cinder创建volume流程简介

来源:互联网 发布:淘宝模特收费 编辑:程序博客网 时间:2024/05/21 11:34

cinder创建volume流程简介

Openstack icehouse
Cinder-api启动脚本

/etc/init.d/openstack-cinder-apiVim /etc/init.d/openstack-cinder-api. /etc/rc.d/init.d/functionssuffix=apiprog=openstack-cinder-$suffixexec="/usr/bin/cinder-$suffix" #cinder执行文件config="/etc/cinder/cinder.conf" #cinder主要配置文件distconfig="/usr/share/cinder/cinder-dist.conf" #主要配置文件pidfile="/var/run/cinder/cinder-$suffix.pid"  #进程文件logfile="/var/log/cinder/$suffix.log"  #cinder-api日志文件[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$proglockfile=/var/lock/subsys/$prog #lockstart() {    [ -x $exec ] || exit 5    [ -f $config ] || exit 6    echo -n $"Starting $prog: "    daemon --user cinder --pidfile $pidfile "$exec --config-file $distconfig --config-file $config --logfile $logfile &>/dev/null & echo \$! > $pidfile"    retval=$?    echo    [ $retval -eq 0 ] && touch $lockfile    return $retval}省略。。。

查看openstack-cinder-api进程
ps -ef | grep cinder-api 
这里写图片描述

"""Starter script for Cinder OS API."""import eventlet #线程管理模块eventlet.monkey_patch()import osimport sysfrom oslo.config import cfg #负责CLI和CONF配置项解析的组件possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),                                   os.pardir,                                   os.pardir))  # possible_topdir = /usrif os.path.exists(os.path.join(possible_topdir, "cinder", "__init__.py")):  #false    sys.path.insert(0, possible_topdir)from cinder.openstack.common import gettextutilsgettextutils.install('cinder', lazy=False)# Need to register global_optsfrom cinder.common import config  # noqafrom cinder.openstack.common import log as loggingfrom cinder import rpcfrom cinder import servicefrom cinder import utilsfrom cinder import versionCONF = cfg.CONFif __name__ == '__main__':    CONF(sys.argv[1:], project='cinder',         version=version.version_string())    logging.setup("cinder")    utils.monkey_patch()    rpc.init(CONF) #初始化rpc服务    launcher = service.process_launcher()    server = service.WSGIService('osapi_volume') #调用osapi_volume组件的工厂程序    launcher.launch_service(server, workers=server.workers or 1)launcher.wait()

