mirror of
https://github.com/Start9Labs/start-sdk.git
synced 2026-03-30 20:24:47 +00:00
fix: Make the backup cleanup the other files that are not used.
This commit is contained in:
36
backups.ts
36
backups.ts
@@ -33,7 +33,7 @@ type BackupSet = {
|
|||||||
* srcVolume: 'main', srcPath:'smallData/', dstPath: 'main/smallData/', dstVolume: : Backups.BACKUP
|
* srcVolume: 'main', srcPath:'smallData/', dstPath: 'main/smallData/', dstVolume: : Backups.BACKUP
|
||||||
* }, {
|
* }, {
|
||||||
* srcVolume: 'main', srcPath:'bigData/', dstPath: 'main/bigData/', dstVolume: : Backups.BACKUP, options: {exclude:['bigData/excludeThis']}}
|
* srcVolume: 'main', srcPath:'bigData/', dstPath: 'main/bigData/', dstVolume: : Backups.BACKUP, options: {exclude:['bigData/excludeThis']}}
|
||||||
* ).build()
|
* ).build()q
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export class Backups {
|
export class Backups {
|
||||||
@@ -84,7 +84,35 @@ export class Backups {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
build() {
|
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) {
|
for (const item of this.backupSet) {
|
||||||
if (notEmptyPath(item.dstPath)) {
|
if (notEmptyPath(item.dstPath)) {
|
||||||
await effects.createDir({
|
await effects.createDir({
|
||||||
@@ -102,7 +130,9 @@ export class Backups {
|
|||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
};
|
};
|
||||||
const restoreBackup: T.ExpectedExports.restoreBackup = async (effects) => {
|
const restoreBackup: T.ExpectedExports.restoreBackup = async (
|
||||||
|
{ effects },
|
||||||
|
) => {
|
||||||
for (const item of this.backupSet) {
|
for (const item of this.backupSet) {
|
||||||
if (notEmptyPath(item.srcPath)) {
|
if (notEmptyPath(item.srcPath)) {
|
||||||
await effects.createDir({
|
await effects.createDir({
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Config } from "../config_builder/config.ts";
|
import { Config } from "../config_builder/config.ts";
|
||||||
import { YAML } from "../dependencies.ts";
|
import { YAML } from "../dependencies.ts";
|
||||||
import { matches } 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 { ConfigSpec } from "../types/config-types.ts";
|
||||||
import { TypeFromProps, typeFromProps } from "../utils/propertiesMatcher.ts";
|
import { TypeFromProps, typeFromProps } from "../utils/propertiesMatcher.ts";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { getConfig, setConfig } from "./mod.ts";
|
import { getConfig, setConfig } from "./mod.ts";
|
||||||
import * as T from "../types.ts";
|
import * as T from "../types.ts";
|
||||||
|
|
||||||
|
import { LegacyExpectedExports as ExpectedExports } from "../types.ts";
|
||||||
import * as M from "../migrations.ts";
|
import * as M from "../migrations.ts";
|
||||||
import * as util from "../util.ts";
|
import * as util from "../util.ts";
|
||||||
import { EmVer } from "../emver-lite/mod.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>(
|
export function fromMapping<versions extends string>(
|
||||||
migrations: M.MigrationMapping<versions>,
|
migrations: M.MigrationMapping<versions>,
|
||||||
currentVersion: string,
|
currentVersion: string,
|
||||||
): T.ExpectedExports.migration {
|
): ExpectedExports.migration {
|
||||||
const inner = M.fromMapping(migrations, currentVersion);
|
const inner = M.fromMapping(migrations, currentVersion);
|
||||||
return async (effects: T.Effects, version: string, direction?: unknown) => {
|
return async (effects: T.Effects, version: string, direction?: unknown) => {
|
||||||
await initNoRepeat(
|
await initNoRepeat(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export { properties } from "./properties.ts";
|
export { noPropertiesFound, properties, propertiesv2 } from "./properties.ts";
|
||||||
export { setConfig } from "./setConfig.ts";
|
export { setConfig } from "./setConfig.ts";
|
||||||
export { getConfig, getConfigAndMatcher } from "./getConfig.ts";
|
export { getConfig, getConfigAndMatcher } from "./getConfig.ts";
|
||||||
export * as migrations from "./migrations.ts";
|
export * as migrations from "./migrations.ts";
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
import { YAML } from "../dependencies.ts";
|
import { YAML } from "../dependencies.ts";
|
||||||
import { exists } from "../util.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
|
// deno-lint-ignore no-explicit-any
|
||||||
const asResult = (result: any) => ({ result: result as Properties });
|
const asResult = (result: any) => ({ result: result as Properties });
|
||||||
const noPropertiesFound: ResultType<Properties> = {
|
export const noPropertiesFound: ResultType<Properties> = {
|
||||||
result: {
|
result: {
|
||||||
version: 2,
|
version: 2,
|
||||||
data: {
|
data: {
|
||||||
@@ -26,7 +32,7 @@ const noPropertiesFound: ResultType<Properties> = {
|
|||||||
* @param effects
|
* @param effects
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const properties: ExpectedExports.properties = async (
|
export const properties: LegacyExpectedExports.properties = async (
|
||||||
effects: Effects,
|
effects: Effects,
|
||||||
) => {
|
) => {
|
||||||
if (
|
if (
|
||||||
@@ -40,3 +46,24 @@ export const properties: ExpectedExports.properties = async (
|
|||||||
volumeId: "main",
|
volumeId: "main",
|
||||||
}).then(YAML.parse).then(asResult);
|
}).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);
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import { YAML } from "../dependencies.ts";
|
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";
|
import { okOf } from "../util.ts";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export function setupConfigExports<A extends ConfigSpec>(options: {
|
|||||||
}) {
|
}) {
|
||||||
const validator = options.spec.validator();
|
const validator = options.spec.validator();
|
||||||
return {
|
return {
|
||||||
setConfig: (async (effects: Effects, config: unknown) => {
|
setConfig: (async ({ effects, input: config }) => {
|
||||||
if (!validator.test(config)) {
|
if (!validator.test(config)) {
|
||||||
await effects.error(String(validator.errorMessage(config)));
|
await effects.error(String(validator.errorMessage(config)));
|
||||||
return { error: "Set config type error for config" };
|
return { error: "Set config type error for config" };
|
||||||
@@ -26,7 +26,7 @@ export function setupConfigExports<A extends ConfigSpec>(options: {
|
|||||||
"depends-on": options.dependsOn,
|
"depends-on": options.dependsOn,
|
||||||
});
|
});
|
||||||
}) as ExpectedExports.setConfig,
|
}) as ExpectedExports.setConfig,
|
||||||
getConfig: (async (effects: Effects) => {
|
getConfig: (async ({ effects }) => {
|
||||||
return okOf({
|
return okOf({
|
||||||
spec: options.spec.build(),
|
spec: options.spec.build(),
|
||||||
config: nullIfEmpty(await options.read(effects)),
|
config: nullIfEmpty(await options.read(effects)),
|
||||||
|
|||||||
@@ -1,6 +1,36 @@
|
|||||||
import { types as T } from "./mod.ts";
|
import { types as T } from "./mod.ts";
|
||||||
import { EmVer } from "./emver-lite/mod.ts";
|
import { EmVer } from "./emver-lite/mod.ts";
|
||||||
import { matches } from "./dependencies.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"> = (
|
export type MigrationFn<version extends string, type extends "up" | "down"> = (
|
||||||
effects: T.Effects,
|
effects: T.Effects,
|
||||||
@@ -26,7 +56,7 @@ export type MigrationMapping<versions extends string> = {
|
|||||||
export function fromMapping<versions extends string>(
|
export function fromMapping<versions extends string>(
|
||||||
migrations: MigrationMapping<versions>,
|
migrations: MigrationMapping<versions>,
|
||||||
currentVersion: string,
|
currentVersion: string,
|
||||||
): T.ExpectedExports.migration {
|
): ExpectedExports.migration {
|
||||||
const directionShape = matches.literals("from", "to");
|
const directionShape = matches.literals("from", "to");
|
||||||
return async (
|
return async (
|
||||||
effects: T.Effects,
|
effects: T.Effects,
|
||||||
|
|||||||
2
mod.ts
2
mod.ts
@@ -1,7 +1,7 @@
|
|||||||
export { matches, YAML } from "./dependencies.ts";
|
export { matches, YAML } from "./dependencies.ts";
|
||||||
export * as types from "./types.ts";
|
export * as types from "./types.ts";
|
||||||
export * as compat from "./compat/mod.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 healthUtil from "./healthUtil.ts";
|
||||||
export * as util from "./util.ts";
|
export * as util from "./util.ts";
|
||||||
export * as configBuilder from "./config_builder/mod.ts";
|
export * as configBuilder from "./config_builder/mod.ts";
|
||||||
|
|||||||
82
types.ts
82
types.ts
@@ -3,8 +3,86 @@ import { ConfigSpec } from "./types/config-types.ts";
|
|||||||
|
|
||||||
// deno-lint-ignore no-namespace
|
// deno-lint-ignore no-namespace
|
||||||
export namespace ExpectedExports {
|
export namespace ExpectedExports {
|
||||||
|
// deno-lint-ignore no-unused-labels
|
||||||
version:
|
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. */
|
/** 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 = (
|
export type setConfig = (
|
||||||
effects: Effects,
|
effects: Effects,
|
||||||
@@ -108,7 +186,7 @@ export type Effects = {
|
|||||||
chown(input: { volumeId: string; path: string; uid: string }): Promise<null>;
|
chown(input: { volumeId: string; path: string; uid: string }): Promise<null>;
|
||||||
chmod(input: { volumeId: string; path: string; mode: 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 */
|
/** Log at the trace level */
|
||||||
trace(whatToPrint: string): void;
|
trace(whatToPrint: string): void;
|
||||||
|
|||||||
Reference in New Issue
Block a user