首页 > 代码库 > Openstack(Ocata)镜像创建流程分析
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 =http://www.mamicode.com/ 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)
Openstack(Ocata)镜像创建流程分析