一.创建一个cinder volume
Cinder.api.v2.api
这里写图片描述

 def create(self, req, body):        """Creates a new volume."""        if not self.is_valid_body(body, 'volume'): 1.判断请求体是否合法            msg = _("Missing required element '%s' in request body") % 'volume'            raise exc.HTTPBadRequest(explanation=msg)        LOG.debug('Create volume request body: %s', body)        context = req.environ['cinder.context']        volume = body['volume']        kwargs = {}        # NOTE(thingee): v2 API allows name instead of display_name        if volume.get('name'):  2.使用display_name 替换 name            volume['display_name'] = volume.get('name')            del volume['name']        # NOTE(thingee): v2 API allows description instead of        #                display_description        if volume.get('description'):3.使用display_description 替换 description            volume['display_description'] = volume.get('description')            del volume['description']  4.检查是否有所选的volume类型    req_volume_type = volume.get('volume_type', None)        if req_volume_type:            try:                if not uuidutils.is_uuid_like(req_volume_type):                    kwargs['volume_type'] = \                        volume_types.get_volume_type_by_name(                            context, req_volume_type)                else:                    kwargs['volume_type'] = volume_types.get_volume_type(                        context, req_volume_type)            except exception.VolumeTypeNotFound:                msg = _("Volume type not found.")                raise exc.HTTPNotFound(explanation=msg)        5.获取请求元信息        kwargs['metadata'] = volume.get('metadata', None)        6.判断是否使用指定的snapshot来创建volume        snapshot_id = volume.get('snapshot_id')        if snapshot_id is not None:            try:                kwargs['snapshot'] = self.volume_api.get_snapshot(context,                                                                  snapshot_id)            except exception.NotFound:                explanation = _('snapshot id:%s not found') % snapshot_id                raise exc.HTTPNotFound(explanation=explanation)        else:            kwargs['snapshot'] = None        7.判断是否从已有的设备中创建volume        source_volid = volume.get('source_volid')        if source_volid is not None:            try:                kwargs['source_volume'] = \                    self.volume_api.get_volume(context,                                               source_volid)            except exception.NotFound:                explanation = _('source volume id:%s not found') % source_volid                raise exc.HTTPNotFound(explanation=explanation)        else:            kwargs['source_volume'] = None        8.设置将要创建volume的大小        size = volume.get('size', None)        if size is None and kwargs['snapshot'] is not None:            size = kwargs['snapshot']['volume_size']        elif size is None and kwargs['source_volume'] is not None:            size = kwargs['source_volume']['size']        LOG.audit(_("Create volume of %s GB"), size, context=context)        9.判断是否加载了os-image-create服务        if self.ext_mgr.is_loaded('os-image-create'):            image_href = volume.get('imageRef')            if image_href: 如果imageref被nova API产生,则从imageref中提取image_uuid                image_uuid = self._image_uuid_from_href(image_href)                kwargs['image_id'] = image_uuid        10.设置volume的可用域        kwargs['availability_zone'] = volume.get('availability_zone', None)                  11.设置scheduler_hints volume创建参数        kwargs['scheduler_hints'] = volume.get('scheduler_hints', None)        new_volume = self.volume_api.create(context,                                            size,                                            volume.get('display_name'),                                            volume.get('display_description'),                                            **kwargs)        # TODO(vish): Instance should be None at db layer instead of        #             trying to lazy load, but for now we turn it into        #             a dict to avoid an error.        new_volume = dict(new_volume.iteritems())        utils.add_visible_admin_metadata(context, new_volume, self.volume_api)        retval = self._view_builder.detail(req, new_volume)        Return  retval

这里写图片描述
这里写图片描述
这里写图片描述
/etc/cinder/cinder.conf
这里写图片描述
这里写图片描述
/cinder/volume/api.API()
这里写图片描述

def create(self, context, size, name, description, snapshot=None,               image_id=None, volume_type=None, metadata=None,               availability_zone=None, source_volume=None,               scheduler_hints=None, backup_source_volume=None):1.如果是通过已有的volume创建新volume则新的volume类型必须与源volume类型一致        if source_volume and volume_type:            if volume_type['id'] != source_volume['volume_type_id']:                msg = _("Invalid volume_type provided (requested type "                        "must match source volume, or be omitted). "                        "You should omit the argument.")                raise exception.InvalidInput(reason=msg)2.如果是通过已有的snapshot创建新volume则新的volume类型必须与源snapshot类型一致        if snapshot and volume_type:            if volume_type['id'] != snapshot['volume_type_id']:                msg = _("Invalid volume_type provided (requested type "                        "must match source snapshot, or be omitted). "                        "You should omit the argument.")                raise exception.InvalidInput(reason=msg)3.内置函数,用于判断选择的域是否在可用域范围内    def check_volume_az_zone(availability_zone):            try:                return self._valid_availability_zone(availability_zone)            except exception.CinderException:                LOG.exception(_("Unable to query if %s is in the "                                "availability zone set"), availability_zone)                return False        create_what = {            'context': context,            'raw_size': size,            'name': name,            'description': description,            'snapshot': snapshot,            'image_id': image_id,            'raw_volume_type': volume_type,            'metadata': metadata,            'raw_availability_zone': availability_zone,            'source_volume': source_volume,            'scheduler_hints': scheduler_hints,            'key_manager': self.key_manager,            'backup_source_volume': backup_source_volume,        }4.创建vpi volume flow        try:            flow_engine = create_volume.get_flow(self.scheduler_rpcapi,                                                 self.volume_rpcapi,                                                 self.db,                                                 self.image_service,                                                 check_volume_az_zone,                                                 create_what)        except Exception:            LOG.exception(_("Failed to create api volume flow"))            raise exception.CinderException(                _("Failed to create api volume flow"))

