synology snapshots, getcapacity, misc
This commit is contained in:
		
							parent
							
								
									c761b426d4
								
							
						
					
					
						commit
						66a22d718f
					
				|  | @ -143,6 +143,111 @@ class SynologyHttpClient { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   async GetLunIDByName(name) { | ||||||
|  |     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.name == name; | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     if (lun) { | ||||||
|  |       return lun.lun_id; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async GetLunByName(name) { | ||||||
|  |     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.name == name; | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     if (lun) { | ||||||
|  |       return lun; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async GetSnapshotByLunIDAndName(lun_id, name) { | ||||||
|  |     const get_snapshot_info = { | ||||||
|  |       lid: lun_id, //check?
 | ||||||
|  |       api: "SYNO.Core.Storage.iSCSILUN", | ||||||
|  |       method: "load_snapshot", | ||||||
|  |       version: 1, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let response = await this.do_request("GET", "entry.cgi", get_snapshot_info); | ||||||
|  | 
 | ||||||
|  |     if (response.body.data) { | ||||||
|  |       let snapshot = response.body.data.find((i) => { | ||||||
|  |         return i.desc == name; | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       if (snapshot) { | ||||||
|  |         return snapshot; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async GetSnapshotByLunIDAndSnapshotUUID(lun_id, snapshot_uuid) { | ||||||
|  |     const get_snapshot_info = { | ||||||
|  |       lid: lun_id, //check?
 | ||||||
|  |       api: "SYNO.Core.Storage.iSCSILUN", | ||||||
|  |       method: "load_snapshot", | ||||||
|  |       version: 1, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let response = await this.do_request("GET", "entry.cgi", get_snapshot_info); | ||||||
|  | 
 | ||||||
|  |     if (response.body.data) { | ||||||
|  |       let snapshot = response.body.data.find((i) => { | ||||||
|  |         return i.uuid == snapshot_uuid; | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       if (snapshot) { | ||||||
|  |         return snapshot; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async DeleteSnapshot(snapshot_uuid) { | ||||||
|  |     const iscsi_snapshot_delete = { | ||||||
|  |       api: "SYNO.Core.ISCSI.LUN", | ||||||
|  |       method: "delete_snapshot", | ||||||
|  |       version: 1, | ||||||
|  |       snapshot_uuid: snapshot_uuid, // snapshot_id
 | ||||||
|  |       deleted_by: "democratic_csi", // ?
 | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let response = await this.do_request( | ||||||
|  |       "GET", | ||||||
|  |       "entry.cgi", | ||||||
|  |       iscsi_snapshot_delete | ||||||
|  |     ); | ||||||
|  |     // return?
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async GetVolumeInfo(volume_path) { | ||||||
|  |     let data = { | ||||||
|  |       api: "SYNO.Core.Storage.Volume", | ||||||
|  |       method: "get", | ||||||
|  |       version: "1", | ||||||
|  |       //volume_path: "/volume1",
 | ||||||
|  |       volume_path, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return await this.do_request("GET", "entry.cgi", data); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   async GetTargetByTargetID(target_id) { |   async GetTargetByTargetID(target_id) { | ||||||
|     let targets = await this.ListTargets(); |     let targets = await this.ListTargets(); | ||||||
|     let target = targets.find((i) => { |     let target = targets.find((i) => { | ||||||
|  | @ -237,18 +342,30 @@ class SynologyHttpClient { | ||||||
|       //is_soft_feas_ignored: false,
 |       //is_soft_feas_ignored: false,
 | ||||||
|       is_soft_feas_ignored: true, |       is_soft_feas_ignored: true, | ||||||
|     }; |     }; | ||||||
|     try { | 
 | ||||||
|       await this.do_request("GET", "entry.cgi", iscsi_lun_delete); |     await this.do_request("GET", "entry.cgi", iscsi_lun_delete); | ||||||
|     } catch (err) { | 
 | ||||||
|       /** |     // } catch (err) {
 | ||||||
|        * 18990710 = already gone |     //   /**
 | ||||||
|        * LUN_BAD_LUN_UUID = 18990505 |     //    * 18990710 = already gone
 | ||||||
|        * LUN_NO_SUCH_SNAPSHOT = 18990532 |     //    * LUN_BAD_LUN_UUID = 18990505
 | ||||||
|        */ |     //    * LUN_NO_SUCH_SNAPSHOT = 18990532
 | ||||||
|       if (![18990505].includes(err.body.error.code)) { |     //    *//*
 | ||||||
|         throw err; |     //   if (![18990505].includes(err.body.error.code)) {
 | ||||||
|       } |     //     throw err;
 | ||||||
|     } |     //   }
 | ||||||
|  |     // }
 | ||||||
|  |     // */
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async CreateSnapshot(data) { | ||||||
|  |     data = Object.assign({}, data, { | ||||||
|  |       api: "SYNO.Core.ISCSI.LUN", | ||||||
|  |       method: "take_snapshot", | ||||||
|  |       version: 1, | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return await this.do_request("GET", "entry.cgi", data); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async CreateTarget(data = {}) { |   async CreateTarget(data = {}) { | ||||||
|  | @ -311,9 +428,9 @@ class SynologyHttpClient { | ||||||
|       /** |       /** | ||||||
|        * 18990710 = non-existant |        * 18990710 = non-existant | ||||||
|        */ |        */ | ||||||
|       if (![18990710].includes(err.body.error.code)) { |       //if (![18990710].includes(err.body.error.code)) {
 | ||||||
|         throw err; |       throw err; | ||||||
|       } |       //}
 | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -324,7 +441,7 @@ class SynologyHttpClient { | ||||||
|       version: 1, |       version: 1, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     await this.do_request( |     return await this.do_request( | ||||||
|       "GET", |       "GET", | ||||||
|       "entry.cgi", |       "entry.cgi", | ||||||
|       Object.assign({}, iscsi_lun_extend, { uuid: uuid, new_size: size }) |       Object.assign({}, iscsi_lun_extend, { uuid: uuid, new_size: size }) | ||||||
|  |  | ||||||
|  | @ -53,8 +53,8 @@ class ControllerSynologyDriver extends CsiBaseDriver { | ||||||
|         "CREATE_DELETE_VOLUME", |         "CREATE_DELETE_VOLUME", | ||||||
|         //"PUBLISH_UNPUBLISH_VOLUME",
 |         //"PUBLISH_UNPUBLISH_VOLUME",
 | ||||||
|         //"LIST_VOLUMES",
 |         //"LIST_VOLUMES",
 | ||||||
|         //"GET_CAPACITY",
 |         "GET_CAPACITY", | ||||||
|         //"CREATE_DELETE_SNAPSHOT",
 |         "CREATE_DELETE_SNAPSHOT", | ||||||
|         //"LIST_SNAPSHOTS",
 |         //"LIST_SNAPSHOTS",
 | ||||||
|         //"CLONE_VOLUME",
 |         //"CLONE_VOLUME",
 | ||||||
|         //"PUBLISH_READONLY",
 |         //"PUBLISH_READONLY",
 | ||||||
|  | @ -69,7 +69,7 @@ class ControllerSynologyDriver extends CsiBaseDriver { | ||||||
|         //"UNKNOWN",
 |         //"UNKNOWN",
 | ||||||
|         "STAGE_UNSTAGE_VOLUME", |         "STAGE_UNSTAGE_VOLUME", | ||||||
|         "GET_VOLUME_STATS", |         "GET_VOLUME_STATS", | ||||||
|         //"EXPAND_VOLUME"
 |         "EXPAND_VOLUME", | ||||||
|       ]; |       ]; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | @ -407,13 +407,15 @@ class ControllerSynologyDriver extends CsiBaseDriver { | ||||||
|         let iscsiName = driver.buildIscsiName(name); |         let iscsiName = driver.buildIscsiName(name); | ||||||
|         let iqn = driver.options.iscsi.baseiqn + iscsiName; |         let iqn = driver.options.iscsi.baseiqn + iscsiName; | ||||||
| 
 | 
 | ||||||
|         response = await httpClient.GetTargetByIQN(iqn); |         let target = await httpClient.GetTargetByIQN(iqn); | ||||||
|         if (response) { |         if (target) { | ||||||
|           await httpClient.DeleteTarget(response.target_id); |           await httpClient.DeleteTarget(target.target_id); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         response = await httpClient.GetLunUUIDByName(iscsiName); |         let lun_uuid = await httpClient.GetLunUUIDByName(iscsiName); | ||||||
|         await httpClient.DeleteLun(response); |         if (lun_uuid) { | ||||||
|  |           await httpClient.DeleteLun(lun_uuid); | ||||||
|  |         } | ||||||
|         break; |         break; | ||||||
|       default: |       default: | ||||||
|         throw new GrpcError( |         throw new GrpcError( | ||||||
|  | @ -523,10 +525,33 @@ class ControllerSynologyDriver extends CsiBaseDriver { | ||||||
|    * @param {*} call |    * @param {*} call | ||||||
|    */ |    */ | ||||||
|   async GetCapacity(call) { |   async GetCapacity(call) { | ||||||
|     throw new GrpcError( |     // throw new GrpcError(
 | ||||||
|       grpc.status.UNIMPLEMENTED, |     //   grpc.status.UNIMPLEMENTED,
 | ||||||
|       `operation not supported by driver` |     //   `operation not supported by driver`
 | ||||||
|  |     // );
 | ||||||
|  | 
 | ||||||
|  |     const driver = this; | ||||||
|  |     const httpClient = await driver.getHttpClient(); | ||||||
|  | 
 | ||||||
|  |     if (!driver.options.synology.location) { | ||||||
|  |       throw new GrpcError( | ||||||
|  |         grpc.status.FAILED_PRECONDITION, | ||||||
|  |         `invalid configuration: missing location` | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (call.request.volume_capabilities) { | ||||||
|  |       const result = this.assertCapabilities(call.request.volume_capabilities); | ||||||
|  | 
 | ||||||
|  |       if (result.valid !== true) { | ||||||
|  |         return { available_capacity: 0 }; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let response = await httpClient.GetVolumeInfo( | ||||||
|  |       driver.options.synology.location | ||||||
|     ); |     ); | ||||||
|  |     return { available_capacity: response.body.data.volume.size_free_byte }; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|  | @ -558,11 +583,8 @@ class ControllerSynologyDriver extends CsiBaseDriver { | ||||||
|    * @param {*} call |    * @param {*} call | ||||||
|    */ |    */ | ||||||
|   async CreateSnapshot(call) { |   async CreateSnapshot(call) { | ||||||
|     throw new GrpcError( |  | ||||||
|       grpc.status.UNIMPLEMENTED, |  | ||||||
|       `operation not supported by driver` |  | ||||||
|     ); |  | ||||||
|     const driver = this; |     const driver = this; | ||||||
|  |     const httpClient = await driver.getHttpClient(); | ||||||
| 
 | 
 | ||||||
|     // both these are required
 |     // both these are required
 | ||||||
|     let source_volume_id = call.request.source_volume_id; |     let source_volume_id = call.request.source_volume_id; | ||||||
|  | @ -596,7 +618,47 @@ class ControllerSynologyDriver extends CsiBaseDriver { | ||||||
|       ); |       ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // TODO: create snapshot here
 |     // create snapshot here
 | ||||||
|  | 
 | ||||||
|  |     let iscsiName = driver.buildIscsiName(source_volume_id); | ||||||
|  |     let lun = await httpClient.GetLunByName(iscsiName); | ||||||
|  | 
 | ||||||
|  |     if (!lun) { | ||||||
|  |       throw new GrpcError( | ||||||
|  |         grpc.status.INVALID_ARGUMENT, | ||||||
|  |         `invalid source_volume_id: ${source_volume_id}` | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // check for already exists
 | ||||||
|  |     let snapshot = await httpClient.GetSnapshotByLunIDAndName(lun.lun_id, name); | ||||||
|  |     if (snapshot) { | ||||||
|  |       return { | ||||||
|  |         snapshot: { | ||||||
|  |           /** | ||||||
|  |            * The purpose of this field is to give CO guidance on how much space | ||||||
|  |            * is needed to create a volume from this snapshot. | ||||||
|  |            */ | ||||||
|  |           size_bytes: 0, | ||||||
|  |           snapshot_id: `/lun/${lun.lun_id}/${snapshot.uuid}`, // add shanpshot_uuid //fixme
 | ||||||
|  |           source_volume_id: source_volume_id, | ||||||
|  |           //https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/timestamp.proto
 | ||||||
|  |           creation_time: { | ||||||
|  |             seconds: snapshot.time, | ||||||
|  |             nanos: 0, | ||||||
|  |           }, | ||||||
|  |           ready_to_use: true, | ||||||
|  |         }, | ||||||
|  |       }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let data = Object.assign({}, driver.options.iscsi.lunSnapshotAttributes, { | ||||||
|  |       src_lun_uuid: lun.uuid, | ||||||
|  |       taken_by: "democratic-csi", | ||||||
|  |       description: name, //check
 | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     let response = await httpClient.CreateSnapshot(data); | ||||||
| 
 | 
 | ||||||
|     return { |     return { | ||||||
|       snapshot: { |       snapshot: { | ||||||
|  | @ -605,7 +667,7 @@ class ControllerSynologyDriver extends CsiBaseDriver { | ||||||
|          * is needed to create a volume from this snapshot. |          * is needed to create a volume from this snapshot. | ||||||
|          */ |          */ | ||||||
|         size_bytes: 0, |         size_bytes: 0, | ||||||
|         snapshot_id, |         snapshot_id: `/lun/${lun.lun_id}/${response.body.data.snapshot_uuid}`, | ||||||
|         source_volume_id: source_volume_id, |         source_volume_id: source_volume_id, | ||||||
|         //https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/timestamp.proto
 |         //https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/timestamp.proto
 | ||||||
|         creation_time: { |         creation_time: { | ||||||
|  | @ -624,12 +686,13 @@ class ControllerSynologyDriver extends CsiBaseDriver { | ||||||
|    * @param {*} call |    * @param {*} call | ||||||
|    */ |    */ | ||||||
|   async DeleteSnapshot(call) { |   async DeleteSnapshot(call) { | ||||||
|     throw new GrpcError( |     // throw new GrpcError(
 | ||||||
|       grpc.status.UNIMPLEMENTED, |     //   grpc.status.UNIMPLEMENTED,
 | ||||||
|       `operation not supported by driver` |     //   `operation not supported by driver`
 | ||||||
|     ); |     // );
 | ||||||
| 
 | 
 | ||||||
|     const driver = this; |     const driver = this; | ||||||
|  |     const httpClient = await driver.getHttpClient(); | ||||||
| 
 | 
 | ||||||
|     const snapshot_id = call.request.snapshot_id; |     const snapshot_id = call.request.snapshot_id; | ||||||
| 
 | 
 | ||||||
|  | @ -640,7 +703,19 @@ class ControllerSynologyDriver extends CsiBaseDriver { | ||||||
|       ); |       ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // TODO: delete snapshot here
 |     let parts = snapshot_id.split("/"); | ||||||
|  |     let lun_id = parts[2]; | ||||||
|  |     let snapshot_uuid = parts[3]; | ||||||
|  | 
 | ||||||
|  |     // TODO: delete snapshot
 | ||||||
|  |     let snapshot = await httpClient.GetSnapshotByLunIDAndSnapshotUUID( | ||||||
|  |       lun_id, | ||||||
|  |       snapshot_uuid | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     if (snapshot) { | ||||||
|  |       await httpClient.DeleteSnapshot(snapshot.uuid); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     return {}; |     return {}; | ||||||
|   } |   } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue