libvirt的file injection

在E:\nova\nova\virt\libvirt\driver.py 中的_create_and_inject_local_root 检查是否需要进行injection
def _create_and_inject_local_root(self, context, instance,
                                      booted_from_volume, suffix, disk_images,
                                      injection_info, fallback_from_host):
        # File injection only if needed
		#判断是否要进行injection
        need_inject = (not configdrive.required_by(instance) and
                       injection_info is not None and
                       CONF.libvirt.inject_partition != -2)

        # NOTE(ndipanov): Even if disk_mapping was passed in, which
        # currently happens only on rescue - we still don't want to
        # create a base image.
        if not booted_from_volume:
			#执行injection 操作
            if need_inject:
                self._inject_data(backend, instance, injection_info)

        elif need_inject:
            LOG.warning('File injection into a boot from volume '
                        'instance is not supported', instance=instance)
我们看看这里的CONF.libvirt.inject_partition为啥不能等于-2
源码路径为:E:\nova\nova\conf\libvirt.py
    cfg.IntOpt('inject_partition',
               default=-2,
               min=-2,
               help="""
Possible values:

* -2 => disable the injection of data.
* -1 => find the root partition with the file system to mount with libguestfs
*  0 => The image is not partitioned
* >0 => The number of the partition to use for the injection
可以看到-2就表示禁止injection
在实际运行的机器上通过cat /etc/nova/nova-computer.conf可以返现这个参数一般情况下是被设置成-1的
这样就我们看看_inject_data的实现
    def _inject_data(self, disk, instance, injection_info):
        """Injects data in a disk image

        Helper used for injecting data in a disk image file system.

        :param disk: The disk we're injecting into (an Image object)
        :param instance: The instance we're injecting into
        :param injection_info: Injection info
        """
        # Handles the partition need to be used.
        LOG.debug('Checking root disk injection %(info)s',
                  info=str(injection_info), instance=instance)
        target_partition = None
		#找到要inject data的硬盘路径
        if not instance.kernel_id:
            target_partition = CONF.libvirt.inject_partition
            if target_partition == 0:
                target_partition = None
        if CONF.libvirt.virt_type == 'lxc':
            target_partition = None

        # Handles the key injection.
		#处理key injection的case,我们的case中这个值为none
        if CONF.libvirt.inject_key and instance.get('key_data'):
            key = str(instance.key_data)
        else:
            key = None

        # Handles the admin password injection.
		#处理key injection的case,我们的case中这个值为none
        if not CONF.libvirt.inject_password:
            admin_pass = None
        else:
            admin_pass = injection_info.admin_pass

        # Handles the network injection.
		#处理key injection的case,我们的case中这个值为none
        net = netutils.get_injected_network_template(
            injection_info.network_info,
            libvirt_virt_type=CONF.libvirt.virt_type)

        # Handles the metadata injection
        metadata = instance.get('metadata')
		#可以看到可以执行injection的有key/net/metadata/admin_pass
        if any((key, net, metadata, admin_pass, injection_info.files)):
            LOG.debug('Injecting %(info)s', info=str(injection_info),
                      instance=instance)
            img_id = instance.image_ref
            try:
			#调用具体的驱动来执行injection 动作
                disk_api.inject_data(disk.get_model(self._conn),
                                     key, net, metadata, admin_pass,
                                     injection_info.files,
                                     partition=target_partition,
                                     mandatory=('files',))
            except Exception as e:
                with excutils.save_and_reraise_exception():
                    LOG.error('Error injecting data into image '
                              '%(img_id)s (%(e)s)',
                              {'img_id': img_id, 'e': e},
                              instance=instance)
E:\nova\nova\virt\disk\api.py
def inject_data(image, key=None, net=None, metadata=None, admin_password=None,
                files=None, partition=None, mandatory=()):
       items = {'image': image, 'key': key, 'net': net, 'metadata': metadata,
             'files': files, 'partition': partition}
    LOG.debug("Inject data image=%(image)s key=%(key)s net=%(net)s "
              "metadata=%(metadata)s admin_password=<SANITIZED> "
              "files=%(files)s partition=%(partition)s", items)
    try:
		#可以看到执行injection的是虚拟文件系统fs,这里首先得到fs后,再执行setup
        fs = vfs.VFS.instance_for_image(image, partition)
        fs.setup()
    except Exception as e:
        # If a mandatory item is passed to this function,
        # then reraise the exception to indicate the error.
        for inject in mandatory:
            inject_val = items[inject]
            if inject_val:
                raise
        LOG.warning('Ignoring error injecting data into image %(image)s '
                    '(%(e)s)', {'image': image, 'e': e})
        return False

    try:
		#执行这个fs的injection
        return inject_data_into_fs(fs, key, net, metadata, admin_password,
                                   files, mandatory)
    finally:
        fs.teardown()
我们以guestfs的fs为例
E:\nova\nova\virt\disk\vfs\guestfs.py
    def setup(self, mount=True):
        LOG.debug("Setting up appliance for %(image)s",
                  {'image': self.image})
        try:
		#得到guestfs的handle,以后对guestfs操作都是通过这个handle来完成
            self.handle = tpool.Proxy(
                guestfs.GuestFS(python_return_dict=False,
                                close_on_exit=False))
        except TypeError as e:
            if ('close_on_exit' in six.text_type(e) or
                'python_return_dict' in six.text_type(e)):
                # NOTE(russellb) In case we're not using a version of
                # libguestfs new enough to support parameters close_on_exit
                # and python_return_dict which were added in libguestfs 1.20.
                self.handle = tpool.Proxy(guestfs.GuestFS())
            else:
                raise
        try:
			#这里会根据image是local image还是rbd image 来设置不同的参数,但是都会调用add_drive_opts 将image作为一个driver添加到appliance
            if isinstance(self.image, imgmodel.LocalImage):
                self.handle.add_drive_opts(self.image.path,
                                           format=self.image.format)
            elif isinstance(self.image, imgmodel.RBDImage):
                self.handle.add_drive_opts("%s/%s" % (self.image.pool,
                                                      self.image.name),
                                           protocol="rbd",
                                           format=imgmodel.FORMAT_RAW,
                                           server=self.image.servers,
                                           username=self.image.user,
                                           secret=self.image.password)
            else:
                raise exception.UnsupportedImageModel(
                    self.image.__class__.__name__)
			#运行这个appliance
            self.handle.launch()
			#这里的mount 为true
            if mount:
                self.setup_os()
                self.handle.aug_init("/", 0)
                self.mount = True
        except RuntimeError as e:
            # explicitly teardown instead of implicit close()
            # to prevent orphaned VMs in cases when an implicit
            # close() is not enough
            self.teardown()
            raise exception.NovaException(
                _("Error mounting %(image)s with libguestfs (%(e)s)") %
                {'image': self.image, 'e': e})
        except Exception:
            # explicitly teardown instead of implicit close()
            # to prevent orphaned VMs in cases when an implicit
            # close() is not enough
            self.teardown()
            raise
前面都是injection前的准备工作,最后的injection是在E:\nova\nova\virt\disk\api.py
def inject_data_into_fs(fs, key, net, metadata, admin_password, files,
    #可以看到这个函数对不同的injection有不同的处理函数,这里以文件为例,
    items = {'key': key, 'net': net, 'metadata': metadata,
             'admin_password': admin_password, 'files': files}
    functions = {
        'key': _inject_key_into_fs,
        'net': _inject_net_into_fs,
        'metadata': _inject_metadata_into_fs,
        'admin_password': _inject_admin_password_into_fs,
        'files': _inject_files_into_fs,
    }
    status = True
    for inject, inject_val in items.items():
        if inject_val:
            try:
			#以文件injection为例的话,最终是调用_inject_files_into_fs
                inject_func = functions[inject]
                inject_func(inject_val, fs)
            except Exception as e:
                if inject in mandatory:
                    raise
                LOG.warning('Ignoring error injecting %(inject)s into '
                            'image (%(e)s)', {'inject': inject, 'e': e})
                status = False
    return status


def _inject_files_into_fs(files, fs):
    for (path, contents) in files:
        # NOTE(wangpan): Ensure the parent dir of injecting file exists
        parent_dir = os.path.dirname(path)
        if (len(parent_dir) > 0 and parent_dir != "/"
                and not fs.has_file(parent_dir)):
			#设定路径
            fs.make_path(parent_dir)
			#设定为root 用户
            fs.set_ownership(parent_dir, "root", "root")
			#设置权限为744
            fs.set_permissions(parent_dir, 0o744)
		#调用_inject_file_into_fs
        _inject_file_into_fs(fs, path, contents)
		
def _inject_file_into_fs(fs, path, contents, append=False):
    LOG.debug("Inject file fs=%(fs)s path=%(path)s append=%(append)s",
              {'fs': fs, 'path': path, 'append': append})
    if append:
        fs.append_file(path, contents)
    else:
        fs.replace_file(path, contents)
_inject_file_into_fs 文件找那个的append 为false,最后执行fs.replace_file 原来所谓的文件injection
就是调用虚拟文件系统的fs.replace_file来讲形参contents写到形参path 表示的路径中.
    def replace_file(self, path, content):
        LOG.debug("Replace file path=%s", path)
        path = self._canonicalize_path(path)
        self.handle.write(path, content)
可见如前面所说,最后还是通过handler调用guestfs的writer函数来执行injection

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值