本文共 10056 字,大约阅读时间需要 33 分钟。
在E:\nova\nova\virt\libvirt\driver.py 中的_create_and_inject_local_root 检查是否需要进行injectiondef _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.pydef 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=" "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.pydef 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 statusdef _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
转载地址:http://urjmi.baihongyu.com/