Cinder 云盘创建与挂载流程
Cinder 的设计遵循 service -> manager -> driver 的三层架构。
主要包括 cinder-api, cinder-scheduler, cinder-volume 三大核心组件(进程),组件之间通过 RPC 进行通信。
RESTful 入口 cinder-api
# etc/nova/api-paste.ini
[app:apiv3]
paste.app_factory = cinder.api.v3.router:APIRouter.factory
# cinder/api/openstack/__init__py
class APIRouter(base_wsgi.Router):
def __init__
ext_mgr = self.ExtensionManager()
self._setup_routes(mapper, ext_mgr)
self._setup_ext_routes(mapper, ext_mgr)
self._setup_extensions(ext_mgr)
# cinder/api/v3/router.py
class APIRouter(cinder.api.openstack.APIRouter):
ExtensionManager = extensions.ExtensionManager
def _setup_routes(self, mapper, ext_mgr):
self.resources['volumes'] = volumes.create_resource(ext_mgr)
mapper.resource("volume", "volumes",
controller=self.resources['volumes'],
collection={'detail': 'GET', 'summary': 'GET'},
member={'action': 'POST'})
self.resources['attachments'] = attachments.create_resource(ext_mgr)
mapper.resource("attachment", "attachments",
controller=self.resources['attachments'],
collection={'detail': 'GET', 'summary': 'GET'},
member={'action': 'POST'})
云盘创建
# cinder/api/v3/volumes.py
class VolumeController(volumes_v2.VolumeController):
def create
self.volume_api.create
# cinder/volume/api.py
class API(base.Base):
def create
flow_engine = create_volume.get_flow
flow_engine.run()
# cinder/volume/flow/api/create_volume.py
def get_flow
api_flow.add(VolumeCastTask(scheduler_rpcapi, volume_rpcapi, db_api))
class VolumeCastTask(flow_utils.CinderTask):
def execute
self._cast_create_volume
def _cast_create_volume
self.scheduler_rpcapi.create_volume
Cinder 的 scheduler 没有像 Nova 一样提供 api 对 rpcapi 进行封装,整个组件间的交互流程也比 Nova 要简单清晰的很多
# cinder/scheduler/rpcapi.py
class SchedulerAPI(rpc.RPCAPI):
def create_volume
cctxt.cast(ctxt, 'create_volume', **msg_args)
# cinder/scheduler/manager.py
scheduler_manager_opts = [
cfg.StrOpt('scheduler_driver',
default='cinder.scheduler.filter_scheduler.FilterScheduler',
help='Default scheduler driver to use'),
]
class SchedulerManager(manager.CleanableManager, manager.Manager):
def create_volume
flow_engine = create_volume.get_flow
scheduler_flow.add(ScheduleCreateVolumeTask(driver_api))
flow_engine.run()
# cinder/scheduler/flows/create_volume.py
def get_flow
scheduler_flow.add(ScheduleCreateVolumeTask(driver_api))
class ScheduleCreateVolumeTask(flow_utils.CinderTask):
def execute
# 驱动由配置选项 scheduler_driver 决定,默认值为 cinder.scheduler.filter_scheduler.FilterScheduler
self.driver_api.schedule_create_volume
# cinder/scheduler/filter_scheduler.py
class FilterScheduler(driver.Scheduler):
def schedule_create_volume
self._schedule
self._get_weighted_candidates
self._choose_top_backend
self.volume_rpcapi.create_volume
从 cinder-api 到 cinder-scheduler,现在终于到了 cinder-volume,需要注意的是,每个不同的后端,会创建一个对应的 manager,其中 class VolumeManager
的 service_name
初始化参数决定了 manager 对应的后端卷驱动(请参考 cinder/cmd/volume.py 对 CONF.enabled_backends 选项的处理)
# cinder/volume/rpcapi.py
class VolumeAPI(rpc.RPCAPI):
def create_volume
cctxt.cast(ctxt, 'create_volume',
request_spec=request_spec,
filter_properties=filter_properties,
allow_reschedule=allow_reschedule,
volume=volume)
# cinder/volume/manager.py
class VolumeManager(manager.CleanableManager,
manager.SchedulerDependentManager):
def create_volume
flow_engine = create_volume.get_flow
flow_engine.run()
# cinder/volume/flows/manager/create_volume.py
def get_flow
volume_flow.add(ExtractVolumeSpecTask(db),
NotifyVolumeActionTask(db, "create.start"),
CreateVolumeFromSpecTask(manager,
db,
driver,
image_volume_cache),
CreateVolumeOnFinishTask(db, "create.end"))
class CreateVolumeFromSpecTask(flow_utils.CinderTask):
def execute
if create_type == 'raw':
self._create_raw_volume
self.driver.create_volume
elif create_type == 'snap':
self._create_from_snapshot
self.driver.create_volume_from_snapshot
elif create_type == 'source_vol':
self._create_from_source_volume
self.driver.create_cloned_volume
elif create_type == 'image':
elf._create_from_image
elif create_type == 'backup':
self._create_from_backup
根据不同的后端类型,不同的驱动有不同的处理逻辑
# cinder/volume/drivers/rbd.py
class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
driver.ManageableVD, driver.ManageableSnapshotsVD,
driver.BaseVD):
def create_volume
self.RBDProxy().create
云盘挂载
Nova 进行云盘挂载时会调用 Cinder 的 attachments RESTful 接口返回 os_brick 挂载所需要的信息。
# cinder/api/v3/attachments.py
class AttachmentsController(wsgi.Controller):
def update
self.volume_api.attachment_update
# cinder/volume/api.py
class API(base.Base):
def attachment_update
self.volume_rpcapi.attachment_update
# cinder/volume/rpcapi.py
class VolumeAPI(rpc.RPCAPI):
def attachment_update
cctxt.call(ctxt,
'attachment_update',
vref=vref,
connector=connector,
attachment_id=attachment_id)
# cinder/volume/manager.py
class VolumeManager(manager.CleanableManager,
manager.SchedulerDependentManager):
def attachment_update
self._connection_create
self.driver.initialize_connection
# 回调,多数驱动都没有实现该接口,默认实现为空
self.driver.attach_volume
# cinder/volume/drivers/rbd.py
def initialize_connection(self, volume, connector):
hosts, ports = self._get_mon_addrs()
data = {
'driver_volume_type': 'rbd',
'data': {
'name': '%s/%s' % (self.configuration.rbd_pool,
volume.name),
'hosts': hosts,
'ports': ports,
'cluster_name': self.configuration.rbd_cluster_name,
'auth_enabled': (self.configuration.rbd_user is not None),
'auth_username': self.configuration.rbd_user,
'secret_type': 'ceph',
'secret_uuid': self.configuration.rbd_secret_uuid,
'volume_id': volume.id,
"discard": True,
'keyring': self._get_keyring_contents(),
}
}
LOG.debug('connection data: %s', data)
return data
最后修改于 2019-07-08