diff --git a/src/driver/controller-synology/http/index.js b/src/driver/controller-synology/http/index.js index 66fe124..6f45ed2 100644 --- a/src/driver/controller-synology/http/index.js +++ b/src/driver/controller-synology/http/index.js @@ -174,6 +174,23 @@ class SynologyHttpClient { } } + async GetLunByID(lun_id) { + const lun_list = { + api: "SYNO.Core.ISCSI.LUN", + version: "1", + method: "list", + }; + + let response = await this.do_request("GET", "entry.cgi", lun_list); + let lun = response.body.data.luns.find((i) => { + return i.lun_id == lun_id; + }); + + if (lun) { + return lun; + } + } + async GetLunByName(name) { const lun_list = { api: "SYNO.Core.ISCSI.LUN", @@ -464,6 +481,36 @@ class SynologyHttpClient { Object.assign({}, iscsi_lun_extend, { uuid: uuid, new_size: size }) ); } + + + + async CreateClonedVolume(src_lun_uuid, dst_lun_name) { + const create_cloned_volume = { + api: "SYNO.Core.ISCSI.LUN", + version: 1, + method: "clone", + src_lun_uuid: JSON.stringify(src_lun_uuid), // src lun uuid + dst_lun_name: dst_lun_name, // dst lun name + is_same_pool: true, // always true? string? + clone_type: "democratic-csi", // check + } + return await this.do_request("GET", "entry.cgi", create_cloned_volume); + } + + async CreateVolumeFromSnapshot(src_lun_uuid, snapshot_uuid, cloned_lun_name) { + const create_volume_from_snapshot = { + api: "SYNO.Core.ISCSI.LUN", + version: 1, + method: "clone_snapshot", + src_lun_uuid: src_lun_uuid, // src lun uuid, snapshot id? + snapshot_uuid: JSON.stringify(snapshot_uuid), // shaptop uuid + cloned_lun_name: cloned_lun_name, // cloned lun name + clone_type: "democratic-csi", // check + } + return await this.do_request("GET", "entry.cgi", create_volume_from_snapshot); + } + + } module.exports.SynologyHttpClient = SynologyHttpClient; diff --git a/src/driver/controller-synology/index.js b/src/driver/controller-synology/index.js index f405fab..01158a9 100644 --- a/src/driver/controller-synology/index.js +++ b/src/driver/controller-synology/index.js @@ -280,14 +280,63 @@ class ControllerSynologyDriver extends CsiBaseDriver { let data; let target; let lun_mapping; + let lun_uuid; + let existingLun; - // create lun - data = Object.assign({}, driver.options.iscsi.lunAttributes, { - name: iscsiName, - location: driver.options.synology.volume, - size: capacity_bytes, - }); - let lun_uuid = await httpClient.CreateLun(data); + if (volume_content_source) { + let src_lun_uuid; + let src_lun_id; + switch (volume_content_source.type) { + case "snapshot": + let parts = volume_content_source.snapshot.snapshot_id.split("/"); + src_lun_id = parts[2]; + let snapshot_uuid = parts[3]; + let src_lun = await httpClient.GetLunByID(src_lun_id); + src_lun_uuid = src_lun.uuid; + + existingLun = await httpClient.GetLunByName(iscsiName); + if (!existingLun) { + await httpClient.CreateVolumeFromSnapshot( + src_lun_uuid, + snapshot_uuid, + iscsiName + ); + } + break; + case "volume": + let srcLunName = driver.buildIscsiName( + volume_content_source.volume.volume_id + ); + src_lun_uuid = await httpClient.GetLunUUIDByName(srcLunName); + + existingLun = httpClient.GetLunByName(iscsiName); + if (!existingLun) { + await httpClient.CreateClonedVolume(src_lun_uuid, iscsiName); + } + break; + default: + throw new GrpcError( + grpc.status.INVALID_ARGUMENT, + `invalid volume_content_source type: ${volume_content_source.type}` + ); + break; + } + // resize to requested amount + + let lun = await httpClient.GetLunByName(iscsiName); + lun_uuid = lun.uuid; + if (lun.size < capacity_bytes) { + await httpClient.ExpandISCSILun(lun_uuid, capacity_bytes); + } + } else { + // create lun + data = Object.assign({}, driver.options.iscsi.lunAttributes, { + name: iscsiName, + location: driver.options.synology.volume, + size: capacity_bytes, + }); + lun_uuid = await httpClient.CreateLun(data); + } // create target let iqn = driver.options.iscsi.baseiqn + iscsiName; @@ -437,16 +486,16 @@ class ControllerSynologyDriver extends CsiBaseDriver { driver.options.api.lunDelete.settleMaxRetries || 6; let settleSeconds = driver.options.api.lunDelete.settleSeconds || 5; let waitTimeBetweenChecks = settleSeconds * 1000; - + await sleep(waitTimeBetweenChecks); lun_uuid = await httpClient.GetLunUUIDByName(iscsiName); - + while (currentCheck <= settleMaxRetries && lun_uuid) { currentCheck++; await sleep(waitTimeBetweenChecks); lun_uuid = await httpClient.GetLunUUIDByName(iscsiName); } - + if (lun_uuid) { throw new GrpcError( grpc.status.UNKNOWN,