Cinder源码跟踪笔记

注: 这是本人看cinder代码时候的一些脉络整理记录。不做具体详细的逐行分析。
参考文档: http://blog.csdn.net/gaoxingnengjisuan/article/category/1853287

Cinder服务起来以后,会有三个服务,api,schedule,volume。这次主要是通过volume创建一个卷的操作来理解cinder代码的跳转运作。

大致流程:

APIRouter【cinder.api.v2.router】 
→ VolumeController:create 【cinder.api.v2.volumes】
→ volume_api:create【config里面的volume_api_class配置,默认是cinder.volume.api.API】
→ create_volume : get_flow 【cinder.volume.flows.api.create_volume】
→ 构建flow,把相应的task放到flow里面执行
→ 执行flow,VolumeCastTask
→ VolumeCastTask : execute → _cast_create_volume
→ _cast_create_volume : 如果不存存在可以用的主机,则使用调度器进行主机的选择①,否则直接使用volume的主机创建②。
①→ scheduler_rpcapi.create_volume 【cinder.scheduler.rpcapi】发送rpc消息cast
→ manager接受rpc cast消息【cinder.scheduler.manager】,相同的方法名 create_volume
→ create_volume.get_flow 【cinder.scheduler.flows】,调用数据库【cinder.db】,调用driver【config里scheduler_driver=cinder.scheduler.filter_scheduler.FilterScheduler】。创建flow,给flow加入task
→ 执行flow,ScheduleCreateVolumeTask:execute
→ 调用driver的具体实现来进行过滤:schedule_create_volume【cinder.scheduler.filter_scheduler.FilterScheduler】,如果没有合适主机则抛出异常。
→ 调用 volume_rpcapi.create_volume 发送rpc cast消息,转到②
②→ volume_rpcapi.create_volume【cinder.volume.rpcapi】发送rpc消息cast
→ manager接受rpc cast消息【cinder.volume.manager】,通过create_volume接收
→ create_volume.get_flow【cinder.volume.flows.manager.create_volume】,这里就是实际创建一个卷的代码了,CreateVolumeFromSpecTask。
→ CreateVolumeFromSpecTask中可以根据volume_type 来选择创建卷的方式(raw,snapshot,image,源卷)

APIRouter

在CLI中输入cinder create命令后,可以创建一个卷。首先,命令通过RESTful API会在 cinder.api.v2.router.APIRouter中路由到所对应的controller方法捕获。create命令对应的就是里面的create方法。

#cinder/api/v2/router.py
self.resources['volumes'] = volumes.create_resource(ext_mgr)
        mapper.resource("volume", "volumes",
                        controller=self.resources['volumes'],
                        collection={'detail': 'GET'},
                        member={'action': 'POST'})

wsgi router 的 Resource

router的Resource会找到相应的cinder.api.v1.volumes.VolumeController里面对应的create方法:VolumeController:create

  • 在这个类里面的create方法中,主要是通过req和body解析出建立卷所需要的参数。
#cinder/api/v1/volumes.py
@wsgi.response(202)
@wsgi.serializers(xml=VolumeTemplate)
@wsgi.deserializers(xml=CreateDeserializer)
def create(self, req, body):
    # ......
    # 前面都是处理req请求的,主要是解析建立卷所需要的参数
    # 最后通过volume_api的create方法创建
    # volume_api是通过cinder.conf配置的
    # 默认是cinder.volume.api.APIvolume_api_class
    new_volume = self.volume_api.create(context,
                                            size,
                                            volume.get('display_name'),
                                            volume.get('display_description'),
                                            **kwargs)

Cinder/volume/api.API

跳到这一步,分析构建卷的参数,构建taskflow模式。
这里通过调用taskflow模式,通过get_flow跳转到cinder.volume.flows.api.create_volum中

#Cinder/volume/api.py
 try:
            flow_engine = create_volume.get_flow(self.scheduler_rpcapi,
                                                     self.volume_rpcapi,
                                                     self.db,
                                                     self.image_service,
                                                     availability_zones,
                                                     create_what)
except Exception:
            msg = _('Failed to create api volume flow.')
            LOG.exception(msg)
            raise exception.CinderException(msg)

Taskflow模式

  • 构建flow,把相应的task放到flow里面执行
  • 执行flow,VolumeCastTask
#cinder.volume.flows.api.create_volum.py
def get_flow(scheduler_rpcapi, volume_rpcapi, db_api,
             image_service_api, availability_zones,
             create_what):
    """Constructs and returns the api entrypoint flow.

    This flow will do the following:

    1. Inject keys & values for dependent tasks.
    2. Extracts and validates the input 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 = ACTION.replace(":", "_") + "_api"
    api_flow = linear_flow.Flow(flow_name)

    api_flow.add(ExtractVolumeRequestTask(
        image_service_api,
        availability_zones,
        rebind={'size': 'raw_size',
                'availability_zone': 'raw_availability_zone',
                'volume_type': 'raw_volume_type'}))
    api_flow.add(QuotaReserveTask(),
                 EntryCreateTask(db_api),
                 QuotaCommitTask())

    # This will cast it out to either the scheduler or volume manager via
    # the rpc apis provided.
    api_flow.add(VolumeCastTask(scheduler_rpcapi, volume_rpcapi, db_api))

    # Now load (but do not run) the flow using the provided initial data.
    return taskflow.engines.load(api_flow, store=create_what)

这里实际做到创建卷这个动作的就是在VolumeCastTask 这个task中,通过里面的execute调用到_cast_create_volume方法,这里的主要作用就是会判断,如果已经确定了不存在可以用的主机,就使用调度器调度的方法找到主机后再通过volume的driver来做具体的创建操作①,如果已经存在可用主机,就直接调用driver来创建卷②。

① 通过scheduler模块找到合适主机
  • 上一步就会跳转到代码:cinder.scheduler.rpcapi.py来发送消息
    • scheduler_rpcapi.create_volume 发送rpc cast消息。
  • 一般来说,一个模块的rpc消息,都是通过这个模块的manager.py里面的同名方法,create_volume来接收的。这里就是cinder.scheduler.manager.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):

        self._wait_for_scheduler()
        try:
        #这里的create_volume是cinder.scheduler.flows里面的create_volume.py
            flow_engine = create_volume.get_flow(context,
                                                 db, self.driver,
                                                 request_spec,
                                                 filter_properties,
                                                 volume_id,
                                                 snapshot_id,
                                                 image_id)
        except Exception:
            msg = _("Failed to create scheduler manager volume flow")
            LOG.exception(msg)
            raise exception.CinderException(msg)

        with flow_utils.DynamicLogListener(flow_engine, logger=LOG):
            flow_engine.run()
  • 接着在上面的get_flow继续进入taskflow模式,构建flow。db就是cinder的数据库: cinder.db;self.driver是通过cinder.conf配置的scheduler_driver确定的,默认是cinder.scheduler.filter_scheduler.FilterScheduler

  • 其中在get_flow中, 主要用于调度作用的是ScheduleCreateVolumeTask这个task,它的execute方法中,就会通过调用schedule_driver里面的schedule_create_volume来执行调度的方法找到适用的主机。

  • 找到主机以后再通过volume_rpcapi来发送cast信息给volume来执行创建操作②

② 通过volume模块来创建卷
  • cinder.volume.manager 接收rpc消息,create_volume

  • 创建taskflow来执行具体的创建操作。主要就是cinder.volume.flows.manager.create_volume 里面的
    CreateVolumeFromSpecTask方法。

  • CreateVolumeFromSpecTask可以根据volume_type来选择创建卷的方式,一共有四种raw,snapshot,image,源卷。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值