基于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]#