Merge pull request #105 from huntermm18/next
synology snapshots, getcapacity, misc
This commit is contained in:
commit
5c27e3296d
|
|
@ -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,12 +525,35 @@ class ControllerSynologyDriver extends CsiBaseDriver {
|
||||||
* @param {*} call
|
* @param {*} call
|
||||||
*/
|
*/
|
||||||
async GetCapacity(call) {
|
async GetCapacity(call) {
|
||||||
|
// throw new GrpcError(
|
||||||
|
// grpc.status.UNIMPLEMENTED,
|
||||||
|
// `operation not supported by driver`
|
||||||
|
// );
|
||||||
|
|
||||||
|
const driver = this;
|
||||||
|
const httpClient = await driver.getHttpClient();
|
||||||
|
|
||||||
|
if (!driver.options.synology.location) {
|
||||||
throw new GrpcError(
|
throw new GrpcError(
|
||||||
grpc.status.UNIMPLEMENTED,
|
grpc.status.FAILED_PRECONDITION,
|
||||||
`operation not supported by driver`
|
`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 };
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* TODO: check capability to ensure not asking about block volumes
|
* TODO: check capability to ensure not asking about block volumes
|
||||||
|
|
@ -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