more performant proccess for removing all snapshots on a dataset

Signed-off-by: Travis Glenn Hansen <travisghansen@yahoo.com>
This commit is contained in:
Travis Glenn Hansen 2021-08-14 13:58:39 -06:00
parent 1a5b2e699a
commit 023f7e16b2
2 changed files with 55 additions and 29 deletions

View File

@ -1601,29 +1601,10 @@ class FreeNASApiDriver extends CsiBaseDriver {
}
}
async removeSnapshotsFromDatatset(datasetName, options = {}) {
// TODO: alter the logic here to not be n+1
// https://jira.ixsystems.com/browse/NAS-111708
const httpClient = await this.getHttpClient();
async removeSnapshotsFromDatatset(datasetName) {
const httpApiClient = await this.getTrueNASHttpApiClient();
let response;
let endpoint = `/pool/dataset/id/${encodeURIComponent(datasetName)}`;
response = await httpClient.get(endpoint, { "extra.snapshots": 1 });
//console.log(response);
if (response.statusCode == 404) {
return;
}
if (response.statusCode == 200) {
for (let snapshot of response.body.snapshots) {
await httpApiClient.SnapshotDelete(snapshot.name);
}
return;
}
throw new Error("unhandled statusCode: " + response.statusCode);
let job_id = await httpApiClient.DatasetDestroySnapshots(datasetName);
await httpApiClient.CoreWaitForJob(job_id, 30);
}
/**
@ -2224,9 +2205,7 @@ class FreeNASApiDriver extends CsiBaseDriver {
}
// remove snapshots from target
await this.removeSnapshotsFromDatatset(datasetName, {
force: true,
});
await this.removeSnapshotsFromDatatset(datasetName);
} else {
try {
response = await httpApiClient.CloneCreate(
@ -2377,9 +2356,7 @@ class FreeNASApiDriver extends CsiBaseDriver {
);
// remove snapshots from target
await this.removeSnapshotsFromDatatset(datasetName, {
force: true,
});
await this.removeSnapshotsFromDatatset(datasetName);
// remove snapshot from source
await httpApiClient.SnapshotDelete(fullSnapshotName, {
@ -2707,7 +2684,6 @@ class FreeNASApiDriver extends CsiBaseDriver {
* @param {*} call
*/
async ControllerExpandVolume(call) {
// TODO: https://jira.ixsystems.com/browse/NAS-111707
const driver = this;
const driverZfsResourceType = this.getDriverZfsResourceType();
const httpApiClient = await this.getTrueNASHttpApiClient();

View File

@ -1,3 +1,4 @@
const { sleep } = require("../../../utils/general");
const { Zetabyte } = require("../../../utils/zfs");
// used for in-memory cache of the version info
@ -491,6 +492,30 @@ class Api {
throw new Error(JSON.stringify(response.body));
}
async DatasetDestroySnapshots(datasetName, data = {}) {
const httpClient = await this.getHttpClient(false);
let response;
let endpoint;
data.name = datasetName;
endpoint = "/pool/dataset/destroy_snapshots";
response = await httpClient.post(endpoint, data);
if (response.statusCode == 200) {
return response.body;
}
if (
response.statusCode == 422 &&
JSON.stringify(response.body).includes("already exists")
) {
return;
}
throw new Error(JSON.stringify(response.body));
}
async SnapshotSet(snapshotName, properties) {
const httpClient = await this.getHttpClient(false);
let response;
@ -654,6 +679,31 @@ class Api {
throw new Error(JSON.stringify(response.body));
}
async CoreWaitForJob(job_id, timeout = 0) {
if (!job_id) {
throw new Error("invalid job_id");
}
const startTime = Date.now() / 1000;
let currentTime;
let job;
// wait for job to finish
while (!job || !["SUCCESS", "ABORTED", "FAILED"].includes(job.state)) {
job = await this.CoreGetJobs({ id: job_id });
job = job[0];
await sleep(3000);
currentTime = Date.now() / 1000;
if (timeout > 0 && currentTime > startTime + timeout) {
throw new Error("timeout waiting for job to complete");
}
}
return job;
}
async CoreGetJobs(data) {
const httpClient = await this.getHttpClient(false);