UNPKG

@controlplane/cli

Version:

Control Plane Corporation CLI

1,022 lines 40.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RestoreSnapshot = exports.DeleteSnapshot = exports.GetSnapshot = exports.CreateSnapshot = exports.SnapshotCmd = exports.DeleteVolume = exports.GetVolume = exports.VolumeCmd = exports.filterVolumes = exports.ExpandVolumeSet = exports.GetVolumeSet = exports.Create = exports.VolumeSetCmd = exports.volumeSnapshotKind = exports.volumeNewSizeKind = exports.volumeKind = void 0; const options_1 = require("./options"); const resolver_1 = require("./resolver"); const command_1 = require("../cli/command"); const resultFetcher_1 = require("../rest/resultFetcher"); const functions_1 = require("../util/functions"); const generic_1 = require("./generic"); const objects_1 = require("../util/objects"); const logger_1 = require("../util/logger"); exports.volumeKind = 'volume'; exports.volumeNewSizeKind = 'volumeNewSize'; exports.volumeSnapshotKind = 'volumeSnapshot'; const performance_classes = ['general-purpose-ssd', 'high-throughput-ssd', 'shared']; const file_system_types = ['xfs', 'ext4', "shared"]; const volumeset_defaults = { initialCapacity: 10, performanceClass: performance_classes[0], fileSystemType: file_system_types[0], autoscaling: { maxCapacity: 10, minFreePercentage: 1, scalingFactor: 1.1, }, snapshots: { createFinalSnapshot: true, retentionDuration: '7d', }, }; class VolumeSetCmd extends command_1.Command { constructor() { super(...arguments); this.command = 'volumeset'; this.describe = 'Manage a persistent volumeset within a global virtual cloud'; } builder(yargs) { const schema = { rels: ['gvc'], }; const resolver = (0, resolver_1.kindResolver)('volumeset'); const opts = [options_1.withGvcOptions, options_1.withStandardOptions]; const commandName = 'volume set'; const commandNamePlural = 'volume sets'; const commandNameA = 'a volume set'; return (yargs .demandCommand() .version(false) .help() // generic .command(new generic_1.Edit(commandName, resolver, ...opts).toYargs()) .command(new generic_1.Patch(commandName, resolver, ...opts).toYargs()) .command(new generic_1.Query(commandNamePlural, resolver, schema, ...opts).toYargs()) .command(new generic_1.Delete(commandNamePlural, resolver, ...opts).toYargs()) .command(new generic_1.Eventlog(commandName, resolver, ...opts).toYargs()) .command(new generic_1.Tag(commandNamePlural, resolver, ...opts).toYargs()) .command(new generic_1.ListPermissions(commandNameA, resolver, ...opts).toYargs()) .command(new generic_1.ViewAccessReport(commandName, resolver, ...opts).toYargs()) .command(new generic_1.Update(commandName, resolver, [ { path: 'description', }, { path: 'tags.<key>', }, { path: 'spec.initialCapacity', type: 'number', }, { path: 'spec.snapshots.createFinalSnapshot', type: 'boolean', }, { path: 'spec.snapshots.retentionDuration', }, { path: 'spec.snapshots.schedule', }, { path: 'spec.autoscaling.maxCapacity', type: 'number', }, { path: 'spec.autoscaling.minFreePercentage', type: 'number', }, { path: 'spec.autoscaling.scalingFactor', type: 'number', }, ], ...opts).toYargs()) // specific .command(new GetVolumeSet(resolver, ...opts).toYargs()) .command(new Create(resolver).toYargs()) .command(new ExpandVolumeSet(resolver, ...opts).toYargs()) .command(new SnapshotCmd(resolver, ...opts).toYargs()) .command(new VolumeCmd(resolver, ...opts).toYargs())); } handle() { } } exports.VolumeSetCmd = VolumeSetCmd; class Create extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'create'; this.describe = 'Create a new volume set'; } builder(yargs) { return (0, functions_1.pipe)( // (yargs) => { return yargs.options({ name: { describe: 'Name of the new volume set', requiresArg: true, demandOption: true, }, description: { alias: 'desc', describe: 'Optional description, defaults to the name if not set', }, 'performance-class': { describe: 'Performance class of the volume set', default: volumeset_defaults.performanceClass, choices: performance_classes, requiresArg: true, }, 'file-system-type': { describe: 'File system', default: volumeset_defaults.fileSystemType, choices: file_system_types, requiresArg: true, }, 'initial-capacity': { describe: 'Initial capacity in GB', default: volumeset_defaults.initialCapacity, requiresArg: true, number: true, }, 'enable-autoscaling': { describe: 'Enable Autoscaling', default: false, boolean: true, }, 'max-capacity': { describe: 'Max capacity in GB, autoscaling needs to be enabled: --enable-autoscaling', default: volumeset_defaults.autoscaling.maxCapacity, requiresArg: true, number: true, }, 'min-free-percentage': { describe: 'Min free percentage, autoscaling needs to be enabled: --enable-autoscaling', default: volumeset_defaults.autoscaling.minFreePercentage, requiresArg: true, number: true, }, 'scaling-factor': { describe: 'Scaling factor, autoscaling needs to be enabled: --enable-autoscaling', default: volumeset_defaults.autoscaling.scalingFactor, requiresArg: true, number: true, }, 'create-final-snapshot': { describe: 'Create Final Snapshot', default: volumeset_defaults.snapshots.createFinalSnapshot, boolean: true, }, 'retention-duration': { describe: 'Retention Duration', requiresArg: true, default: volumeset_defaults.snapshots.retentionDuration, }, 'schedule': { describe: 'Snapshot Schedule (UTC)', requiresArg: true, }, }); }, generic_1.withTagOptions, options_1.withAllOptions)(yargs); } async handle(args) { const req = toCreateVolumesetRequest(args); const link = this.resolve.parentLink(this.session.context); const body = await this.client.create(link, req); this.session.outFormat(body); } } exports.Create = Create; class GetVolumeSet extends generic_1.Get { constructor(resolve, ...funcs) { super('volume sets', resolve, ...funcs); this.describe = 'Retrieve one or more referenced volume sets'; } async list(args) { let link; if (args.allGvcs) { link = this.resolve.homeLink(this.session.context); } else { link = this.resolve.parentLink(this.session.context); } const body = await this.client.get(link); await (0, resultFetcher_1.fetchPages)(this.client, this.session.format.max, body); this.session.outFormat(body); } builder(yargs) { return (0, functions_1.pipe)(super.builder.bind(this), (yargs) => { return yargs.options({ 'all-gvcs': { boolean: true, describe: 'Show volume sets from all the global virtual clouds within the current or overridden organization', }, }); })(yargs); } } exports.GetVolumeSet = GetVolumeSet; function withNewSizeOption(yargs) { return yargs.options({ 'new-size': { type: 'number', requiresArg: true, demandOption: true, describe: 'The new storage capacity of the volume in GiB', }, }); } class ExpandVolumeSet extends command_1.Command { constructor(resolve, ...argumentFuncs) { super(); // Public Properties // this.command = 'expand <ref>'; this.describe = 'Expand the size of one or more volumes in the referenced volume set'; this.resolve = resolve; this.argumentsPipe = (0, functions_1.pipe)( // generic_1.withSingleRef, withNewSizeOption, generic_1.withMultipleLocationsOption, withMultipleVolumeIndexesOption, ...argumentFuncs); } builder(yargs) { return this.argumentsPipe(yargs); } async handle(args) { // Initialize const volumeSetLink = this.resolve.resourceLink(args.ref, this.session.context); const volumeSet = await this.client.get(volumeSetLink); const failures = []; const accumulator = { kind: 'list', itemKind: exports.volumeNewSizeKind, items: [], links: [], }; // Filter volumes let volumes; try { volumes = filterVolumes(volumeSet, args); } catch (e) { this.session.abort({ message: e.message }); } for (const volume of volumes) { try { const command = { type: 'expandVolume', spec: { location: volume.location, volumeIndex: volume.index, newStorageCapacity: args.newSize, }, }; await this.client.axios.post(`${volumeSetLink}/-command`, command); const volumeNewSize = { newSize: `${args.newSize}GiB`, location: volume.location, volumeIndex: volume.index, name: volumeSet.name, stage: 'initiating', created: new Date(), lastModified: new Date(), }; accumulator.items.push(volumeNewSize); } catch (e) { failures.push(e); } } await this.session.outFormat(accumulator); if (failures.length > 0) { this.session.abort({ error: failures }); } } } exports.ExpandVolumeSet = ExpandVolumeSet; function toCreateVolumesetRequest(args) { var _a; const req = { name: args.name, description: (_a = args.description) !== null && _a !== void 0 ? _a : args.name, tags: (0, generic_1.fromTagOptions)(args), spec: {}, }; req.spec = { initialCapacity: args.initialCapacity, performanceClass: args.performanceClass, fileSystemType: args.fileSystemType, snapshots: { createFinalSnapshot: args.createFinalSnapshot, retentionDuration: args.retentionDuration, schedule: args.schedule, }, }; if (args.enableAutoscaling) { req.spec.autoscaling = { maxCapacity: args.maxCapacity, minFreePercentage: args.minFreePercentage, scalingFactor: args.scalingFactor, }; } return req; } function filterVolumes(volumeSet, args) { var _a, _b, _c; if (!volumeSet.status || !volumeSet.status.locations || volumeSet.status.locations.length === 0) { throw new Error(`Volume Set '${volumeSet.name}' has no locations. You will need to enable a location in the global virtual cloud`); } if (args.snapshotName) { args.snapshotName = (0, objects_1.toArray)(args.snapshotName); } if (args.location) { args.location = (0, objects_1.toArray)(args.location); const invalidLocations = []; const locationsMap = new Set(); for (const statusLocation of volumeSet.status.locations) { locationsMap.add(statusLocation.name); } for (const location of args.location) { if (!locationsMap.has(location)) { invalidLocations.push(location); } } if (invalidLocations.length > 0) { throw new Error(`Volume Set '${volumeSet.name}' has no locations named '${invalidLocations.join(', ')}'`); } } if (args.volumeIndex !== undefined) { args.volumeIndex = (0, objects_1.toArray)(args.volumeIndex); } const volumes = []; for (const statusLocation of volumeSet.status.locations) { if (args.location && !args.location.includes(statusLocation.name)) { continue; } for (const volume of (_a = statusLocation.volumes) !== null && _a !== void 0 ? _a : []) { if (args.volumeIndex !== undefined && !args.volumeIndex.includes(volume.index)) { continue; } let snapshots = (_b = volume.volumeSnapshots) !== null && _b !== void 0 ? _b : []; if (args.snapshotName) { snapshots = snapshots.filter((snapshot) => args.snapshotName.includes(snapshot.name)); } volumes.push({ snapshots: snapshots, location: statusLocation.name, index: volume.index, lifecycle: (_c = volume.lifecycle) !== null && _c !== void 0 ? _c : '', }); } } return volumes; } exports.filterVolumes = filterVolumes; function getSnapshotUniqueIdentifier(snapshot) { return `${snapshot.location}@${snapshot.volumeIndex}@${snapshot.name}`; } function getVolumeUniqueIdentifier(volume) { return `${volume.location}@${volume.volumeIndex}`; } // Volumes // class VolumeCmd extends command_1.Command { constructor(resolve, ...argumentFuncs) { super(); this.resolve = resolve; // Public Properties // this.command = 'volume'; this.describe = 'Manage volume set volumes'; this.argumentFuncs = argumentFuncs; } builder(yargs) { const resolver = (0, resolver_1.kindResolver)('volumeset'); return (yargs .demandCommand() .version(false) .help() // specific .command(new GetVolume(resolver, ...this.argumentFuncs).toYargs()) .command(new DeleteVolume(resolver, ...this.argumentFuncs).toYargs())); } handle() { } } exports.VolumeCmd = VolumeCmd; class GetVolume extends command_1.Command { constructor(resolve, ...argumentFuncs) { super(); // Public Properties // this.command = 'get <ref>'; this.describe = 'Retrieve one or more volumes by a volume set reference'; this.resolve = resolve; this.argumentsPipe = (0, functions_1.pipe)( // generic_1.withSingleRef, generic_1.withMultipleLocationsOption, withMultipleVolumeIndexesOption, ...argumentFuncs); } builder(yargs) { return this.argumentsPipe(yargs); } async handle(args) { // Initialize const commandVolumes = new Map(); const volumeSetLink = this.resolve.resourceLink(args.ref, this.session.context); const volumeSet = await this.client.get(volumeSetLink); const accumulator = { kind: 'list', itemKind: exports.volumeKind, items: [], links: [], }; // Filter volumes let volumes; try { volumes = filterVolumes(volumeSet, args); } catch (e) { this.session.abort({ message: e.message }); } // Read volumes from volume set for (const volume of volumes) { const volumeResource = { location: volume.location, volumeIndex: volume.index, stage: volume.lifecycle, }; accumulator.items.push(volumeResource); } // Attempt to discover volumes being deleted through commands try { const commands = await this.client.get(`${volumeSetLink}/-command`); // Fetch all commands await (0, resultFetcher_1.fetchPages)(this.client, this.session.format.max, commands); for (const _command of commands.items) { const command = _command; if ( // These properties must be defined !command.spec || !command.created || !command.lastModified || !command.lifecycleStage || // Only delete volume commands is what we need command.type !== 'deleteVolume' || command.lifecycleStage !== 'running' || // Filter by locationed if requested (args.location && !args.location.includes(command.spec.location))) { continue; } const volumeResource = { location: command.spec.location, volumeIndex: command.spec.volumeIndex, stage: 'deleting', lastModified: command.lastModified, }; // Uniquely identify volume const volumeUniqueIdentifier = getVolumeUniqueIdentifier(volumeResource); // Manage already added volumes if (commandVolumes.has(volumeUniqueIdentifier)) { const existingVolume = commandVolumes.get(volumeUniqueIdentifier); // Update based on creation time if (command.lastModified > existingVolume.lastModified) { existingVolume.stage = volumeResource.stage; } continue; } commandVolumes.set(volumeUniqueIdentifier, volumeResource); } } catch (e) { logger_1.logger.error(e); } // Process and capture last volume stage for (const _volumeResource of accumulator.items) { const volumeResource = _volumeResource; const volumeUniqueIdentifier = getVolumeUniqueIdentifier(volumeResource); // Process volume stage if (commandVolumes.has(volumeUniqueIdentifier)) { const commandVolume = commandVolumes.get(volumeUniqueIdentifier); volumeResource.stage = commandVolume.stage; // Remove command volume because it already served its purpose commandVolumes.delete(volumeUniqueIdentifier); } } // Add remaining volumes that were not processed and are running commandVolumes.forEach((volume) => { if (volume.stage === 'completed') { return; } accumulator.items.push(volume); }); if (this.session.format.max) { accumulator.items = accumulator.items.slice(0, this.session.format.max); } await this.session.outFormat(accumulator); } } exports.GetVolume = GetVolume; class DeleteVolume extends command_1.Command { constructor(resolve, ...argumentFuncs) { super(); // Public Properties // this.command = 'delete <ref>'; this.describe = 'Delete one or more volumes by a volume set reference'; this.resolve = resolve; this.argumentsPipe = (0, functions_1.pipe)( // generic_1.withSingleRef, generic_1.withMultipleLocationsOption, withMultipleVolumeIndexesOption, ...argumentFuncs); } builder(yargs) { return this.argumentsPipe(yargs); } async handle(args) { // Initialize const volumeSetLink = this.resolve.resourceLink(args.ref, this.session.context); const volumeSet = await this.client.get(volumeSetLink); const failures = []; const accumulator = { kind: 'list', itemKind: exports.volumeKind, items: [], links: [], }; // Filter volumes let volumes; try { volumes = filterVolumes(volumeSet, args); } catch (e) { this.session.abort({ message: e.message }); } for (const volume of volumes) { try { const command = { type: 'deleteVolume', spec: { location: volume.location, volumeIndex: volume.index, }, }; const response = await this.client.axios.post(`${volumeSetLink}/-command`, command); if (response.status === 201) { const volumeResource = { location: volume.location, volumeIndex: volume.index, stage: 'deleting', }; accumulator.items.push(volumeResource); } else { throw new Error(`Unexpected status code ${response.status} while deleting the volume at index ${volume.index} in location ${volume.location}`); } } catch (e) { failures.push(e); } } await this.session.outFormat(accumulator); if (failures.length > 0) { this.session.abort({ error: failures }); } } } exports.DeleteVolume = DeleteVolume; // Snapshots // class SnapshotCmd extends command_1.Command { constructor(resolve, ...argumentFuncs) { super(); this.resolve = resolve; // Public Properties // this.command = 'snapshot'; this.describe = 'Manage volume set snapshots'; this.argumentFuncs = argumentFuncs; } builder(yargs) { const resolver = (0, resolver_1.kindResolver)('volumeset'); return (yargs .demandCommand() .version(false) .help() // specific .command(new CreateSnapshot(resolver, ...this.argumentFuncs).toYargs()) .command(new GetSnapshot(resolver, ...this.argumentFuncs).toYargs()) .command(new DeleteSnapshot(resolver, ...this.argumentFuncs).toYargs()) .command(new RestoreSnapshot(resolver, ...this.argumentFuncs).toYargs())); } handle() { } } exports.SnapshotCmd = SnapshotCmd; function withSingleSnapshotNameOption(isRequired) { return function (yargs) { return yargs.options({ 'snapshot-name': { type: 'string', demandOption: isRequired, describe: 'Name of the snapshot', }, }); }; } function withSingleVolumeIndexOption(isRequired) { return function (yargs) { return yargs.options({ 'volume-index': { type: 'number', demandOption: isRequired, describe: 'The index of the volume of which a snapshot should be taken', }, }); }; } function withMultipleSnapshotNamesOption(isRequired) { return function (yargs) { return yargs.options({ 'snapshot-name': { type: 'string', multiple: true, demandOption: isRequired, describe: 'Name of the snapshot', }, }); }; } function withMultipleVolumeIndexesOption(yargs) { return yargs.options({ 'volume-index': { type: 'number', multiple: true, describe: 'The index of the volume of which a snapshot should be taken', }, }); } class CreateSnapshot extends command_1.Command { constructor(resolve, ...argumentFuncs) { super(); // Public Properties // this.command = 'create <ref>'; this.describe = 'Create one or more snapshots by a volume set reference'; this.resolve = resolve; this.argumentsPipe = (0, functions_1.pipe)( // generic_1.withSingleRef, withMultipleSnapshotNamesOption(true), generic_1.withMultipleLocationsOption, withMultipleVolumeIndexesOption, generic_1.withTagOptions, ...argumentFuncs); } builder(yargs) { return this.argumentsPipe(yargs); } async handle(args) { // Initialize const volumeSetLink = this.resolve.resourceLink(args.ref, this.session.context); const volumeSet = await this.client.get(volumeSetLink); const failures = []; const accumulator = { kind: 'list', itemKind: exports.volumeSnapshotKind, items: [], links: [], }; // Filter volumes let volumes; try { volumes = filterVolumes(volumeSet, args); } catch (e) { this.session.abort({ message: e.message }); } for (const volume of volumes) { for (const snapshotName of args.snapshotName) { const command = { type: 'createVolumeSnapshot', spec: { location: volume.location, volumeIndex: volume.index, snapshotName: snapshotName, snapshotTags: (0, generic_1.tagsToArray)(args), }, }; try { const response = await this.client.axios.post(`${volumeSetLink}/-command`, command); if (response.status === 201) { const snapshot = { location: volume.location, volumeIndex: volume.index, name: snapshotName, tags: (0, generic_1.fromTagOptions)(args), stage: 'initiating', lastModified: new Date(), }; accumulator.items.push(snapshot); } else { throw new Error(`Unexpected status code ${response.status} while creating snapshot ${snapshotName} for volume index ${volume.index} in location ${volume.location}`); } } catch (e) { failures.push(e); } } } await this.session.outFormat(accumulator); if (failures.length > 0) { this.session.abort({ error: failures }); } } } exports.CreateSnapshot = CreateSnapshot; class GetSnapshot extends command_1.Command { constructor(resolve, ...argumentFuncs) { super(); // Public Properties // this.command = 'get <ref>'; this.describe = 'Retrieve one or more snapshots by a volume set reference'; this.resolve = resolve; this.argumentsPipe = (0, functions_1.pipe)( // generic_1.withSingleRef, withMultipleSnapshotNamesOption(false), generic_1.withMultipleLocationsOption, withMultipleVolumeIndexesOption, ...argumentFuncs); } builder(yargs) { return this.argumentsPipe(yargs); } async handle(args) { var _a, _b; // Initialize const commandSnapshots = new Map(); const volumeSetLink = this.resolve.resourceLink(args.ref, this.session.context); const volumeSet = await this.client.get(volumeSetLink); const accumulator = { kind: 'list', itemKind: exports.volumeSnapshotKind, items: [], links: [], }; // Filter volumes let volumes; try { volumes = filterVolumes(volumeSet, args); } catch (e) { this.session.abort({ message: e.message }); } // Read snapshots from volume set volumes for (const volume of volumes) { for (const snapshot of volume.snapshots) { const snapshotResource = { location: volume.location, volumeIndex: volume.index, name: snapshot.name, tags: (0, generic_1.arrayToTags)((_a = snapshot.tags) !== null && _a !== void 0 ? _a : []), stage: 'completed', created: snapshot.created, lastModified: snapshot.created, }; accumulator.items.push(snapshotResource); } } // Attempt to read snapshots from commands to monitor stages try { const commands = await this.client.get(`${volumeSetLink}/-command`); // Fetch all commands await (0, resultFetcher_1.fetchPages)(this.client, this.session.format.max, commands); for (const _command of commands.items) { const command = _command; if ( // These properties must be defined !command.spec || !command.created || !command.lastModified || !command.lifecycleStage || // Filter by snapshot name if requested (args.snapshotName && !args.snapshotName.includes(command.spec.snapshotName)) || // Filter by locationed if requested (args.location && !args.location.includes(command.spec.location))) { continue; } let stage = command.lifecycleStage; if (stage === 'running') { switch (command.type) { case 'createVolumeSnapshot': stage = 'initiating'; break; case 'deleteVolumeSnapshot': stage = 'deleting'; break; case 'restoreVolume': stage = 'restoring'; break; } } else if (stage === 'failed') { switch (command.type) { case 'deleteVolumeSnapshot': stage = 'delete failed'; break; case 'restoreVolume': stage = 'restore failed'; break; } } const snapshot = { location: command.spec.location, volumeIndex: command.spec.volumeIndex, name: command.spec.snapshotName, tags: (0, generic_1.arrayToTags)((_b = command.spec.snapshotTags) !== null && _b !== void 0 ? _b : []), stage, lastModified: command.lastModified, }; // Uniquely identify snapshot const snapshotUniqueIdentifier = getSnapshotUniqueIdentifier(snapshot); // Manage already added snapshots if (commandSnapshots.has(snapshotUniqueIdentifier)) { const existingSnapshot = commandSnapshots.get(snapshotUniqueIdentifier); // Update based on creation time if (command.lastModified > existingSnapshot.lastModified) { existingSnapshot.stage = snapshot.stage; } continue; } commandSnapshots.set(snapshotUniqueIdentifier, snapshot); } } catch (e) { logger_1.logger.error(e); } // Process and capture last snapshot stage for (const _snapshotResource of accumulator.items) { const snapshotResource = _snapshotResource; const snapshotUniqueIdentifier = getSnapshotUniqueIdentifier(snapshotResource); // Process snapshot stage if (commandSnapshots.has(snapshotUniqueIdentifier)) { const commandSnapshot = commandSnapshots.get(snapshotUniqueIdentifier); snapshotResource.stage = commandSnapshot.stage; // Remove command snapshot because it already served its purpose commandSnapshots.delete(snapshotUniqueIdentifier); } } // Add remaining snapshots that were not processed and are running commandSnapshots.forEach((snapshot) => { if (snapshot.stage === 'completed') { return; } accumulator.items.push(snapshot); }); if (accumulator.items.length > 0) { // Sort snapshots accumulator.items = accumulator.items.sort((a, b) => { if (a.location !== b.location) { return a.location.localeCompare(b.location); } if (a.volumeIndex !== b.volumeIndex) { return a.volumeIndex - b.volumeIndex; } return a.name.localeCompare(b.name); }); } if (this.session.format.max) { accumulator.items = accumulator.items.slice(0, this.session.format.max); } await this.session.outFormat(accumulator); } } exports.GetSnapshot = GetSnapshot; class DeleteSnapshot extends command_1.Command { constructor(resolve, ...argumentFuncs) { super(); // Public Properties // this.command = 'delete <ref>'; this.describe = 'Delete one or more snapshots by a volume set reference'; this.resolve = resolve; this.argumentsPipe = (0, functions_1.pipe)( // generic_1.withSingleRef, withMultipleSnapshotNamesOption(true), generic_1.withMultipleLocationsOption, withMultipleVolumeIndexesOption, ...argumentFuncs); } builder(yargs) { return this.argumentsPipe(yargs); } async handle(args) { var _a; // Initialize const volumeSetLink = this.resolve.resourceLink(args.ref, this.session.context); const volumeSet = await this.client.get(volumeSetLink); const failures = []; const accumulator = { kind: 'list', itemKind: exports.volumeSnapshotKind, items: [], links: [], }; // Filter volumes let volumes; try { volumes = filterVolumes(volumeSet, args); } catch (e) { this.session.abort({ message: e.message }); } for (const volume of volumes) { for (const snapshot of volume.snapshots) { try { const command = { type: 'deleteVolumeSnapshot', spec: { location: volume.location, volumeIndex: volume.index, snapshotName: snapshot.name, }, }; const response = await this.client.axios.post(`${volumeSetLink}/-command`, command); if (response.status === 201) { const snapshotResource = { location: volume.location, volumeIndex: volume.index, name: snapshot.name, tags: (0, generic_1.arrayToTags)((_a = snapshot.tags) !== null && _a !== void 0 ? _a : []), stage: 'deleting', created: snapshot.created, lastModified: snapshot.created, }; accumulator.items.push(snapshotResource); } else { throw new Error(`Unexpected status code ${response.status} while deleting snapshot ${snapshot.name} for volume index ${volume.index} in location ${volume.location}`); } } catch (e) { failures.push(e); } } } await this.session.outFormat(accumulator); if (failures.length > 0) { this.session.abort({ error: failures }); } } } exports.DeleteSnapshot = DeleteSnapshot; class RestoreSnapshot extends command_1.Command { constructor(resolve, ...argumentFuncs) { super(); // Public Properties // this.command = 'restore <ref>'; this.describe = 'Restore a snapshot to a volume'; this.resolve = resolve; this.argumentsPipe = (0, functions_1.pipe)( // generic_1.withSingleRef, withSingleSnapshotNameOption(true), (0, generic_1.withSingleLocationOption)(true), withSingleVolumeIndexOption(true), ...argumentFuncs); } builder(yargs) { return this.argumentsPipe(yargs); } async handle(args) { // Initialize const volumeSetLink = this.resolve.resourceLink(args.ref, this.session.context); const volumeSet = await this.client.get(volumeSetLink); const failures = []; const accumulator = { kind: 'list', itemKind: exports.volumeSnapshotKind, items: [], links: [], }; // Filter volumes let volumes; try { volumes = filterVolumes(volumeSet, args); } catch (e) { this.session.abort({ message: e.message }); } for (const volume of volumes) { for (const snapshot of volume.snapshots) { try { const command = { type: 'restoreVolume', spec: { location: volume.location, volumeIndex: volume.index, snapshotName: snapshot.name, }, }; const response = await this.client.axios.post(`${volumeSetLink}/-command`, command); if (response.status === 201) { const snapshotResource = { location: volume.location, volumeIndex: volume.index, name: snapshot.name, tags: {}, stage: 'restoring', created: snapshot.created, lastModified: snapshot.created, }; accumulator.items.push(snapshotResource); } else { throw new Error(`Unexpected status code ${response.status} while restoring snapshot ${snapshot.name} for volume index ${volume.index} in location ${volume.location}`); } } catch (e) { failures.push(e); } } } await this.session.outFormat(accumulator); if (failures.length > 0) { this.session.abort({ error: failures }); } } } exports.RestoreSnapshot = RestoreSnapshot; //# sourceMappingURL=volumeset.js.map