Openstack(Ocata)镜像创建流程分析

O版中镜像RESFUL请求默认是v2,与v1相比更复杂了。这里主要分析镜像创建(glance image-create)流程。

glanceclient的命令do_image_create(v2/shell.py)分别执行了image = gc.images.create(**fields)、do_image_upload(gc, args)两步,分别对应api中create、upload方法

1、glance.api.v2.images:ImageController中包含了create、index、delete等基本方法。

 1 @utils.mutating
 2     #创建镜像对象:这里主要分析image_factory和image_repo的获取;try内容是生成一个image对象,并存放到repo中。此时只是存储到数据库中,并没有生成相应的image文件,size大小为None
 3     def create(self, req, image, extra_properties, tags):
 4         image_factory = self.gateway.get_image_factory(req.context)
 5         image_repo = self.gateway.get_repo(req.context)
 6         try:
 7             image = image_factory.new_image(extra_properties=extra_properties,
 8                                             tags=tags, **image)
 9             image_repo.add(image)
10         except (exception.DuplicateLocation,
11                 exception.Invalid) as e:
12             raise webob.exc.HTTPBadRequest(explanation=e.msg)
13         except (exception.ReservedProperty,
14                 exception.ReadonlyProperty) as e:
15             raise webob.exc.HTTPForbidden(explanation=e.msg)
16         except exception.Forbidden as e:
17             LOG.debug("User not permitted to create image")
18             raise webob.exc.HTTPForbidden(explanation=e.msg)
19         except exception.LimitExceeded as e:
20             LOG.warn(encodeutils.exception_to_unicode(e))
21             raise webob.exc.HTTPRequestEntityTooLarge(
22                 explanation=e.msg, request=req, content_type=‘text/plain‘)
23         except exception.Duplicate as e:
24             raise webob.exc.HTTPConflict(explanation=e.msg)
25         except exception.NotAuthenticated as e:
26             raise webob.exc.HTTPUnauthorized(explanation=e.msg)
27         except TypeError as e:
28             LOG.debug(encodeutils.exception_to_unicode(e))
29             raise webob.exc.HTTPBadRequest(explanation=e)
30
31         return image
 1 #依次将domain、location、quota、policy、notifier、authorization作为构造对
 2 #像参数。返回一个FactoryProxy。
 3 def get_image_factory(self, context):
 4         image_factory = glance.domain.ImageFactory()
 5         store_image_factory = glance.location.ImageFactoryProxy(
 6             image_factory, context, self.store_api, self.store_utils)
 7         quota_image_factory = glance.quota.ImageFactoryProxy(
 8             store_image_factory, context, self.db_api, self.store_utils)
 9         policy_image_factory = policy.ImageFactoryProxy(
10             quota_image_factory, context, self.policy)
11         notifier_image_factory = glance.notifier.ImageFactoryProxy(
12             policy_image_factory, context, self.notifier)
13         #api.conf中property_protection_file默认为None
14         if property_utils.is_property_protection_enabled():
15             property_rules = property_utils.PropertyRules(self.policy)
16             pif = property_protections.ProtectedImageFactoryProxy(
17                 notifier_image_factory, context, property_rules)
18             authorized_image_factory = authorization.ImageFactoryProxy(
19                 pif, context)
20         else:
21             #执行如下流程
22             authorized_image_factory = authorization.ImageFactoryProxy(
23                 notifier_image_factory, context)
24         return authorized_image_factory
 1 #获取仓库repo,用于存储image对象。
 2 def get_repo(self, context):
 3         image_repo = glance.db.ImageRepo(context, self.db_api)
 4         store_image_repo = glance.location.ImageRepoProxy(
 5             image_repo, context, self.store_api, self.store_utils)
 6         quota_image_repo = glance.quota.ImageRepoProxy(
 7             store_image_repo, context, self.db_api, self.store_utils)
 8         policy_image_repo = policy.ImageRepoProxy(
 9             quota_image_repo, context, self.policy)
10         notifier_image_repo = glance.notifier.ImageRepoProxy(
11             policy_image_repo, context, self.notifier)
12         if property_utils.is_property_protection_enabled():
13             property_rules = property_utils.PropertyRules(self.policy)
14             pir = property_protections.ProtectedImageRepoProxy(
15                 notifier_image_repo, context, property_rules)
16             authorized_image_repo = authorization.ImageRepoProxy(
17                 pir, context)
18         else:
19             authorized_image_repo = authorization.ImageRepoProxy(
20                 notifier_image_repo, context)
21
22         return authorized_image_repo