/cinder/volume/api.py
这里写图片描述
/cinder/volume/api.py
这里写图片描述
/cinder/db/base.py
这里写图片描述
/cinder/volume/api.py
这里写图片描述

        flow_engine.run()        volume = flow_engine.storage.fetch('volume')        return volume

/cinder/volume/api.py
这里写图片描述
/cinder/volume/flows/api.py
这里写图片描述
/cinder/volume/flows/api.get_flow()

def get_flow(scheduler_rpcapi, volume_rpcapi, db,             image_service,             az_check_functor,             create_what):    """Constructs and returns the api entrypoint flow.    This flow will do the following:    1. Inject keys & values for dependent tasks.为任务注入keys 和values    2. Extracts and validates the input keys & values.提前和确认keys和values    3. Reserves the quota (reverts quota on any failures).存储配额    4. Creates the database entry.创建数据库实体记录    5. Commits the quota.提交配额    6. Casts to volume manager or scheduler for further processing.卷管理或者调度,进一步处理    """    #flow_name=volume_create_apiflow_name = ACTION.replace(":", "_") + "_api"1.创建一个线性流    api_flow = linear_flow.Flow(flow_name)2.把提供的task/tasks/flow/flows添加到当前flow中

这里写图片描述

#ExtractVolumeRequestTask接收一个集合,返回一个经过验证的参数集,或者经转换的参数集提供给其他task使用    api_flow.add(ExtractVolumeRequestTask(        image_service,        az_check_functor,        rebind={'size': 'raw_size',                'availability_zone': 'raw_availability_zone',                'volume_type': 'raw_volume_type'}))#QuotaReserveTask预留一个指定大小的volume,和volume typeapi_flow.add(QuotaReserveTask(),#EntryCreateTask 在数据库中创建一条创建volume的记录                 EntryCreateTask(db),    #QuotaCommitTask提交预留信息                 QuotaCommitTask())    # This will cast it out to either the scheduler or volume manager via# the rpc apis provided.#VolumeCastTask执行volume cast操作到scheduler或者volume manager    api_flow.add(VolumeCastTask(scheduler_rpcapi, volume_rpcapi, db))# Now load (but do not run) the flow using the provided initial data.3.使用提供的初始化数据来加载该flow    #flow: flow to load    #store: dict -- data to put to storage to satisfy flow requirements    return taskflow.engines.load(api_flow, store=create_what)

/cinder/volume/flows/api.
这里写图片描述
/cinder/volume/flows/api.
这里写图片描述
注:task任务类详解
ExtractVolumeRequestTask
QuotaReserveTask
EntryCreateTask
QuotaCommitTask
VolumeCastTask

