在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
libvirt的file injection
最新推荐文章于 2023-03-04 20:06:25 发布