2、glance.api.v2.image_data:ImageDataController中upload方法主要包括以下几步:

a、获取image_repo = self.gateway.get_repo(req.context)

b、image = image_repo.get(image_id)
         image.status = ‘saving‘

c、image_repo.save(image, from_state=‘queued‘)  save方法会将镜像image信息更新到db
         image.set_data(data, size)

d、image_repo.save(image, from_state=‘saving‘)   这里data是一个eventlet.wsgi.Input对象

3、重点分析set_data方法:其分别执行了glance.notifier和glance.location模块中set_data方法。其中glance.location.ImageProxy中set_data为镜像文件的实际上传过程。

 1 def set_data(self, data, size=None):
 2         if size is None:
 3             size = 0  # NOTE(markwash): zero -> unknown size
 4
 5         # Create the verifier for signature verification (if correct properties
 6         # are present)
 7         extra_props = self.image.extra_properties
 8         if (signature_utils.should_create_verifier(extra_props)):
 9             # NOTE(bpoulos): if creating verifier fails, exception will be
10             # raised
11             img_signature = extra_props[signature_utils.SIGNATURE]
12             hash_method = extra_props[signature_utils.HASH_METHOD]
13             key_type = extra_props[signature_utils.KEY_TYPE]
14             cert_uuid = extra_props[signature_utils.CERT_UUID]
15             verifier = signature_utils.get_verifier(
16                 context=self.context,
17                 img_signature_certificate_uuid=cert_uuid,
18                 img_signature_hash_method=hash_method,
19                 img_signature=img_signature,
20                 img_signature_key_type=key_type
21             )
22         else:
23             verifier = None
24         #用glance_store模块完成文件上传到glance目录中,
25         location, size, checksum, loc_meta = self.store_api.add_to_backend(
26             CONF,
27             self.image.image_id,
28             utils.LimitingReader(utils.CooperativeReader(data),
29                                  CONF.image_size_cap),
30             size,
31             context=self.context,
32             verifier=verifier)
33
34         # NOTE(bpoulos): if verification fails, exception will be raised
35         if verifier:
36             try:
37                 verifier.verify()
38                 LOG.info(_LI("Successfully verified signature for image %s"),
39                          self.image.image_id)
40             except crypto_exception.InvalidSignature:
41                 raise cursive_exception.SignatureVerificationError(
42                     _(‘Signature verification failed‘)
43                 )
44         #更新镜像相关属性
45         self.image.locations = [{‘url‘: location, ‘metadata‘: loc_meta,
46                                  ‘status‘: ‘active‘}]
47         self.image.size = size
48         self.image.checksum = checksum
49         self.image.status = ‘active‘

默认情况下,镜像的virtual_size值为None。这里如果需要该值,则需要调用qemu-img info image-file获取virtual-size和size大小。修改1:获取virtual-size大小;修改2:设置image的virtual-size。

 1 #glance.common.utils.py增加get_virtual_size方法
 2 def get_virtual_size(image_id):
 3     try:
 4         file_path = os.path.join(CONF.glance_store.filesystem_store_datadir, image_id)
 5         stdout, stderr = putils.trycmd(‘qemu-img‘, ‘info‘,
 6                                            ‘--output=json‘, file_path,
 7                                            prlimit=utils.QEMU_IMG_PROC_LIMITS,
 8                                            log_errors=putils.LOG_ALL_ERRORS)
 9     except OSError as exc:
10         if exc.errno != 2:
11             with excutils.save_and_reraise_exception():
12                 exc_message = encodeutils.exception_to_unicode(exc)
13                 msg = _LE(‘Failed to execute introspection ‘
14                               ‘%(task_id)s: %(exc)s‘)
15                 LOG.error(msg, {‘task_id‘: self.task_id,
16                                     ‘exc‘: exc_message})
17             return
18
19         if stderr:
20             raise RuntimeError(stderr)
21     metadata = json.loads(stdout)
22     virtual_size = metadata.get(‘virtual-size‘, 0)
23     return virtual_size

glance.location中set_data方法增加:self.image.virtual_size = utils.get_virtual_size(self.image.image_id)

时间: 2024-08-28 18:30:20

Openstack(Ocata)镜像创建流程分析的相关文章

openstack之nova-api服务流程分析