class VolumeCastTask(flow_utils.CinderTask):    """Performs a volume create cast to the scheduler or to the volume manager.    This which will signal a transition of the api workflow to another child    and/or related workflow on another component.    Reversion strategy: N/A    """    def __init__(self, scheduler_rpcapi, volume_rpcapi, db):        requires = ['image_id', 'scheduler_hints', 'snapshot_id',                    'source_volid', 'volume_id', 'volume_type',                    'volume_properties']        super(VolumeCastTask, self).__init__(addons=[ACTION],                                             requires=requires)        self.volume_rpcapi = volume_rpcapi        self.scheduler_rpcapi = scheduler_rpcapi        self.db = db#远程调用建立卷的方法,实现卷的建立操作;    def _cast_create_volume(self, context, request_spec, filter_properties):        source_volid = request_spec['source_volid']        volume_id = request_spec['volume_id']        snapshot_id = request_spec['snapshot_id']        image_id = request_spec['image_id']        host = None#如果是从snapshot来创建volume则要获取该snapshot的所在的host        if snapshot_id and CONF.snapshot_same_host:            # NOTE(Rongze Zhu): A simple solution for bug 1008866.            #            # If snapshot_id is set, make the call create volume directly to            # the volume host where the snapshot resides instead of passing it            # through the scheduler. So snapshot can be copy to new volume.            snapshot_ref = self.db.snapshot_get(context, snapshot_id)            source_volume_ref = self.db.volume_get(context,                                                   snapshot_ref['volume_id'])            host = source_volume_ref['host']  #如果是从snapshot来创建新volume,则要获取该volume所在的host        elif source_volid:            source_volume_ref = self.db.volume_get(context, source_volid)            host = source_volume_ref['host']#如果没有提供host参数时执行以下代码,进行调度选择合适的host执行创建操作        if not host:            # Cast to the scheduler and let it handle whatever is needed            # to select the target host for this volume.            self.scheduler_rpcapi.create_volume(                context,                CONF.volume_topic,                volume_id,                snapshot_id=snapshot_id,                image_id=image_id,                request_spec=request_spec,                filter_properties=filter_properties) #否则执行以下代码,rpc到指定的host上执行操作        else:            # Bypass the scheduler and send the request directly to the volume            # manager.            now = timeutils.utcnow()            values = {'host': host, 'scheduled_at': now}            volume_ref = self.db.volume_update(context, volume_id, values)#更新数据库的接口            self.volume_rpcapi.create_volume(                context,                volume_ref,                volume_ref['host'],                request_spec,                filter_properties,                allow_reschedule=False,                snapshot_id=snapshot_id,                image_id=image_id,                source_volid=source_volid)  #flow_engine.run()会调用该函数    def execute(self, context, **kwargs):        scheduler_hints = kwargs.pop('scheduler_hints', None)        request_spec = kwargs.copy()        filter_properties = {}        if scheduler_hints:            filter_properties['scheduler_hints'] = scheduler_hints        self._cast_create_volume(context, request_spec, filter_properties)

执行execute()函数执行volume创建工作,假设host为空执行self.scheduler_rpcapi.create_volume()
这里写图片描述

def create_volume(self, ctxt, topic, volume_id, snapshot_id=None,                      image_id=None, request_spec=None,                      filter_properties=None):      1.创建发送RPC消息的Client        cctxt = self.client.prepare(version='1.2')        request_spec_p = jsonutils.to_primitive(request_spec)2.发送RPC消息远程调用对应manager的create_volume方法,并立刻返回        return cctxt.cast(ctxt, 'create_volume',                          topic=topic,                          volume_id=volume_id,                          snapshot_id=snapshot_id,                          image_id=image_id,                          request_spec=request_spec_p,                          filter_properties=filter_properties)

/cinder/scheduler/rpcapi.py
这里写图片描述
/cinder/scheduler/rpcapi.py
这里写图片描述
/cinder/rpc.py
这里写图片描述

def get_client(target, version_cap=None, serializer=None):    assert TRANSPORT is not Noneserializer = RequestContextSerializer(serializer)    return messaging.RPCClient(TRANSPORT,                               target,                               version_cap=version_cap,/oslo/messaging   /oslo/messaging/rpc *                               serializer=serializer)

这里写图片描述
/oslo/messaging/rpc/client.py
这里写图片描述

def prepare(self, exchange=_marker, topic=_marker, namespace=_marker,                version=_marker, server=_marker, fanout=_marker,                timeout=_marker, version_cap=_marker):        """Prepare a method invocation context.        Use this method to override client properties for an individual method        invocation. For example::            def test(self, ctxt, arg):                cctxt = self.prepare(version='2.5')                return cctxt.call(ctxt, 'test', arg=arg)        :param exchange: see Target.exchange        :type exchange: str        :param topic: see Target.topic        :type topic: str        :param namespace: see Target.namespace        :type namespace: str        :param version: requirement the server must support, see Target.version        :type version: str        :param server: send to a specific server, see Target.server        :type server: str        :param fanout: send to all servers on topic, see Target.fanout        :type fanout: bool        :param timeout: an optional default timeout (in seconds) for call()s        :type timeout: int or float        :param version_cap: raise a RPCVersionCapError version exceeds this cap        :type version_cap: str        """#准备rpc 方法的context        return _CallContext._prepare(self,                                     exchange, topic, namespace,                                     version, server, fanout,                                     timeout, version_cap)

/oslo/messaging/rpc/clinet.py
这里写图片描述
/oslo/messaging/rpc/client.py
这里写图片描述
/oslo/message/rpc/client.py

