Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dashmate): a flag to keep data on reset #2026

Merged
merged 1 commit into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/dashmate/src/commands/reset.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ export default class ResetCommand extends ConfigBaseCommand {

static flags = {
...ConfigBaseCommand.flags,
hard: Flags.boolean({ char: 'h', description: 'reset config as well as data', default: false }),
hard: Flags.boolean({ char: 'h', description: 'reset config as well as services and data', default: false }),
force: Flags.boolean({ char: 'f', description: 'skip running services check', default: false }),
platform: Flags.boolean({ char: 'p', description: 'reset platform services and data only', default: false }),
verbose: Flags.boolean({ char: 'v', description: 'use verbose mode for output', default: false }),
'keep-data': Flags.boolean({ description: 'keep data', default: false }),
};

/**
Expand All @@ -30,6 +31,7 @@ export default class ResetCommand extends ConfigBaseCommand {
hard: isHardReset,
force: isForce,
platform: isPlatformOnlyReset,
'keep-data': keepData,
},
config,
resetNodeTask,
Expand Down Expand Up @@ -58,6 +60,7 @@ export default class ResetCommand extends ConfigBaseCommand {
isPlatformOnlyReset,
isForce,
isVerbose,
keepData,
});
} catch (e) {
throw new MuteOneLineError(e);
Expand Down
12 changes: 10 additions & 2 deletions packages/dashmate/src/docker/DockerCompose.js
Original file line number Diff line number Diff line change
Expand Up @@ -414,15 +414,23 @@ export default class DockerCompose {
* Down docker compose
*
* @param {Config} config
* @param {Object} [options]
* @param {Object} [options.removeVolumes=false]
* @return {Promise<void>}
*/
async down(config) {
async down(config, options = {}) {
await this.throwErrorIfNotInstalled();

const commandOptions = ['--remove-orphans'];

if (options.removeVolumes) {
commandOptions.push('-v');
}

try {
await dockerCompose.down({
...this.#createOptions(config),
commandOptions: ['-v', '--remove-orphans'],
commandOptions,
});
} catch (e) {
throw new DockerComposeError(e);
Expand Down
88 changes: 53 additions & 35 deletions packages/dashmate/src/listr/tasks/resetNodeTaskFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,57 +52,75 @@ export default function resetNodeTaskFactory(
{
title: 'Remove all services and associated data',
enabled: (ctx) => !ctx.isPlatformOnlyReset,
task: async () => dockerCompose.down(config),
task: async (ctx, task) => {
if (ctx.keepData) {
// eslint-disable-next-line no-param-reassign
task.title = 'Remove all services and keep associated data';
}

const options = {
removeVolumes: !ctx.keepData,
};

return dockerCompose.down(config, options);
},
},
{
title: 'Remove platform services and associated data',
enabled: (ctx) => ctx.isPlatformOnlyReset,
task: async () => {
task: async (ctx, task) => {
if (ctx.keepData) {
// eslint-disable-next-line no-param-reassign
task.title = 'Remove platform services and keep associated data';
}

await dockerCompose.rm(config, { profiles: ['platform'] });

// Remove volumes
const { COMPOSE_PROJECT_NAME: composeProjectName } = generateEnvs(config);
if (ctx.keepData) {
const { COMPOSE_PROJECT_NAME: composeProjectName } = generateEnvs(config);

const projectVolumeNames = await dockerCompose.getVolumeNames(
config,
{ profiles: ['platform'] },
);
const projectVolumeNames = await dockerCompose.getVolumeNames(
config,
{ profiles: ['platform'] },
);

await Promise.all(
projectVolumeNames
.map((volumeName) => `${composeProjectName}_${volumeName}`)
.map(async (volumeName) => {
const volume = await docker.getVolume(volumeName);
await Promise.all(
projectVolumeNames
.map((volumeName) => `${composeProjectName}_${volumeName}`)
.map(async (volumeName) => {
const volume = await docker.getVolume(volumeName);

let isRetry;
do {
isRetry = false;
let isRetry;
do {
isRetry = false;

try {
await volume.remove({ force: true });
} catch (e) {
// volume is in use
if (e.statusCode === 409) {
await wait(1000);
try {
await volume.remove({ force: true });
} catch (e) {
// volume is in use
if (e.statusCode === 409) {
await wait(1000);

// Remove containers
await dockerCompose.rm(config, { profiles: ['platform'] });
// Remove containers
await dockerCompose.rm(config, { profiles: ['platform'] });

isRetry = true;
isRetry = true;

continue;
}
continue;
}

// volume does not exist
if (e.statusCode === 404) {
break;
}
// volume does not exist
if (e.statusCode === 404) {
break;
}

throw e;
}
} while (isRetry);
}),
);
throw e;
}
} while (isRetry);
}),
);
}
},
},
{
Expand Down
Loading