nova-api发布api服务没有用到一个些框架,基本都是从头写的.在不了解它时,以为它非常复杂,难以掌握.花了两三天的时间把它分析一遍后,发现它本身的结构比较简单,主要难点在于对它所使用的一些类库不了解,如paste.deploy/webob/routes.对于paste.deploy,结合它的官网文档把它的源码看了两遍.webob看的是源码.routes看的是文档.对于这些类库提供的函数,如果从文档中去理解他们想要做什么,真不是件容易的事.查看其实现源码,就明了了.不过在分析源码过程中,碰到

openstack之虚拟机的创建流程

这篇博文静静的呆在草稿箱大半年了,如果不是因为某些原因被问到,以及因为忽略它而导致的损失,否则我也不知道什么时候会将它完成.感谢这段时间经历的挫折,让我知道不足,希望你能给我更大的决心! 本文试图详细地描述openstack创建虚拟机的完整过程,从用户发起请求到虚拟机成功运行,包括客户端请求的发出.keystone身份验证.nova-api接收请求.nova-scheduler调度.nova-computer创建.nova-network分配网络.对于每一个模块在创建虚拟机的过程中所负责的功能和

Openstack之Nova创建虚机流程分析

前言  Openstack作为一个虚拟机管理平台,核心功能自然是虚拟机的生命周期的管理,而负责虚机管理的模块就是Nova. 本文就是openstack中Nova模块的分析,所以本文重点是以下三点: 先了解Openstack的整体架构,搞清楚为什么要用这样的架构: 然后再了解架构中的各个组件,组件提供的主要功能与各个组件之间的交互: 了解虚机的启动过程,能在遇到问题时发现问题出在哪个模块中的哪个组件. Nova组件介绍 接下来进行详细介绍,如有错误,欢迎拍砖! 下图为创建虚拟机的一个大概流程图.

【Java基础】Java类的加载和对象创建流程的详细分析

相信我们在面试Java的时候总会有一些公司要做笔试题目的,而Java类的加载和对象创建流程的知识点也是常见的题目之一.接下来通过实例详细的分析一下. 实例问题 实例代码 Parent类 1 package mytest.javaBase; 2 3 public class Parent { 4 int a = 10; 5 static int b = 11; 6 // 静态代码块 7 static { 8 System.out.println("Parent静态代码块:b=" + b)

Java类的加载和对象创建流程的详细分析

相信我们在面试Java的时候总会有一些公司要做笔试题目的,而Java类的加载和对象创建流程的知识点也是常见的题目之一.接下来通过实例详细的分析一下: package com.test; public class Parent { int a = 10; static int b =11; //静态代码块 static { System.out.println("parent静态代码块:b=" + b); b++; } //代码块 { System.out.println("P

nova挂载cinder卷流程分析

Nova挂载cinder卷流程分析 1. nova通过命令nova volume-attach server volume device-name或者http请求 Req:POST /v2/{tenant-id}/servers/{server-id}/os-volume_attachments' Body:{'volumeAttachment': {'device': '/dev/vdb', 'volumeId': '951be889-b794-4723-9ac9-efde61cacf3a'}

nova boot代码流程分析(三):nova与neutron的交互(2)

继续<nova boot代码流程分析(三):nova与neutron的交互(1)>的分析. #/nova/virt/libvirt/driver.py:LibvirtDriver # NOTE(ilyaalekseyev): Implementation like in multinics # for xenapi(tr3buchet) def spawn(self, context, instance, image_meta, injected_files, admin_password,

nova boot代码流程分析(一):Claim机制

nova boot创建VM的流程大致为: 1. novaclient发送HTTP请求到nova-api(这里内部细节包括keystone对用户的验证及用户从keystone获取token和endpoints等信息,具体参考<keystone WSGI流程>). 2. nova-api通过rpc调用到nova-conductor. 3. nova-conductor调用rpc进入nova-scheduler进行compute节点的选择,nova-scheduler将compute节点选择的信息的

ubuntu中利用devstack安装openstack ocata

介绍: 宿主机win10,在vmware下创建两台ubuntu16.04虚拟机,一台作为控制节点,一台作为计算节点,利用devstack部署openstack ocata. 前期工作: 1.下载ubuntu镜像,我用的是ubuntu-16.04.3-server-amd64版本 2.下载vmware workstation,我用的是vmware workstation 11版本 3.下载xshell,用于ssh连接虚拟机,方便复制代码 4.安装完vmware后,点击编辑,启动虚拟网络编辑器,选择