def cast(self, ctxt, method, **kwargs):        """Invoke a method and return immediately. See RPCClient.cast()."""#制作要发送的消息        msg = self._make_message(ctxt, method, kwargs)#对ctxt做序列化        ctxt = self.serializer.serialize_context(ctxt)#检查版本        if self.version_cap:            self._check_version_cap(msg.get('version'))        try:#开始发送RPC消息            self.transport._send(self.target, ctxt, msg)        except driver_base.TransportDriverError as ex:            raise ClientSendError(self.target, ex)

RPC后有/cinder/scheduler/manager.SchedulerManager接收
/cinder/scheduler/rpcapi.py
这里写图片描述
/cinder/scheduler/manager.py
这里写图片描述

def create_volume(self, context, topic, volume_id, snapshot_id=None,                      image_id=None, request_spec=None,                      filter_properties=None):        try:            flow_engine = create_volume.get_flow(context,                                                 db, self.driver,                                                 request_spec,                                                 filter_properties,                                                 volume_id,                                                 snapshot_id,                                                 image_id)        except Exception:            LOG.exception(_("Failed to create scheduler manager volume flow"))            raise exception.CinderException(                _("Failed to create scheduler manager volume flow"))        flow_engine.run()

/cinder/scheduler/manager.py
这里写图片描述
/cinder/scheduler/flows/create_volume.py
这里写图片描述
/cinder/scheduler/flows/create_volume.py
这里写图片描述
ExtractSchedulerSpecTask task.FunctorTask(schedule_create_volume)
ExtractSchedulerSpecTask 主要用于提取scheduler请求的一些指定参数,

class ExtractSchedulerSpecTask(flow_utils.CinderTask):    """Extracts a spec object from a partial and/or incomplete request spec.    Reversion strategy: N/A    """    default_provides = set(['request_spec'])    def __init__(self, db, **kwargs):        super(ExtractSchedulerSpecTask, self).__init__(addons=[ACTION],                                                       **kwargs)        self.db = db    def _populate_request_spec(self, context, volume_id, snapshot_id,                               image_id):        # Create the full request spec using the volume_id.        #        # NOTE(harlowja): this will fetch the volume from the database, if        # the volume has been deleted before we got here then this should fail.        #        # In the future we might want to have a lock on the volume_id so that        # the volume can not be deleted while its still being created?        if not volume_id:            msg = _("No volume_id provided to populate a request_spec from")            raise exception.InvalidInput(reason=msg)        volume_ref = self.db.volume_get(context, volume_id)        volume_type_id = volume_ref.get('volume_type_id')        vol_type = self.db.volume_type_get(context, volume_type_id)        return {            'volume_id': volume_id,            'snapshot_id': snapshot_id,            'image_id': image_id,            'volume_properties': {                'size': utils.as_int(volume_ref.get('size'), quiet=False),                'availability_zone': volume_ref.get('availability_zone'),                'volume_type_id': volume_type_id,            },            'volume_type': list(dict(vol_type).iteritems()),        }#提取指定的scheduler请求参数,并返回    def execute(self, context, request_spec, volume_id, snapshot_id,                image_id):        # For RPC version < 1.2 backward compatibility        if request_spec is None:            request_spec = self._populate_request_spec(context, volume_id,                                                       snapshot_id, image_id)        return {            'request_spec': request_spec,        }task.FunctorTask(schedule_create_volume)执行scheduler_create_volume()是get_flow()的内嵌函数,被包装成stask,加载到stask flow中。def schedule_create_volume(context, request_spec, filter_properties):        def _log_failure(cause):            LOG.error(_("Failed to schedule_create_volume: %(cause)s") %                      {'cause': cause})        def _notify_failure(cause):            """When scheduling fails send out a event that it failed."""            topic = "scheduler.create_volume"            payload = {                'request_spec': request_spec,                'volume_properties': request_spec.get('volume_properties', {}),                'volume_id': volume_id,                'state': 'error',                'method': 'create_volume',                'reason': cause,            }            try:                rpc.get_notifier('scheduler').error(context, topic, payload)            except exception.CinderException:                LOG.exception(_("Failed notifying on %(topic)s "                                "payload %(payload)s") % {'topic': topic,                                                          'payload': payload})        try:            driver.schedule_create_volume(context, request_spec,                                          filter_properties)        except exception.NoValidHost as e:            # Not host found happened, notify on the scheduler queue and log            # that this happened and set the volume to errored out and            # *do not* reraise the error (since whats the point).            _notify_failure(e)            _log_failure(e)            common.error_out_volume(context, db, volume_id, reason=e)        except Exception as e:            # Some other error happened, notify on the scheduler queue and log            # that this happened and set the volume to errored out and            # *do* reraise the error.            with excutils.save_and_reraise_exception():                _notify_failure(e)                _log_failure(e)                common.error_out_volume(context, db, volume_id, reason=e)

