首页 > 代码库 > 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)镜像创建流程分析