基于ocata版本,创建快照的代码流程梳理
1、用户下发创建快照的命令
cinder --debug snapshot-create ee514adb-4e05-4ede-876a-c9a9d95cc1da
curl -g -i -X POST http://10.27.244.33:8776/v2/ec5405bdbcd243bbaf5b40093181ff70/snapshots -H "User-Agent: python-cinderclient" -H "Content-Type: application/json" -H "Accept: application/json" -H "X-Auth-Token: {SHA1}72f3a32d5a1929eca8d181f9c270545f9bf83dfa" -d { "snapshot": { "description": null, "metadata": {}, "force": false, "name": null, "volume_id": "ee514adb-4e05-4ede-876a-c9a9d95cc1da" } }
响应体
{ "snapshot": { "status": "creating", "size": 1, "metadata": {}, "name": null, "volume_id": "ee514adb-4e05-4ede-876a-c9a9d95cc1da", "created_at": "2019-06-13T06:39:42.076207", "description": null, "id": "9d5dead2-4aa3-4178-a08b-c695598b683d", "updated_at": null } }
创建快照时,给快照起一个名字并且加描述信息
cinder --debug snapshot-create ee514adb-4e05-4ede-876a-c9a9d95cc1da --name=chenwei --description=test2
cinder --debug snapshot-create ee514adb-4e05-4ede-876a-c9a9d95cc1da --name=chenwei --description=test2 -H "User-Agent: python-cinderclient" -H "Content-Type: application/json" -H "Accept: application/json" -H "X-Auth-Token: {SHA1}7a1799ec02c94f5245b657cac274acee68886c05" -d { "snapshot": { "description": "test2", "metadata": {}, "force": false, "name": "chenwei", "volume_id": "ee514adb-4e05-4ede-876a-c9a9d95cc1da" } } 响应体 { "snapshot": { "status": "creating", "size": 1, "metadata": {}, "name": "chenwei", "volume_id": "ee514adb-4e05-4ede-876a-c9a9d95cc1da", "created_at": "2019-06-13T06:46:52.599300", "description": "test2", "id": "253fface-6400-4520-8d2f-237d96e614e4", "updated_at": null } }
查看cinder数据库中snapshot表的内容
mysql> select * from snapshots where id="253fface-6400-4520-8d2f-237d96e614e4"G; *************************** 1. row *************************** created_at: 2019-06-13 06:46:53 updated_at: 2019-06-13 06:46:53 deleted_at: NULL deleted: 0 id: 253fface-6400-4520-8d2f-237d96e614e4 volume_id: ee514adb-4e05-4ede-876a-c9a9d95cc1da user_id: 6a053d95688846a0823dfae9648a05f4 project_id: ec5405bdbcd243bbaf5b40093181ff70 status: available progress: 100% volume_size: 1 scheduled_at: NULL display_name: chenwei display_description: test2 provider_location: NULL encryption_key_id: NULL volume_type_id: NULL cgsnapshot_id: NULL provider_id: NULL provider_auth: NULL group_snapshot_id: NULL 1 row in set (0.00 sec)
[root@xxx glance]# cinder snapshot-list +--------------------------------------+--------------------------------------+-----------+---------+------+ | ID | Volume ID | Status | Name | Size | +--------------------------------------+--------------------------------------+-----------+---------+------+ | 253fface-6400-4520-8d2f-237d96e614e4 | ee514adb-4e05-4ede-876a-c9a9d95cc1da | available | chenwei | 1 | | 9d5dead2-4aa3-4178-a08b-c695598b683d | ee514adb-4e05-4ede-876a-c9a9d95cc1da | available | - | 1 | +--------------------------------------+--------------------------------------+-----------+---------+------+
1、用户发送创建快照的HTTP请求,对应的api接口如下
POST /v2/{project_id}/snapshots Request样例: { "snapshot": { "name": "snap-001", "description": "Daily backup", "volume_id": "5aa119a8-d25b-45a7-8d1b-88e127885635", "force": true, "metadata": { "key": "v3" } } }
2、cinder api接受该请求,并处理的入口函数cinder/api/v2/snapshots.py:class SnapshotsController(wsgi.Controller):create
def create(self, req, body): """Creates a new snapshot.""" ....... snapshot = body['snapshot'] try: volume_id = snapshot['volume_id']-----------------从请求体中获取卷的id except KeyError: msg = _("'volume_id' must be specified") raise exc.HTTPBadRequest(explanation=msg) volume = self.volume_api.get(context, volume_id)--------- 调用volume接口,获取卷的信息 force = snapshot.get('force', False)----------------默认为false ..... # NOTE(thingee): v2 API allows name instead of display_name if 'name' in snapshot: snapshot['display_name'] = snapshot.pop('name')------给snapshot的display_name参数赋值 ..... if force: new_snapshot = self.volume_api.create_snapshot_force( context, volume, snapshot.get('display_name'), snapshot.get('description'), **kwargs) else: new_snapshot = self.volume_api.create_snapshot(--------------调用create_snapshot创建快照 context, volume, snapshot.get('display_name'), snapshot.get('description'), **kwargs) req.cache_db_snapshot(new_snapshot) return self._view_builder.detail(req, new_snapshot)
3、cinder/volume/api.py:class API(base.Base):create_snapshot函数
self.volume_api = volume.API() def create_snapshot(self, context, volume, name, -------------卷的名字 description,-------卷的描述信息 metadata=None, cgsnapshot_id=None, group_snapshot_id=None): result = self._create_snapshot(context, volume, name, description, False, metadata, cgsnapshot_id, group_snapshot_id) LOG.info(_LI("Snapshot create request issued successfully."), resource=result) return result def _create_snapshot(self, context, volume, name, description, force=False, metadata=None, cgsnapshot_id=None, group_snapshot_id=None): volume.assert_not_frozen() snapshot = self.create_snapshot_in_db(---------------s1先预留配额,然后在数据库中添加快照entry, context, volume, name, description, force, metadata, cgsnapshot_id, True, group_snapshot_id) self.volume_rpcapi.create_snapshot(context, volume, snapshot)------发送rpc请求,创建snapshot
s1步,对create_snapshot_in_db函数中详解
def create_snapshot_in_db() ..... if commit_quota: try: if CONF.no_snapshot_gb_quota:----默认值为false reserve_opts = {'snapshots': 1} else: reserve_opts = {'snapshots': 1, 'gigabytes': volume['size']} QUOTAS.add_volume_type_opts(context, reserve_opts, volume.get('volume_type_id')) reservations = QUOTAS.reserve(context, **reserve_opts) snapshot = objects.Snapshot(context=context, **kwargs) snapshot.create() if commit_quota: QUOTAS.commit(context, reservations)
4、发送rpc请求,给cinder-manager,进行创建快照
cinder/volume/rpcapi.py:class VolumeAPI(rpc.RPCAPI):create_snapshot def create_snapshot(self, ctxt, volume, snapshot): snapshot.create_worker() cctxt = self._get_cctxt(volume.service_topic_queue)----传入volume参数,为了寻找消息队列 cctxt.cast(ctxt, 'create_snapshot', snapshot=snapshot) cinder/volume/manager.py:class VolumeManager:create_snapshot(self, context, snapshot): def create_snapshot(self, context, snapshot): """Creates and exports the snapshot.""" context = context.elevated() self._notify_about_snapshot_usage( context, snapshot, "create.start") try: # NOTE(flaper87): Verify the driver is enabled # before going forward. The exception will be caught # and the snapshot status updated. utils.require_driver_initialized(self.driver)-------s1初始化相关驱动,debug调试self.driver=<cinder.volume.drivers.lvm.LVMVolumeDriver object at 0x71e34d0> # Pass context so that drivers that want to use it, can, # but it is not a requirement for all drivers. snapshot.context = context model_update = self.driver.create_snapshot(snapshot)------s2调用对应驱动程序的create_snapshot if model_update: snapshot.update(model_update)------------------s3更新数据库snapshots表 snapshot.save() ........ vol_ref = self.db.volume_get(context, snapshot.volume_id)--------s3从数据库获取快照对应卷的信息 if vol_ref.bootable:-------------s4如果卷是可启动的,同步glance metadata信息 try: self.db.volume_glance_metadata_copy_to_snapshot( context, snapshot.id, snapshot.volume_id) ......... snapshot.status = fields.SnapshotStatus.AVAILABLE snapshot.progress = '100%' snapshot.save() self._notify_about_snapshot_usage(context, snapshot, "create.end") LOG.info(_LI("Create snapshot completed successfully"), resource=snapshot) return snapshot.id s1 self.driver=<cinder.volume.drivers.lvm.LVMVolumeDriver object at 0x71e34d0> s2 snapshot的值 Snapshot(cgsnapshot=<?>, cgsnapshot_id=None, created_at=2019-06-13T07:40:09Z, deleted=False, deleted_at=None, display_description='test3', display_name='chenwei1', encryption_key_id=None, group_snapshot=<?>, group_snapshot_id=None, id=d580f2e9-03de-4ffa-833d-366785ad77fb, metadata={}, progress='0%', project_id='ec5405bdbcd243bbaf5b40093181ff70', provider_auth=None, provider_id=None, provider_location=None, status='creating', updated_at=None, user_id='6a053d95688846a0823dfae9648a05f4', volume=<?>, volume_id=ee514adb-4e05-4ede-876a-c9a9d95cc1da, volume_size=1, volume_type_id=None)
5、以lvm驱动为例
cinder/volume/drivers/lvm.py def create_snapshot(self, snapshot): """Creates a snapshot.""" self.vg.create_lv_snapshot(self._escape_snapshot(snapshot['name']), snapshot['volume_name'], self.configuration.lvm_type) 调试信息 self.vg=<cinder.brick.local_dev.lvm.LVM object at 0x62addd0> snapshot['name']='snapshot-95ed2e2e-904a-4d42-a8e6-cade527e8812',没搞明白这两个值是怎么传过来的,5步打印的值,并没有这个name snapshot['volume_name']='volume-ee514adb-4e05-4ede-876a-c9a9d95cc1da'
6、最终代码会调用到cinder/brick/local_dev/lvm.py中的create_lv_snapshot函数,执行lvm的相关命令行
@utils.retry(putils.ProcessExecutionError) def create_lv_snapshot(self, name, source_lv_name, lv_type='default'): """Creates a snapshot of a logical volume. :param name: Name to assign to new snapshot :param source_lv_name: Name of Logical Volume to snapshot :param lv_type: Type of LV (default or thin) """ source_lvref = self.get_volume(source_lv_name) if source_lvref is None: LOG.error(_LE("Trying to create snapshot by non-existent LV: %s"), source_lv_name) raise exception.VolumeDeviceNotFound(device=source_lv_name) cmd = LVM.LVM_CMD_PREFIX + ['lvcreate', '--name', name, '--snapshot', '%s/%s' % (self.vg_name, source_lv_name)] if lv_type != 'thin': size = source_lvref['size'] cmd.extend(['-L', '%sg' % (size)]) try: self._execute(*cmd, root_helper=self._root_helper, run_as_root=True) except putils.ProcessExecutionError as err: LOG.exception(_LE('Error creating snapshot')) LOG.error(_LE('Cmd :%s'), err.cmd) LOG.error(_LE('StdOut :%s'), err.stdout) LOG.error(_LE('StdErr :%s'), err.stderr) raise
7、在计算节点上执行相关的lvs命令行,本质上对于Lvm驱动来说,快照(在某一个时间点上,卷数据的完全拷贝)就是一个lvm卷
[root@xxx site-packages]# lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
_snapshot-1ee9b7f6-65a5-4d1c-9a27-126082b28933 vg_os swi-a-s--- 1.00g volume-ee514adb-4e05-4ede-876a-c9a9d95cc1da 0.00
_snapshot-253fface-6400-4520-8d2f-237d96e614e4 vg_os swi-a-s--- 1.00g volume-ee514adb-4e05-4ede-876a-c9a9d95cc1da 0.00
_snapshot-9d5dead2-4aa3-4178-a08b-c695598b683d vg_os swi-a-s--- 1.00g volume-ee514adb-4e05-4ede-876a-c9a9d95cc1da 0.00
_snapshot-d580f2e9-03de-4ffa-833d-366785ad77fb vg_os swi-a-s--- 1.00g volume-ee514adb-4e05-4ede-876a-c9a9d95cc1da 0.00
_snapshot-eec80f33-97a5-445f-8282-57720f475fc5 vg_os swi-a-s--- 1.00g volume-ee514adb-4e05-4ede-876a-c9a9d95cc1da 0.00
lv_os_data vg_os -wi-ao---- 300.00g
lv_os_instance vg_os -wi-ao---- 400.00g
volume-ee514adb-4e05-4ede-876a-c9a9d95cc1da vg_os owi-aos--- 1.00g
[root@xgto02n010027244153 site-packages]#