/cinder/scheduler/flows/create_volume.py
这里写图片描述
/cinder/scheduler/flows/create_volume.py
这里写图片描述
/cinder/scheduler/manager.py
这里写图片描述

ChanceScheduler and SimpleScheduler have been '                             'deprecated due to lack of support for advanced '                             'features like: volume types, volume encryption,'                             ' QoS etc. These two schedulers can be fully '                             'replaced by FilterScheduler with certain '                             'combination of filters and weighers.

/etc/cinder/cinder.conf
这里写图片描述
/cinder/scheduler/filter_scheduler.FilerScheduler().scheduler_create_volume() (dirver.scheduler_create_volume())

def schedule_create_volume(self, context, request_spec, filter_properties):        weighed_host = self._schedule(context, request_spec,                                      filter_properties)        if not weighed_host:            raise exception.NoValidHost(reason="")        host = weighed_host.obj.host        volume_id = request_spec['volume_id']        snapshot_id = request_spec['snapshot_id']        image_id = request_spec['image_id']1.更新创建volume数据库条目        updated_volume = driver.volume_update_db(context, volume_id, host)        self._post_select_populate_filter_properties(filter_properties,                                                     weighed_host.obj)        # context is not serializable        filter_properties.pop('context', None)2.发送RPC到指定volume driver manager 创建volume        self.volume_rpcapi.create_volume(context, updated_volume, host,                                         request_spec, filter_properties,                                         allow_reschedule=True,                                         snapshot_id=snapshot_id,                                         image_id=image_id)

/cinder/scheduler/driver.py
这里写图片描述
/cinder/volume/rpcapi.py
这里写图片描述

def create_volume(self, ctxt, volume, host,                      request_spec, filter_properties,                      allow_reschedule=True,                      snapshot_id=None, image_id=None,                      source_volid=None):        cctxt = self.client.prepare(server=host, version='1.4')        request_spec_p = jsonutils.to_primitive(request_spec)#调用cinder.volume.manager.VolumeManager(create_volume())        cctxt.cast(ctxt, 'create_volume',                   volume_id=volume['id'],                   request_spec=request_spec_p,                   filter_properties=filter_properties,                   allow_reschedule=allow_reschedule,                   snapshot_id=snapshot_id,                   image_id=image_id,                   source_volid=source_volid),

/cinder/volume/manager.py
这里写图片描述

def create_volume(self, context, volume_id, request_spec=None,                      filter_properties=None, allow_reschedule=True,                      snapshot_id=None, image_id=None, source_volid=None):        """Creates the volume."""        context_saved = context.deepcopy()        context = context.elevated()        if filter_properties is None:            filter_properties = {}        try:            # NOTE(flaper87): Driver initialization is            # verified by the task itself.#driver 初始化会被task检查,获取create volume工作流            flow_engine = create_volume.get_flow(                context,                self.db,                self.driver,                self.scheduler_rpcapi,                self.host,                volume_id,                snapshot_id=snapshot_id,                image_id=image_id,                source_volid=source_volid,                allow_reschedule=allow_reschedule,                reschedule_context=context_saved,                request_spec=request_spec,                filter_properties=filter_properties)        except Exception:            LOG.exception(_("Failed to create manager volume flow"))            raise exception.CinderException(                _("Failed to create manager volume flow"))        if snapshot_id is not None:            # Make sure the snapshot is not deleted until we are done with it.            locked_action = "%s-%s" % (snapshot_id, 'delete_snapshot')        elif source_volid is not None:            # Make sure the volume is not deleted until we are done with it.            locked_action = "%s-%s" % (source_volid, 'delete_volume')        else:            locked_action = None        def _run_flow():            # This code executes create volume flow. If something goes wrong,            # flow reverts all job that was done and reraises an exception.            # Otherwise, all data that was generated by flow becomes available            # in flow engine's storage.            flow_engine.run() #确保在使用snapshot或者volume创建volume时,源volume不会被删除。        @utils.synchronized(locked_action, external=True)        def _run_flow_locked():            _run_flow() #启动工作流。        if locked_action is None:            _run_flow()        else:            _run_flow_locked()        # Fetch created volume from storage        volume_ref = flow_engine.storage.fetch('volume')        # Update volume stats        self.stats['allocated_capacity_gb'] += volume_ref['size']        return volume_ref['id']

