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
- cinder创建volume流程简介
- cinder创建volume的流程分析
- cinder 创建backup volume
- cinder创建的volume通过iscsi协议挂载到instance流程分析
- openstack cinder default volume
- Cinder volume 挂载
- 从cinder 删除volume 分析cinder rpc
- 修改Cinder的Volume配额
- 从Cinder volume启动虚拟机
- service openstack-cinder-volume status
- pvcreate 创建pv出现 Can't initialize physical volume"/dev/loop2" of volume group "cinder-volumes2" witho
- [openstack]创建卷(create volume)流程
- 【cinder】从snapshot中创建volume都在同一节点的问题
- [问题篇]VMWare搭建Openstack——Cinder创建扩展Volume的状态Error的问题
- openstack 创建cinder服务的磁盘时,出现ISCSITargetCreateFailed Failed to create iscsi target for volume
- cinder 基于镜像创建volume, 竟然下载镜像,问题排查
- cinder创建云硬盘的时候 出现 cinder-volume | linux-node2@lvm | nova | enabled | down | 2017-04-26T22:45:47.
- OpenStack源码分析之cinder-volume服务
- Spring整合RMI
- Android单元测试
- mysql5.6迁移到mariadb
- android平台led开发之内核硬件驱动层(一)
- delphi EncdDecd.pas单元中Encoding方法出现#$D#$A的解决方法
- cinder创建volume流程简介
- Unity3d陀螺仪看全景图
- android微信支付
- 华为历年机试题型总结系列(七)
- C#发送邮件的方法及实例代码
- aidl is missing
- JAVA多线程编程(三)——线程的生命周期(sleep,join,interrupt)
- JVM学习笔记(一)------基本结构
- MAC命令 和 vi命令