fix: Make the backup cleanup the other files that are not used.

This commit is contained in:
BluJ
2023-02-23 14:58:02 -07:00
parent 7530f0b2ac
commit 51580a43bb
10 changed files with 187 additions and 16 deletions

View File

@@ -33,7 +33,7 @@ type BackupSet = {
* srcVolume: 'main', srcPath:'smallData/', dstPath: 'main/smallData/', dstVolume: : Backups.BACKUP
* }, {
* srcVolume: 'main', srcPath:'bigData/', dstPath: 'main/bigData/', dstVolume: : Backups.BACKUP, options: {exclude:['bigData/excludeThis']}}
* ).build()
* ).build()q
* ```
*/
export class Backups {
@@ -84,7 +84,35 @@ export class Backups {
return this;
}
build() {
const createBackup: T.ExpectedExports.createBackup = async (effects) => {
const createBackup: T.ExpectedExports.createBackup = async (
{ effects },
) => {
const previousItems = (await effects.readDir({
volumeId: Backups.BACKUP,
path: ".",
}).catch(() => [])).map((x) => `${x}`);
const backupPaths = this.backupSet.filter((x) =>
x.dstVolume === Backups.BACKUP
).map((x) => x.dstPath).map((x) => x.replace(/\.\/([^]*)\//, "$1"));
const filteredItems = previousItems.filter((x) =>
backupPaths.indexOf(x) === -1
);
for (
const itemToRemove of filteredItems
) {
effects.error(`Trying to remove ${itemToRemove}`);
await effects.removeDir({
volumeId: Backups.BACKUP,
path: itemToRemove,
}).catch(() =>
effects.removeFile({
volumeId: Backups.BACKUP,
path: itemToRemove,
})
).catch(() => {
effects.warn(`Failed to remove ${itemToRemove} from backup volume`);
});
}
for (const item of this.backupSet) {
if (notEmptyPath(item.dstPath)) {
await effects.createDir({
@@ -102,7 +130,9 @@ export class Backups {
}
return ok;
};
const restoreBackup: T.ExpectedExports.restoreBackup = async (effects) => {
const restoreBackup: T.ExpectedExports.restoreBackup = async (
{ effects },
) => {
for (const item of this.backupSet) {
if (notEmptyPath(item.srcPath)) {
await effects.createDir({

View File

@@ -1,7 +1,7 @@
import { Config } from "../config_builder/config.ts";
import { YAML } from "../dependencies.ts";
import { matches } from "../dependencies.ts";
import { ExpectedExports } from "../types.ts";
import { LegacyExpectedExports as ExpectedExports } from "../types.ts";
import { ConfigSpec } from "../types/config-types.ts";
import { TypeFromProps, typeFromProps } from "../utils/propertiesMatcher.ts";

View File

@@ -1,5 +1,7 @@
import { getConfig, setConfig } from "./mod.ts";
import * as T from "../types.ts";
import { LegacyExpectedExports as ExpectedExports } from "../types.ts";
import * as M from "../migrations.ts";
import * as util from "../util.ts";
import { EmVer } from "../emver-lite/mod.ts";
@@ -116,7 +118,7 @@ export async function initNoRepeat<versions extends string>(
export function fromMapping<versions extends string>(
migrations: M.MigrationMapping<versions>,
currentVersion: string,
): T.ExpectedExports.migration {
): ExpectedExports.migration {
const inner = M.fromMapping(migrations, currentVersion);
return async (effects: T.Effects, version: string, direction?: unknown) => {
await initNoRepeat(

View File

@@ -1,4 +1,4 @@
export { properties } from "./properties.ts";
export { noPropertiesFound, properties, propertiesv2 } from "./properties.ts";
export { setConfig } from "./setConfig.ts";
export { getConfig, getConfigAndMatcher } from "./getConfig.ts";
export * as migrations from "./migrations.ts";

View File

@@ -1,10 +1,16 @@
import { YAML } from "../dependencies.ts";
import { exists } from "../util.ts";
import { Effects, ExpectedExports, Properties, ResultType } from "../types.ts";
import {
Effects,
ExpectedExports,
LegacyExpectedExports,
Properties,
ResultType,
} from "../types.ts";
// deno-lint-ignore no-explicit-any
const asResult = (result: any) => ({ result: result as Properties });
const noPropertiesFound: ResultType<Properties> = {
export const noPropertiesFound: ResultType<Properties> = {
result: {
version: 2,
data: {
@@ -26,7 +32,7 @@ const noPropertiesFound: ResultType<Properties> = {
* @param effects
* @returns
*/
export const properties: ExpectedExports.properties = async (
export const properties: LegacyExpectedExports.properties = async (
effects: Effects,
) => {
if (
@@ -40,3 +46,24 @@ export const properties: ExpectedExports.properties = async (
volumeId: "main",
}).then(YAML.parse).then(asResult);
};
/**
* Default will pull from a file (start9/stats.yaml) expected to be made on the main volume
* Assumption: start9/stats.yaml is created by some process
* Throws: stats.yaml isn't yaml
* @param effects
* @returns
*/
export const propertiesv2: ExpectedExports.properties = async (
{ effects },
) => {
if (
await exists(effects, { path: "start9/stats.yaml", volumeId: "main" }) ===
false
) {
return noPropertiesFound;
}
return await effects.readFile({
path: "start9/stats.yaml",
volumeId: "main",
}).then(YAML.parse).then(asResult);
};

View File

@@ -1,5 +1,9 @@
import { YAML } from "../dependencies.ts";
import { DependsOn, Effects, ExpectedExports } from "../types.ts";
import {
DependsOn,
Effects,
LegacyExpectedExports as ExpectedExports,
} from "../types.ts";
import { okOf } from "../util.ts";
/**

View File

@@ -15,7 +15,7 @@ export function setupConfigExports<A extends ConfigSpec>(options: {
}) {
const validator = options.spec.validator();
return {
setConfig: (async (effects: Effects, config: unknown) => {
setConfig: (async ({ effects, input: config }) => {
if (!validator.test(config)) {
await effects.error(String(validator.errorMessage(config)));
return { error: "Set config type error for config" };
@@ -26,7 +26,7 @@ export function setupConfigExports<A extends ConfigSpec>(options: {
"depends-on": options.dependsOn,
});
}) as ExpectedExports.setConfig,
getConfig: (async (effects: Effects) => {
getConfig: (async ({ effects }) => {
return okOf({
spec: options.spec.build(),
config: nullIfEmpty(await options.read(effects)),

View File

@@ -1,6 +1,36 @@
import { types as T } from "./mod.ts";
import { EmVer } from "./emver-lite/mod.ts";
import { matches } from "./dependencies.ts";
import { LegacyExpectedExports as ExpectedExports } from "./types.ts";
export class Migration2<Version extends string> {
version: Version;
up: (
effects: T.Effects,
) => Promise<T.MigrationRes>;
down: (
effects: T.Effects,
) => Promise<T.MigrationRes>;
constructor(options: {
version: Version;
up: (
effects: T.Effects,
) => Promise<T.MigrationRes>;
down: (
effects: T.Effects,
) => Promise<T.MigrationRes>;
}) {
this.version = options.version;
this.up = options.up;
this.down = options.down;
}
}
export class MigrationMapping2<Migrations extends Migration2<string>[]> {
constructor(
readonly migrations: Migrations,
) {
}
}
export type MigrationFn<version extends string, type extends "up" | "down"> = (
effects: T.Effects,
@@ -26,7 +56,7 @@ export type MigrationMapping<versions extends string> = {
export function fromMapping<versions extends string>(
migrations: MigrationMapping<versions>,
currentVersion: string,
): T.ExpectedExports.migration {
): ExpectedExports.migration {
const directionShape = matches.literals("from", "to");
return async (
effects: T.Effects,

2
mod.ts
View File

@@ -1,7 +1,7 @@
export { matches, YAML } from "./dependencies.ts";
export * as types from "./types.ts";
export * as compat from "./compat/mod.ts";
export * as migrations from "./migrations.ts";
// export * as migrations from "./migrations.ts";
export * as healthUtil from "./healthUtil.ts";
export * as util from "./util.ts";
export * as configBuilder from "./config_builder/mod.ts";

View File

@@ -3,8 +3,86 @@ import { ConfigSpec } from "./types/config-types.ts";
// deno-lint-ignore no-namespace
export namespace ExpectedExports {
// deno-lint-ignore no-unused-labels
version:
2;
1;
/** Set configuration is called after we have modified and saved the configuration in the embassy ui. Use this to make a file for the docker to read from for configuration. */
export type setConfig = (options: {
effects: Effects;
input: Record<string, unknown>;
}) => Promise<ResultType<SetResult>>;
/** Get configuration returns a shape that describes the format that the embassy ui will generate, and later send to the set config */
export type getConfig = (
options: { effects: Effects },
) => Promise<ResultType<ConfigRes>>;
/** These are how we make sure the our dependency configurations are valid and if not how to fix them. */
export type dependencies = Dependencies;
/** For backing up service data though the embassyOS UI */
export type createBackup = (
options: { effects: Effects },
) => Promise<ResultType<unknown>>;
/** For restoring service data that was previously backed up using the embassyOS UI create backup flow. Backup restores are also triggered via the embassyOS UI, or doing a system restore flow during setup. */
export type restoreBackup = (
options: {
effects: Effects;
},
) => Promise<ResultType<unknown>>;
/** Properties are used to get values from the docker, like a username + password, what ports we are hosting from */
export type properties = (
options: {
effects: Effects;
},
) => Promise<ResultType<Properties>>;
/** Health checks are used to determine if the service is working properly after starting
* A good use case is if we are using a web server, seeing if we can get to the web server.
*/
export type health = {
/** Should be the health check id */
[id: string]: (options: {
effects: Effects;
input: TimeMs;
}) => Promise<ResultType<unknown>>;
};
/**
* Migrations are used when we are changing versions when updating/ downgrading.
* There are times that we need to move files around, and do other operations during a migration.
*/
export type migration = (
options: {
effects: Effects;
input: VersionString;
args: unknown[];
},
) => Promise<ResultType<MigrationRes>>;
/**
* Actions are used so we can effect the service, like deleting a directory.
* One old use case is to add a action where we add a file, that will then be run during the
* service starting, and that file would indicate that it would rescan all the data.
*/
export type action = {
[id: string]: (options: {
effects: Effects;
input?: Record<string, unknown>;
}) => Promise<ResultType<ActionResult>>;
};
/**
* This is the entrypoint for the main container. Used to start up something like the service that the
* package represents, like running a bitcoind in a bitcoind-wrapper.
*/
export type main = (
options: { effects: Effects; started(): null },
) => Promise<ResultType<unknown>>;
}
export type TimeMs = number;
export type VersionString = string;
/** @deprecated */
// deno-lint-ignore no-namespace
export namespace LegacyExpectedExports {
/** Set configuration is called after we have modified and saved the configuration in the embassy ui. Use this to make a file for the docker to read from for configuration. */
export type setConfig = (
effects: Effects,
@@ -108,7 +186,7 @@ export type Effects = {
chown(input: { volumeId: string; path: string; uid: string }): Promise<null>;
chmod(input: { volumeId: string; path: string; mode: string }): Promise<null>;
sleep(timeMs: number): Promise<null>;
sleep(timeMs: TimeMs): Promise<null>;
/** Log at the trace level */
trace(whatToPrint: string): void;