/cinder/volume/manager.py
这里写图片描述
/cinder/volume/manager.py
这里写图片描述
根据配置选择加载需要的driver(默认driver
cinder.volume.drivers.lvm.LVMISCSIDriver)
/cinder/volume/manager.py
这里写图片描述
/cinder/volume/flows/manager/create_volume.py

def get_flow(context, db, driver, scheduler_rpcapi, host, volume_id,             allow_reschedule, reschedule_context, request_spec,             filter_properties, snapshot_id=None, image_id=None,             source_volid=None):    """Constructs and returns the manager entrypoint flow.    This flow will do the following:    1. Determines if rescheduling is enabled (ahead of time).    2. Inject keys & values for dependent tasks.    3. Selects 1 of 2 activated only on *failure* tasks (one to update the db       status & notify or one to update the db status & notify & *reschedule*).    4. Extracts a volume specification from the provided inputs.    5. Notifies that the volume has start to be created.    6. Creates a volume from the extracted volume specification.    7. Attaches a on-success *only* task that notifies that the volume creation       has ended and performs further database status updates.    """    flow_name = ACTION.replace(":", "_") + "_manager"    volume_flow = linear_flow.Flow(flow_name)    # This injects the initial starting flow values into the workflow so that    # the dependency order of the tasks provides/requires can be correctly    # determined.    create_what = {        'context': context,        'filter_properties': filter_properties,        'image_id': image_id,        'request_spec': request_spec,        'snapshot_id': snapshot_id,        'source_volid': source_volid,        'volume_id': volume_id,    }    volume_flow.add(ExtractVolumeRefTask(db, host))    if allow_reschedule and request_spec:        volume_flow.add(OnFailureRescheduleTask(reschedule_context,                                                db, scheduler_rpcapi))    #create volume    volume_flow.add(ExtractVolumeSpecTask(db),                    NotifyVolumeActionTask(db, "create.start"),                    CreateVolumeFromSpecTask(db, driver),                    CreateVolumeOnFinishTask(db, "create.end"))    # Now load (but do not run) the flow using the provided initial data.return taskflow.engines.load(volume_flow, store=create_what)

/cinder/volume/flows/manager/create_volume.py
这里写图片描述
ExtractVolumeSpecTask NotifyVolumeActionTask
CreateVolumeFromSpecTask CreateVolumeOnFinishTask
创建volume的工作flow
这里注重介绍CreateVolumeFromSpecTask
/cinder/volume/flows/manager/create_volume.py
这里写图片描述
/cinder/volume/flows/manager/create_volume.py
这里写图片描述
假设create_type是raw,则调用_create_raw_volume()

def _create_raw_volume(self, context, volume_ref, **kwargs):#dirver=cinder.volume.drivers.lvm.LVMISCSIDriver        return self.driver.create_volume(volume_ref)

/cinder/volume/driver/lvm.py
这里写图片描述
LVMISCSIDriver类继承了LVMVolumeDriver、driver.ISCSIDriver
/cinder/volume/driver/lvm.py
这里写图片描述
/cinder/volume/driver/lvm.py
这里写图片描述
/cinder/brick/local_dev/lvm.py
这里写图片描述

0 0
原创粉丝点击