Ovirt程序员

【Ovirt 笔记】engine-iso-uploader 的实

2018-05-15  本文已影响6人  58bc06151329

文前说明

作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。

分析整理的版本为 Ovirt 3.4.5 版本。

命令使用方式:
engine-iso-uploader [options] list 显示 ISO 存储域列表
engine-iso-uploader [options] upload FILE [FILE]...[FILE] 上传 ISO 到存储域。

选项组 说明
--version 显示程序的版本号
-h,--help 显示帮助信息
--quiet 控制台简洁输出(默认 false)
--log-file=PATH 日志文件路径(默认为 /var/log/ovirt-engine/ovirt-iso-uploader/ovirt-iso-uploader-yyyyMMddHHmmss.log
--conf-file=PATH 配置文件路径(默认为 /etc/ovirt-engine/isouploader.conf
--cert-file=PATH CA 证书用来验证引擎(默认为 /etc/pki/ovirt-engine/ca.pem
--insecure 不验证引擎(默认 off)
engine 配置组 说明
-u,--user= restApi 用户,例如:user@engine.example.com,默认 admin@internal
-r,--engine= restApi IP 地址,例如:localhost:443
ISO 存储域配置组 说明
-i,--iso-domain= 指定上传文件的 ISO 存储域
-n,--nfs-server= 指定上传文件的 NFS 服务器,此选项是 ISO 域的替代方案,不与 ISO 域组合,例如:--nfs-server=example.com:/path/to/some/dir
连接配置组 说明
--ssh-user=root 指定用于 SSH 传输的 SSH 用户,必须为 root,目标文件服务器上的组 UID 和 GID 为 36
--ssh-port= SSH 连接接口
-k,--key-file= SSH Key 身份文件(私钥)用于访问文件服务器。
[root@localhost ~]# engine-iso-uploader list
Please provide the REST API password for the admin@internal oVirt Engine user (CTRL+D to abort): 
ISO Storage Domain Name   | Datacenter                | ISO Domain Status
myiso                     | Myowndc                   | active

命令采用了 python 方式进行实现。

optparse 模块

from optparse import OptionParser
parser = OptionParser(...)
parser.add_option(.....)
参数 说明
usage 可以打印用法。
version 在使用 %prog --version 的时候输出版本信息。
description 描述信息
参数 说明
action 指示 optparser 解析参数时候该如何处理。默认是 ' store ' 将命令行参数值保存 options 对象里 。action 的值有 store、store_true、store_false、store_const、append、count、callback。
type 默认是 string,也可以是 int、float 等。
dest 如果没有指定 dest 参数,将用命令行参数名来对 options 对象的值进行存取。
store store 可以为 store_true 和 store_false 两种形式。用于处理命令行参数后面不带值的情况。如 -v、-q 等命令行参数。
default 设置默认值。
help 指定帮助文档。
metavar 提示用户期望参数。
group = OptionGroup(parser)
group.add_option()
parser.add_option_group(group)

shutil 模块

命令 说明
shutil.copyfileobj(fsrc, fdst[, length]) 将文件内容拷贝到另一个文件中
shutil.copyfile(src, dst) 拷贝文件
shutil.copy(src, dst) 拷贝文件和权限
shutil.copy2(src, dst) 拷贝文件和状态信息
shutil.copymode(src, dst) 仅拷贝权限。内容、组、用户均不变
shutil.copystat(src, dst) 仅拷贝状态的信息,即文件属性,包括:mode bits, atime, mtime, flags
shutil.ignore_patterns(*patterns) 忽略哪个文件,有选择性的拷贝
shutil.copytree(src, dst, symlinks=False, ignore=None) 递归的去拷贝文件夹
shutil.rmtree(path[, ignore_errors[, onerror]]) 递归的去删除文件
shutil.move(src, dst) 递归的去移动文件,它类似 mv 命令,其实就是重命名。
shutil.make_archive(base_name, format,...) 创建压缩包并返回文件路径,例如:zip、tar

engine-iso-uploader 命令执行流程

解析参数和加载配置文件

conf = None
conf = Configuration(parser)
class Configuration(dict)
......
if not parser:
    raise Exception("Configuration requires a parser")
self.options, self.args = self.parser.parse_args()

self.load_config_file()

if self.args:
   self.from_args(self.args)

ISO 上传功能

isoup = ISOUploader(conf)
组装不同的 cmd 命令
class Caller(object):
    """
    Utility class for forking programs.
    """
    def __init__(self, configuration):
        self.configuration = configuration

    def prep(self, cmd):
        _cmd = cmd % self.configuration
        logging.debug(_cmd)
        return shlex.split(_cmd)

    def call(self, cmds):
        """Uses the configuration to fork a subprocess and run cmds"""
        _cmds = self.prep(cmds)
        logging.debug("_cmds(%s)" % _cmds)
        proc = subprocess.Popen(_cmds,
                   stdout=subprocess.PIPE,
                   stderr=subprocess.PIPE)
        stdout, stderr = proc.communicate()
        returncode = proc.returncode
        logging.debug("returncode(%s)" % returncode)
        logging.debug("STDOUT(%s)" % stdout)
        logging.debug("STDERR(%s)" % stderr)

        if returncode == 0:
            return (stdout,returncode)
        else:
            raise Exception(stderr)
根据命令类型的不同执行不同的方法
 def list_all_ISO_storage_domains(self):
        """
        List only the ISO storage domains in sorted format.
        """
        def get_name(ary):
            return ary[0]

        if not self._initialize_api():
            sys.exit(ExitCodes.CRITICAL)

        dcAry = self.api.datacenters.list()
        if dcAry is not None:
            isoAry = []
            for dc in dcAry:
                dcName = dc.get_name()
                logging.debug("Found a DC named(%s)" % dcName)
                domainAry = dc.storagedomains.list()
                if domainAry is not None:
                    for domain in domainAry:
                        if domain.get_type() == 'iso':
                            status = domain.get_status()
                            if status is not None:
                                isoAry.append(
                                    [
                                        domain.get_name(),
                                        dcName,
                                        status.get_state()
                                    ]
                                )
                            else:
                                logging.debug(
                                    "the storage domain didn't "
                                    "have a status element."
                                )
                else:
                    logging.debug(
                        _("DC(%s) does not have a storage domain."),
                        dcName
                    )
cmd = self.format_ssh_command(SCP)

def format_ssh_command(self, cmd=SSH):
        cmd = "%s " % cmd
        port_flag = "-p" if cmd.startswith(SSH) else "-P"
        if "ssh_port" in self.configuration:
            cmd += port_flag + " %(ssh_port)s " % self.configuration
        if "key_file" in self.configuration:
            cmd += "-i %(key_file)s " % self.configuration
        return cmd
MOUNT='/bin/mount'
NFS_MOUNT_OPTS = '-t nfs -o rw,sync,soft'
def format_nfs_command(self, address, export, dir):
        cmd = '%s %s %s:%s %s' % (MOUNT, NFS_MOUNT_OPTS, address, export, dir)
        logging.debug('NFS mount command (%s)' % cmd)
        return cmd
# NFS support.
            tmpDir = tempfile.mkdtemp()
            logging.debug('local NFS mount point is %s' % tmpDir)
            cmd = self.format_nfs_command(address, path, tmpDir)
            try:
                self.caller.call(cmd)
                getpwnam(NFS_USER)
                for filename in self.configuration.files:
                    logging.info(_("Start uploading %s "), filename)
                    dest_dir = os.path.join(
                        tmpDir,
                        remote_path
                    )
                    dest_file = os.path.join(
                        dest_dir,
                        os.path.basename(filename)
                    )
                    retVal = self.exists_nfs(
                        dest_file,
                        NUMERIC_VDSM_ID,
                        NUMERIC_VDSM_ID
                    )
if (dir_size > file_size):
                                temp_dest_file = os.path.join(
                                    dest_dir,
                                    '.%s' % os.path.basename(filename)
                                )
                                if self.copy_file(
                                    filename,
                                    temp_dest_file,
                                    NUMERIC_VDSM_ID,
                                    NUMERIC_VDSM_ID
                                ):
                                    if self.rename_file_nfs(
                                        temp_dest_file,
                                        dest_file,
                                        NUMERIC_VDSM_ID,
                                        NUMERIC_VDSM_ID
                                    ):
                                        if id is not None:
                                            # Force oVirt Engine to refresh
                                            #the list
                                            # of files in the ISO domain
                                            self.refresh_iso_domain(id)
                                        logging.info(
                                            _(
                                                '{f} uploaded successfully'
                                            ).format(
                                                f=filename,
                                            )
                                        )
......
UMOUNT='/bin/umount'
NFS_UMOUNT_OPTS = '-t nfs -f '
cmd = '%s %s %s' % (UMOUNT, NFS_UMOUNT_OPTS, mount_dir)
logging.debug(cmd)
self.caller.call(cmd)
finally:
      try:
           cmd = '%s %s %s' % (UMOUNT, NFS_UMOUNT_OPTS, tmpDir)
           logging.debug(cmd)
           self.caller.call(cmd)
           shutil.rmtree(tmpDir)
       except Exception, e:
            ExitCodes.exit_code = ExitCodes.CLEANUP_ERR
            logging.debug(e)
上一篇下一篇

猜你喜欢

热点阅读