@git.zone/cli 3.2.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.smartconfig.json +0 -1
- package/dist_ts/00_commitinfo_data.js +2 -2
- package/dist_ts/classes.gitzoneconfig.js +1 -1
- package/dist_ts/classes.project.js +1 -1
- package/dist_ts/gitzone.cli.js +1 -1
- package/dist_ts/gitzone.logging.js +1 -1
- package/dist_ts/helpers.changelog.js +1 -1
- package/dist_ts/helpers.climode.js +1 -1
- package/dist_ts/helpers.smartconfig.js +61 -11
- package/dist_ts/helpers.smartconfigmigrations.js +1 -1
- package/dist_ts/helpers.tsdocker.js +1 -1
- package/dist_ts/helpers.workflow.d.ts +0 -2
- package/dist_ts/helpers.workflow.js +23 -12
- package/dist_ts/index.js +1 -1
- package/dist_ts/mod_audit/index.js +1 -1
- package/dist_ts/mod_commit/index.js +1 -1
- package/dist_ts/mod_commit/mod.helpers.d.ts +3 -3
- package/dist_ts/mod_commit/mod.helpers.js +10 -10
- package/dist_ts/mod_commit/mod.plugins.js +1 -1
- package/dist_ts/mod_commit/mod.ui.js +1 -1
- package/dist_ts/mod_config/classes.commitconfig.js +1 -1
- package/dist_ts/mod_config/classes.releaseconfig.js +1 -1
- package/dist_ts/mod_config/index.js +23 -24
- package/dist_ts/mod_config/mod.plugins.js +1 -1
- package/dist_ts/mod_deprecate/index.js +1 -1
- package/dist_ts/mod_deprecate/mod.plugins.js +1 -1
- package/dist_ts/mod_docker/classes.dockerpruner.js +7 -1
- package/dist_ts/mod_docker/index.js +1 -1
- package/dist_ts/mod_docker/mod.plugins.js +1 -1
- package/dist_ts/mod_format/classes.baseformatter.js +1 -1
- package/dist_ts/mod_format/classes.diffreporter.js +1 -1
- package/dist_ts/mod_format/classes.formatcontext.js +1 -1
- package/dist_ts/mod_format/classes.formatplanner.js +1 -1
- package/dist_ts/mod_format/classes.formatstats.js +1 -1
- package/dist_ts/mod_format/formatters/assets.formatter.js +1 -1
- package/dist_ts/mod_format/formatters/cleanup.formatter.js +1 -1
- package/dist_ts/mod_format/formatters/copy.formatter.js +1 -1
- package/dist_ts/mod_format/formatters/gitignore.formatter.js +1 -1
- package/dist_ts/mod_format/formatters/license.formatter.js +1 -1
- package/dist_ts/mod_format/formatters/packagejson.formatter.js +1 -1
- package/dist_ts/mod_format/formatters/prettier.formatter.js +1 -1
- package/dist_ts/mod_format/formatters/readme.formatter.js +1 -1
- package/dist_ts/mod_format/formatters/smartconfig.formatter.js +1 -1
- package/dist_ts/mod_format/formatters/templates.formatter.js +1 -1
- package/dist_ts/mod_format/formatters/tsconfig.formatter.js +1 -1
- package/dist_ts/mod_format/index.js +1 -1
- package/dist_ts/mod_format/interfaces.format.js +1 -1
- package/dist_ts/mod_format/mod.plugins.js +1 -1
- package/dist_ts/mod_helpers/index.js +1 -1
- package/dist_ts/mod_helpers/mod.plugins.js +1 -1
- package/dist_ts/mod_meta/index.js +1 -1
- package/dist_ts/mod_meta/meta.classes.meta.js +1 -1
- package/dist_ts/mod_meta/meta.interfaces.js +1 -1
- package/dist_ts/mod_meta/meta.plugins.js +1 -1
- package/dist_ts/mod_open/index.js +1 -1
- package/dist_ts/mod_open/mod.plugins.js +1 -1
- package/dist_ts/mod_release/helpers.releasebranch.d.ts +46 -0
- package/dist_ts/mod_release/helpers.releasebranch.js +579 -0
- package/dist_ts/mod_release/index.d.ts +10 -0
- package/dist_ts/mod_release/index.js +300 -92
- package/dist_ts/mod_release/mod.plugins.js +1 -1
- package/dist_ts/mod_services/classes.dockercontainer.d.ts +50 -3
- package/dist_ts/mod_services/classes.dockercontainer.js +646 -84
- package/dist_ts/mod_services/classes.globalregistry.d.ts +10 -24
- package/dist_ts/mod_services/classes.globalregistry.js +210 -62
- package/dist_ts/mod_services/classes.globalregistrystore.d.ts +48 -0
- package/dist_ts/mod_services/classes.globalregistrystore.js +156 -0
- package/dist_ts/mod_services/classes.interprocesslock.d.ts +21 -0
- package/dist_ts/mod_services/classes.interprocesslock.js +141 -0
- package/dist_ts/mod_services/classes.serviceconfiguration.d.ts +15 -12
- package/dist_ts/mod_services/classes.serviceconfiguration.js +188 -91
- package/dist_ts/mod_services/classes.servicedatamarker.d.ts +32 -7
- package/dist_ts/mod_services/classes.servicedatamarker.js +145 -49
- package/dist_ts/mod_services/classes.servicemanager.d.ts +70 -28
- package/dist_ts/mod_services/classes.servicemanager.js +995 -421
- package/dist_ts/mod_services/classes.servicenames.d.ts +8 -0
- package/dist_ts/mod_services/classes.servicenames.js +54 -0
- package/dist_ts/mod_services/classes.serviceoptions.js +1 -1
- package/dist_ts/mod_services/classes.servicepruner.d.ts +3 -0
- package/dist_ts/mod_services/classes.servicepruner.js +208 -46
- package/dist_ts/mod_services/helpers.js +1 -1
- package/dist_ts/mod_services/index.d.ts +2 -0
- package/dist_ts/mod_services/index.js +81 -58
- package/dist_ts/mod_services/mod.plugins.js +1 -1
- package/dist_ts/mod_standard/index.js +2 -2
- package/dist_ts/mod_standard/mod.plugins.js +1 -1
- package/dist_ts/mod_start/index.js +1 -1
- package/dist_ts/mod_start/mod.plugins.js +1 -1
- package/dist_ts/mod_template/index.js +1 -1
- package/dist_ts/mod_template/mod.plugins.js +1 -1
- package/dist_ts/mod_tools/classes.packagemanager.js +1 -1
- package/dist_ts/mod_tools/index.js +1 -1
- package/dist_ts/mod_tools/mod.plugins.js +1 -1
- package/dist_ts/paths.js +1 -1
- package/dist_ts/plugins.d.ts +3 -1
- package/dist_ts/plugins.js +4 -2
- package/dist_ts_migration/001.service-selection.d.ts +9 -0
- package/dist_ts_migration/001.service-selection.js +51 -0
- package/dist_ts_migration/002.runtime-config.d.ts +19 -0
- package/dist_ts_migration/002.runtime-config.js +170 -0
- package/dist_ts_migration/003.service-data-marker.d.ts +9 -0
- package/dist_ts_migration/003.service-data-marker.js +156 -0
- package/dist_ts_migration/004.global-registry.d.ts +13 -0
- package/dist_ts_migration/004.global-registry.js +165 -0
- package/dist_ts_migration/index.d.ts +11 -0
- package/dist_ts_migration/index.js +59 -0
- package/package.json +6 -3
- package/readme.hints.md +102 -25
- package/readme.md +144 -41
- package/readme.plan.md +29 -16
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/helpers.smartconfig.ts +63 -10
- package/ts/helpers.workflow.ts +41 -12
- package/ts/mod_commit/mod.helpers.ts +12 -8
- package/ts/mod_config/index.ts +22 -23
- package/ts/mod_docker/classes.dockerpruner.ts +6 -0
- package/ts/mod_release/helpers.releasebranch.ts +1282 -0
- package/ts/mod_release/index.ts +608 -129
- package/ts/mod_services/classes.dockercontainer.ts +912 -96
- package/ts/mod_services/classes.globalregistry.ts +290 -89
- package/ts/mod_services/classes.globalregistrystore.ts +279 -0
- package/ts/mod_services/classes.interprocesslock.ts +189 -0
- package/ts/mod_services/classes.serviceconfiguration.ts +215 -108
- package/ts/mod_services/classes.servicedatamarker.ts +210 -52
- package/ts/mod_services/classes.servicemanager.ts +1332 -512
- package/ts/mod_services/classes.servicenames.ts +76 -0
- package/ts/mod_services/classes.servicepruner.ts +310 -52
- package/ts/mod_services/index.ts +89 -62
- package/ts/mod_standard/index.ts +1 -1
- package/ts/plugins.ts +4 -0
- package/ts_migration/001.service-selection.ts +77 -0
- package/ts_migration/002.runtime-config.ts +218 -0
- package/ts_migration/003.service-data-marker.ts +216 -0
- package/ts_migration/004.global-registry.ts +272 -0
- package/ts_migration/index.ts +83 -0
|
@@ -6,14 +6,20 @@
|
|
|
6
6
|
* `@git.zone/tsdeploy` (`deriveRequiredCapabilities`), so the strings and the
|
|
7
7
|
* array shape must never change here.
|
|
8
8
|
*/
|
|
9
|
-
export type TServiceName = 'mongodb' | '
|
|
9
|
+
export type TServiceName = 'mongodb' | 'objectstorage' | 'elasticsearch';
|
|
10
|
+
export type TLegacyServiceName = 'minio';
|
|
10
11
|
export declare const serviceNames: TServiceName[];
|
|
12
|
+
export declare const objectStorageImage = "code.foss.global/lossless.zone/objectstorage@sha256:43b60897eed17b54feb4e363808ce540ed1d9d27201871c5c8a869300d41e1b8";
|
|
11
13
|
/** Owner recorded in markers and container labels. */
|
|
12
14
|
export declare const serviceDataOwner = "@git.zone/cli";
|
|
13
15
|
/** Value of the `git.zone.tool` label on containers created by `gitzone services`. */
|
|
14
16
|
export declare const serviceToolLabel = "gitzone-services";
|
|
15
17
|
/** Marker file name, stored in `<projectPath>/.nogit/`. */
|
|
16
18
|
export declare const serviceDataMarkerFile = ".gitzone-services.json";
|
|
19
|
+
export declare const serviceDataMarkerSchemaVersion = 2;
|
|
20
|
+
export declare const legacyMinioDataDirectoryName = "miniodata";
|
|
21
|
+
export declare const serviceOperationLabel = "git.zone.operation";
|
|
22
|
+
export declare const serviceBindOperation = "service-bind-operation";
|
|
17
23
|
/**
|
|
18
24
|
* Directory basename used below `.nogit/` for each service's bind-mounted data.
|
|
19
25
|
* This mapping is the only shape `gitzone services` ever creates, and prune
|
|
@@ -24,7 +30,7 @@ export declare const serviceDataDirectoryNames: {
|
|
|
24
30
|
};
|
|
25
31
|
/**
|
|
26
32
|
* Image used to run each service, and therefore the image available to perform
|
|
27
|
-
* a
|
|
33
|
+
* a root-helper cleanup of that service's data directory: if the data exists,
|
|
28
34
|
* the service ran, so its image is present locally.
|
|
29
35
|
*/
|
|
30
36
|
export declare const serviceImages: {
|
|
@@ -37,22 +43,31 @@ export interface IServiceDataMarkerEntry {
|
|
|
37
43
|
export interface IServiceDataMarker {
|
|
38
44
|
owner: string;
|
|
39
45
|
kind: 'service-data';
|
|
40
|
-
schemaVersion:
|
|
46
|
+
schemaVersion: 2;
|
|
41
47
|
projectPath: string;
|
|
42
48
|
safeToPrune: true;
|
|
43
49
|
createdAt: string;
|
|
44
50
|
dataDirectories: IServiceDataMarkerEntry[];
|
|
51
|
+
legacyDataDirectories?: ILegacyServiceDataMarkerEntry[];
|
|
52
|
+
}
|
|
53
|
+
export interface ILegacyServiceDataMarkerEntry {
|
|
54
|
+
service: TLegacyServiceName;
|
|
55
|
+
path: string;
|
|
56
|
+
safeToPrune: false;
|
|
45
57
|
}
|
|
46
58
|
/** Absolute path of the marker file for a project. */
|
|
47
59
|
export declare const getServiceDataMarkerPath: (projectPathArg: string) => string;
|
|
60
|
+
export declare const getServiceDataMarkerLockPath: (projectPathArg: string) => string;
|
|
48
61
|
/**
|
|
49
62
|
* Expected absolute data directory path for a service in a project.
|
|
50
63
|
* `mod_services` must always derive data paths through this helper so that
|
|
51
64
|
* creation and reclamation agree on a single shape.
|
|
52
65
|
*/
|
|
53
66
|
export declare const getServiceDataDirectory: (projectPathArg: string, serviceArg: TServiceName) => string;
|
|
67
|
+
/** Exact legacy path retained only for migration detection. */
|
|
68
|
+
export declare const getLegacyMinioDataDirectory: (projectPathArg: string) => string;
|
|
54
69
|
/**
|
|
55
|
-
* True only when `candidatePathArg` is exactly one of the
|
|
70
|
+
* True only when `candidatePathArg` is exactly one of the canonical data
|
|
56
71
|
* directories `gitzone services` creates for `projectPathArg`.
|
|
57
72
|
*
|
|
58
73
|
* This is an allowlist, not a denylist: any path that is not byte-for-byte one
|
|
@@ -60,16 +75,17 @@ export declare const getServiceDataDirectory: (projectPathArg: string, serviceAr
|
|
|
60
75
|
* before a recursive delete.
|
|
61
76
|
*/
|
|
62
77
|
export declare const isSafeServiceDataPath: (projectPathArg: string, candidatePathArg: string) => boolean;
|
|
63
|
-
/** Validate an unknown value as a
|
|
78
|
+
/** Validate an unknown value as a canonical v2 marker. */
|
|
64
79
|
export declare const isValidServiceDataMarker: (markerArg: unknown) => markerArg is IServiceDataMarker;
|
|
65
80
|
/** Read and validate the marker for a project, or undefined when absent/invalid. */
|
|
66
81
|
export declare const readServiceDataMarker: (projectPathArg: string) => Promise<IServiceDataMarker | undefined>;
|
|
82
|
+
export declare const markerProvesServiceDataDirectory: (markerArg: IServiceDataMarker | undefined, projectPathArg: string, serviceArg: TServiceName) => boolean;
|
|
67
83
|
/**
|
|
68
84
|
* Record that `gitzone services` owns a data directory for this project.
|
|
69
85
|
*
|
|
70
86
|
* The marker lives in `.nogit/` rather than inside the bind-mounted data
|
|
71
|
-
* directory itself, so it can never confuse
|
|
72
|
-
*
|
|
87
|
+
* directory itself, so it can never confuse a service runtime. Entries are
|
|
88
|
+
* merged so enabling a service later does not drop the
|
|
73
89
|
* claim on previously created directories.
|
|
74
90
|
*/
|
|
75
91
|
export declare const recordServiceDataDirectory: (projectPathArg: string, serviceArg: TServiceName) => Promise<void>;
|
|
@@ -87,7 +103,16 @@ export declare const getServiceContainerLabels: (optionsArg: {
|
|
|
87
103
|
}) => {
|
|
88
104
|
[key: string]: string;
|
|
89
105
|
};
|
|
106
|
+
export declare const hasExactServiceContainerLabels: (labelsArg: Record<string, string>, expectedArg: Record<string, string>) => boolean;
|
|
90
107
|
/** True when a container's labels prove `gitzone services` created it. */
|
|
91
108
|
export declare const isServiceOwnedByLabels: (labelsArg: {
|
|
92
109
|
[key: string]: string;
|
|
93
110
|
}) => boolean;
|
|
111
|
+
/** Legacy provider evidence is retained for migration, never active lifecycle ownership. */
|
|
112
|
+
export declare const isLegacyMinioContainerLabels: (labelsArg: {
|
|
113
|
+
[key: string]: string;
|
|
114
|
+
}) => boolean;
|
|
115
|
+
/** Transient bind-operation containers are owned by their invocation, not by prune. */
|
|
116
|
+
export declare const isServiceOperationHelperLabels: (labelsArg: {
|
|
117
|
+
[key: string]: string;
|
|
118
|
+
}) => boolean;
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import * as plugins from './mod.plugins.js';
|
|
2
|
-
|
|
2
|
+
import { withInterProcessLock } from './classes.interprocesslock.js';
|
|
3
|
+
export const serviceNames = ['mongodb', 'objectstorage', 'elasticsearch'];
|
|
4
|
+
export const objectStorageImage = 'code.foss.global/lossless.zone/objectstorage@sha256:43b60897eed17b54feb4e363808ce540ed1d9d27201871c5c8a869300d41e1b8';
|
|
3
5
|
/** Owner recorded in markers and container labels. */
|
|
4
6
|
export const serviceDataOwner = '@git.zone/cli';
|
|
5
7
|
/** Value of the `git.zone.tool` label on containers created by `gitzone services`. */
|
|
6
8
|
export const serviceToolLabel = 'gitzone-services';
|
|
7
9
|
/** Marker file name, stored in `<projectPath>/.nogit/`. */
|
|
8
10
|
export const serviceDataMarkerFile = '.gitzone-services.json';
|
|
11
|
+
export const serviceDataMarkerSchemaVersion = 2;
|
|
12
|
+
export const legacyMinioDataDirectoryName = 'miniodata';
|
|
13
|
+
export const serviceOperationLabel = 'git.zone.operation';
|
|
14
|
+
export const serviceBindOperation = 'service-bind-operation';
|
|
9
15
|
/**
|
|
10
16
|
* Directory basename used below `.nogit/` for each service's bind-mounted data.
|
|
11
17
|
* This mapping is the only shape `gitzone services` ever creates, and prune
|
|
@@ -13,26 +19,30 @@ export const serviceDataMarkerFile = '.gitzone-services.json';
|
|
|
13
19
|
*/
|
|
14
20
|
export const serviceDataDirectoryNames = {
|
|
15
21
|
mongodb: 'mongodata',
|
|
16
|
-
|
|
22
|
+
objectstorage: 'objectstoragedata',
|
|
17
23
|
elasticsearch: 'esdata',
|
|
18
24
|
};
|
|
19
25
|
/**
|
|
20
26
|
* Image used to run each service, and therefore the image available to perform
|
|
21
|
-
* a
|
|
27
|
+
* a root-helper cleanup of that service's data directory: if the data exists,
|
|
22
28
|
* the service ran, so its image is present locally.
|
|
23
29
|
*/
|
|
24
30
|
export const serviceImages = {
|
|
25
31
|
mongodb: 'mongo:7.0',
|
|
26
|
-
|
|
32
|
+
objectstorage: objectStorageImage,
|
|
27
33
|
elasticsearch: 'elasticsearch:8.11.0',
|
|
28
34
|
};
|
|
29
35
|
const isPlainObject = (value) => {
|
|
30
36
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
31
37
|
};
|
|
38
|
+
const hasOnlyKeys = (valueArg, allowedKeysArg) => Object.keys(valueArg).every((keyArg) => allowedKeysArg.includes(keyArg));
|
|
32
39
|
/** Absolute path of the marker file for a project. */
|
|
33
40
|
export const getServiceDataMarkerPath = (projectPathArg) => {
|
|
34
41
|
return plugins.path.join(plugins.path.resolve(projectPathArg), '.nogit', serviceDataMarkerFile);
|
|
35
42
|
};
|
|
43
|
+
export const getServiceDataMarkerLockPath = (projectPathArg) => {
|
|
44
|
+
return `${getServiceDataMarkerPath(projectPathArg)}.lock`;
|
|
45
|
+
};
|
|
36
46
|
/**
|
|
37
47
|
* Expected absolute data directory path for a service in a project.
|
|
38
48
|
* `mod_services` must always derive data paths through this helper so that
|
|
@@ -41,8 +51,12 @@ export const getServiceDataMarkerPath = (projectPathArg) => {
|
|
|
41
51
|
export const getServiceDataDirectory = (projectPathArg, serviceArg) => {
|
|
42
52
|
return plugins.path.join(plugins.path.resolve(projectPathArg), '.nogit', serviceDataDirectoryNames[serviceArg]);
|
|
43
53
|
};
|
|
54
|
+
/** Exact legacy path retained only for migration detection. */
|
|
55
|
+
export const getLegacyMinioDataDirectory = (projectPathArg) => {
|
|
56
|
+
return plugins.path.join(plugins.path.resolve(projectPathArg), '.nogit', legacyMinioDataDirectoryName);
|
|
57
|
+
};
|
|
44
58
|
/**
|
|
45
|
-
* True only when `candidatePathArg` is exactly one of the
|
|
59
|
+
* True only when `candidatePathArg` is exactly one of the canonical data
|
|
46
60
|
* directories `gitzone services` creates for `projectPathArg`.
|
|
47
61
|
*
|
|
48
62
|
* This is an allowlist, not a denylist: any path that is not byte-for-byte one
|
|
@@ -58,31 +72,39 @@ export const isSafeServiceDataPath = (projectPathArg, candidatePathArg) => {
|
|
|
58
72
|
}
|
|
59
73
|
return false;
|
|
60
74
|
};
|
|
61
|
-
|
|
75
|
+
const hasValidMarkerEnvelope = (markerArg) => {
|
|
76
|
+
return (markerArg.owner === serviceDataOwner &&
|
|
77
|
+
markerArg.kind === 'service-data' &&
|
|
78
|
+
markerArg.safeToPrune === true &&
|
|
79
|
+
typeof markerArg.projectPath === 'string' &&
|
|
80
|
+
markerArg.projectPath.length > 0 &&
|
|
81
|
+
typeof markerArg.createdAt === 'string' &&
|
|
82
|
+
markerArg.createdAt.length > 0 &&
|
|
83
|
+
Array.isArray(markerArg.dataDirectories));
|
|
84
|
+
};
|
|
85
|
+
/** Validate an unknown value as a canonical v2 marker. */
|
|
62
86
|
export const isValidServiceDataMarker = (markerArg) => {
|
|
63
87
|
if (!isPlainObject(markerArg)) {
|
|
64
88
|
return false;
|
|
65
89
|
}
|
|
66
|
-
if (markerArg
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (typeof markerArg.projectPath !== 'string' || !markerArg.projectPath) {
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
if (!Array.isArray(markerArg.dataDirectories)) {
|
|
90
|
+
if (!hasOnlyKeys(markerArg, [
|
|
91
|
+
'owner',
|
|
92
|
+
'kind',
|
|
93
|
+
'schemaVersion',
|
|
94
|
+
'projectPath',
|
|
95
|
+
'safeToPrune',
|
|
96
|
+
'createdAt',
|
|
97
|
+
'dataDirectories',
|
|
98
|
+
'legacyDataDirectories',
|
|
99
|
+
]) ||
|
|
100
|
+
!hasValidMarkerEnvelope(markerArg) ||
|
|
101
|
+
markerArg.schemaVersion !== serviceDataMarkerSchemaVersion) {
|
|
82
102
|
return false;
|
|
83
103
|
}
|
|
104
|
+
const projectPath = plugins.path.resolve(markerArg.projectPath);
|
|
105
|
+
const seenServices = new Set();
|
|
84
106
|
for (const entry of markerArg.dataDirectories) {
|
|
85
|
-
if (!isPlainObject(entry)) {
|
|
107
|
+
if (!isPlainObject(entry) || !hasOnlyKeys(entry, ['service', 'path'])) {
|
|
86
108
|
return false;
|
|
87
109
|
}
|
|
88
110
|
if (!serviceNames.includes(entry.service)) {
|
|
@@ -91,9 +113,52 @@ export const isValidServiceDataMarker = (markerArg) => {
|
|
|
91
113
|
if (typeof entry.path !== 'string' || !entry.path) {
|
|
92
114
|
return false;
|
|
93
115
|
}
|
|
116
|
+
if (seenServices.has(entry.service) ||
|
|
117
|
+
plugins.path.resolve(entry.path) !== getServiceDataDirectory(projectPath, entry.service)) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
seenServices.add(entry.service);
|
|
121
|
+
}
|
|
122
|
+
if (markerArg.legacyDataDirectories !== undefined) {
|
|
123
|
+
if (!Array.isArray(markerArg.legacyDataDirectories)) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
for (const entry of markerArg.legacyDataDirectories) {
|
|
127
|
+
if (!isPlainObject(entry) ||
|
|
128
|
+
!hasOnlyKeys(entry, ['service', 'path', 'safeToPrune']) ||
|
|
129
|
+
entry.service !== 'minio' ||
|
|
130
|
+
entry.safeToPrune !== false ||
|
|
131
|
+
typeof entry.path !== 'string' ||
|
|
132
|
+
plugins.path.resolve(entry.path) !== getLegacyMinioDataDirectory(projectPath)) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (markerArg.legacyDataDirectories.length > 1) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
94
139
|
}
|
|
95
140
|
return true;
|
|
96
141
|
};
|
|
142
|
+
const writeServiceDataMarker = async (projectPathArg, markerArg) => {
|
|
143
|
+
const markerPath = getServiceDataMarkerPath(projectPathArg);
|
|
144
|
+
await plugins.smartfs.directory(plugins.path.dirname(markerPath)).recursive().create();
|
|
145
|
+
const tempPath = `${markerPath}.tmp-${process.pid}-${plugins.crypto
|
|
146
|
+
.randomBytes(12)
|
|
147
|
+
.toString('hex')}`;
|
|
148
|
+
try {
|
|
149
|
+
await plugins.fs.writeFile(tempPath, `${JSON.stringify(markerArg, null, 2)}\n`, {
|
|
150
|
+
encoding: 'utf8',
|
|
151
|
+
flag: 'wx',
|
|
152
|
+
});
|
|
153
|
+
await plugins.fs.rename(tempPath, markerPath);
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
await plugins.fs.rm(tempPath, { force: true }).catch(() => { });
|
|
157
|
+
throw new Error(`Could not persist service data marker atomically: ${markerPath}`, {
|
|
158
|
+
cause: error,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
};
|
|
97
162
|
/** Read and validate the marker for a project, or undefined when absent/invalid. */
|
|
98
163
|
export const readServiceDataMarker = async (projectPathArg) => {
|
|
99
164
|
const markerPath = getServiceDataMarkerPath(projectPathArg);
|
|
@@ -103,44 +168,59 @@ export const readServiceDataMarker = async (projectPathArg) => {
|
|
|
103
168
|
}
|
|
104
169
|
const content = (await plugins.smartfs.file(markerPath).encoding('utf8').read());
|
|
105
170
|
const parsed = JSON.parse(content);
|
|
106
|
-
return isValidServiceDataMarker(parsed)
|
|
171
|
+
return isValidServiceDataMarker(parsed) &&
|
|
172
|
+
plugins.path.resolve(parsed.projectPath) === plugins.path.resolve(projectPathArg)
|
|
173
|
+
? parsed
|
|
174
|
+
: undefined;
|
|
107
175
|
}
|
|
108
176
|
catch {
|
|
109
177
|
return undefined;
|
|
110
178
|
}
|
|
111
179
|
};
|
|
180
|
+
export const markerProvesServiceDataDirectory = (markerArg, projectPathArg, serviceArg) => {
|
|
181
|
+
const expectedPath = getServiceDataDirectory(projectPathArg, serviceArg);
|
|
182
|
+
return !!markerArg?.dataDirectories.some((entry) => entry.service === serviceArg && plugins.path.resolve(entry.path) === expectedPath);
|
|
183
|
+
};
|
|
112
184
|
/**
|
|
113
185
|
* Record that `gitzone services` owns a data directory for this project.
|
|
114
186
|
*
|
|
115
187
|
* The marker lives in `.nogit/` rather than inside the bind-mounted data
|
|
116
|
-
* directory itself, so it can never confuse
|
|
117
|
-
*
|
|
188
|
+
* directory itself, so it can never confuse a service runtime. Entries are
|
|
189
|
+
* merged so enabling a service later does not drop the
|
|
118
190
|
* claim on previously created directories.
|
|
119
191
|
*/
|
|
120
192
|
export const recordServiceDataDirectory = async (projectPathArg, serviceArg) => {
|
|
121
193
|
const projectPath = plugins.path.resolve(projectPathArg);
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
194
|
+
await withInterProcessLock({
|
|
195
|
+
lockPath: getServiceDataMarkerLockPath(projectPath),
|
|
196
|
+
description: 'Service data marker',
|
|
197
|
+
}, async () => {
|
|
198
|
+
const dataPath = getServiceDataDirectory(projectPath, serviceArg);
|
|
199
|
+
const markerPath = getServiceDataMarkerPath(projectPath);
|
|
200
|
+
const markerExists = await plugins.smartfs.file(markerPath).exists();
|
|
201
|
+
const existingMarker = await readServiceDataMarker(projectPath);
|
|
202
|
+
if (markerExists && !existingMarker) {
|
|
203
|
+
throw new Error(`Refusing to overwrite invalid or foreign service data marker: ${markerPath}`);
|
|
204
|
+
}
|
|
205
|
+
const entries = existingMarker
|
|
206
|
+
? existingMarker.dataDirectories.filter((entry) => entry.service !== serviceArg)
|
|
207
|
+
: [];
|
|
208
|
+
entries.push({ service: serviceArg, path: dataPath });
|
|
209
|
+
entries.sort((entryA, entryB) => entryA.service.localeCompare(entryB.service));
|
|
210
|
+
const marker = {
|
|
211
|
+
owner: serviceDataOwner,
|
|
212
|
+
kind: 'service-data',
|
|
213
|
+
schemaVersion: serviceDataMarkerSchemaVersion,
|
|
214
|
+
projectPath,
|
|
215
|
+
safeToPrune: true,
|
|
216
|
+
createdAt: existingMarker?.createdAt || new Date().toISOString(),
|
|
217
|
+
dataDirectories: entries,
|
|
218
|
+
...(existingMarker?.legacyDataDirectories
|
|
219
|
+
? { legacyDataDirectories: existingMarker.legacyDataDirectories }
|
|
220
|
+
: {}),
|
|
221
|
+
};
|
|
222
|
+
await writeServiceDataMarker(projectPath, marker);
|
|
223
|
+
});
|
|
144
224
|
};
|
|
145
225
|
/**
|
|
146
226
|
* Labels applied to every container `gitzone services` creates.
|
|
@@ -158,9 +238,25 @@ export const getServiceContainerLabels = (optionsArg) => {
|
|
|
158
238
|
'git.zone.safe-to-prune': 'true',
|
|
159
239
|
};
|
|
160
240
|
};
|
|
241
|
+
export const hasExactServiceContainerLabels = (labelsArg, expectedArg) => {
|
|
242
|
+
const actualGitZoneLabels = Object.entries(labelsArg).filter(([key]) => key.startsWith('git.zone.'));
|
|
243
|
+
const expectedGitZoneLabels = Object.entries(expectedArg).filter(([key]) => key.startsWith('git.zone.'));
|
|
244
|
+
return (actualGitZoneLabels.length === expectedGitZoneLabels.length &&
|
|
245
|
+
expectedGitZoneLabels.every(([key, value]) => labelsArg[key] === value));
|
|
246
|
+
};
|
|
161
247
|
/** True when a container's labels prove `gitzone services` created it. */
|
|
162
248
|
export const isServiceOwnedByLabels = (labelsArg) => {
|
|
163
249
|
return (labelsArg['git.zone.tool'] === serviceToolLabel &&
|
|
164
250
|
labelsArg['git.zone.safe-to-prune'] === 'true');
|
|
165
251
|
};
|
|
166
|
-
|
|
252
|
+
/** Legacy provider evidence is retained for migration, never active lifecycle ownership. */
|
|
253
|
+
export const isLegacyMinioContainerLabels = (labelsArg) => {
|
|
254
|
+
return (labelsArg['git.zone.tool'] === serviceToolLabel &&
|
|
255
|
+
labelsArg['git.zone.service'] === 'minio');
|
|
256
|
+
};
|
|
257
|
+
/** Transient bind-operation containers are owned by their invocation, not by prune. */
|
|
258
|
+
export const isServiceOperationHelperLabels = (labelsArg) => {
|
|
259
|
+
return (labelsArg['git.zone.tool'] === serviceToolLabel &&
|
|
260
|
+
labelsArg[serviceOperationLabel] === serviceBindOperation);
|
|
261
|
+
};
|
|
262
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zZXJ2aWNlZGF0YW1hcmtlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL21vZF9zZXJ2aWNlcy9jbGFzc2VzLnNlcnZpY2VkYXRhbWFya2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFhckUsTUFBTSxDQUFDLE1BQU0sWUFBWSxHQUFtQixDQUFDLFNBQVMsRUFBRSxlQUFlLEVBQUUsZUFBZSxDQUFDLENBQUM7QUFFMUYsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQzdCLHNIQUFzSCxDQUFDO0FBRXpILHNEQUFzRDtBQUN0RCxNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBRyxlQUFlLENBQUM7QUFFaEQsc0ZBQXNGO0FBQ3RGLE1BQU0sQ0FBQyxNQUFNLGdCQUFnQixHQUFHLGtCQUFrQixDQUFDO0FBRW5ELDJEQUEyRDtBQUMzRCxNQUFNLENBQUMsTUFBTSxxQkFBcUIsR0FBRyx3QkFBd0IsQ0FBQztBQUM5RCxNQUFNLENBQUMsTUFBTSw4QkFBOEIsR0FBRyxDQUFDLENBQUM7QUFDaEQsTUFBTSxDQUFDLE1BQU0sNEJBQTRCLEdBQUcsV0FBVyxDQUFDO0FBQ3hELE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFHLG9CQUFvQixDQUFDO0FBQzFELE1BQU0sQ0FBQyxNQUFNLG9CQUFvQixHQUFHLHdCQUF3QixDQUFDO0FBRTdEOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSx5QkFBeUIsR0FBc0M7SUFDMUUsT0FBTyxFQUFFLFdBQVc7SUFDcEIsYUFBYSxFQUFFLG1CQUFtQjtJQUNsQyxhQUFhLEVBQUUsUUFBUTtDQUN4QixDQUFDO0FBRUY7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBc0M7SUFDOUQsT0FBTyxFQUFFLFdBQVc7SUFDcEIs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
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import * as plugins from './mod.plugins.js';
|
|
1
2
|
import { ServiceConfiguration } from './classes.serviceconfiguration.js';
|
|
2
|
-
import { DockerContainer } from './classes.dockercontainer.js';
|
|
3
3
|
import { type TServiceName } from './classes.servicedatamarker.js';
|
|
4
|
+
import { type TServiceMigrationScope } from '../../dist_ts_migration/index.js';
|
|
4
5
|
import type { ContainerStatus } from './classes.dockercontainer.js';
|
|
5
6
|
import type { TServiceOptionSource } from './classes.serviceoptions.js';
|
|
6
7
|
export interface IServiceStatus {
|
|
@@ -18,7 +19,12 @@ export interface IServiceStatus {
|
|
|
18
19
|
authEnabled?: boolean;
|
|
19
20
|
/** MongoDB only: whether the auth mode is declared in committed config. */
|
|
20
21
|
authSource?: TServiceOptionSource;
|
|
22
|
+
/** ObjectStorage only: an unowned same-name container is a conflict, not managed state. */
|
|
23
|
+
ownership?: 'owned' | 'conflict' | 'absent';
|
|
24
|
+
managementUi?: string;
|
|
21
25
|
}
|
|
26
|
+
export type TServiceManagerOperation = 'auth' | 'clean' | 'compass' | 'config' | 'logs' | 'remove' | 'reconfigure' | 'restart' | 'start' | 'status' | 'stop';
|
|
27
|
+
export declare const getServiceManagerMigrationScopes: (operationArg: TServiceManagerOperation) => TServiceMigrationScope[];
|
|
22
28
|
export interface IServicesStatus {
|
|
23
29
|
project: {
|
|
24
30
|
name: string;
|
|
@@ -27,9 +33,14 @@ export interface IServicesStatus {
|
|
|
27
33
|
};
|
|
28
34
|
services: {
|
|
29
35
|
mongodb: IServiceStatus;
|
|
30
|
-
|
|
36
|
+
objectstorage: IServiceStatus;
|
|
31
37
|
elasticsearch: IServiceStatus;
|
|
32
38
|
};
|
|
39
|
+
legacy: {
|
|
40
|
+
minioContainer?: string;
|
|
41
|
+
minioDataDirectory: string;
|
|
42
|
+
minioDataExists: boolean;
|
|
43
|
+
};
|
|
33
44
|
totalDataBytes: number;
|
|
34
45
|
}
|
|
35
46
|
export declare const mongoServiceUlimits: {
|
|
@@ -38,33 +49,47 @@ export declare const mongoServiceUlimits: {
|
|
|
38
49
|
readonly hard: 65536;
|
|
39
50
|
};
|
|
40
51
|
};
|
|
41
|
-
export declare const
|
|
42
|
-
export interface
|
|
52
|
+
export declare const objectStorageReconciliationTimeoutMs = 30000;
|
|
53
|
+
export interface IObjectStorageReconciliationClock {
|
|
43
54
|
now(): number;
|
|
44
55
|
delay(millisecondsArg: number): Promise<void>;
|
|
45
56
|
}
|
|
46
|
-
export interface
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
export interface IObjectStorageBucketReconciliationOptions {
|
|
58
|
+
smartBucket: Pick<plugins.smartbucket.SmartBucket, 'checkReadiness' | 'close'> & {
|
|
59
|
+
storageClient: {
|
|
60
|
+
send(commandArg: plugins.s3.HeadBucketCommand | plugins.s3.CreateBucketCommand, optionsArg?: {
|
|
61
|
+
abortSignal?: AbortSignal;
|
|
62
|
+
}): Promise<unknown>;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
50
65
|
bucket: string;
|
|
51
|
-
/** Shared absolute deadline. Defaults to 30 seconds from this call. */
|
|
52
66
|
deadlineAt?: number;
|
|
53
|
-
clock?:
|
|
67
|
+
clock?: IObjectStorageReconciliationClock;
|
|
54
68
|
}
|
|
55
|
-
|
|
56
|
-
export declare const
|
|
69
|
+
export declare const objectStorageExpectedEntrypoint: string[];
|
|
70
|
+
export declare const objectStorageExpectedCommand: string[];
|
|
71
|
+
export declare const objectStorageExpectedHealthcheck: {
|
|
72
|
+
test: string[];
|
|
73
|
+
interval: number;
|
|
74
|
+
timeout: number;
|
|
75
|
+
startPeriod: number;
|
|
76
|
+
retries: number;
|
|
77
|
+
};
|
|
78
|
+
/** Create the configured bucket only after an authenticated 404, then verify by HEAD. */
|
|
79
|
+
export declare const reconcileObjectStorageBucket: (optionsArg: IObjectStorageBucketReconciliationOptions) => Promise<void>;
|
|
57
80
|
export declare class ServiceManager {
|
|
58
81
|
private config;
|
|
59
82
|
private docker;
|
|
60
83
|
private enabledServices;
|
|
61
84
|
private globalRegistry;
|
|
62
|
-
private
|
|
85
|
+
private objectStorageClock;
|
|
86
|
+
private fetchImplementation;
|
|
87
|
+
private smartBucketFactory;
|
|
63
88
|
constructor();
|
|
64
89
|
/**
|
|
65
90
|
* Initialize the service manager
|
|
66
91
|
*/
|
|
67
|
-
init(): Promise<void>;
|
|
92
|
+
init(operationArg: TServiceManagerOperation): Promise<void>;
|
|
68
93
|
/**
|
|
69
94
|
* Human phrasing for where the auth mode came from. A declared auth-off is
|
|
70
95
|
* committed to the repository and therefore affects everyone who clones it,
|
|
@@ -86,7 +111,7 @@ export declare class ServiceManager {
|
|
|
86
111
|
/**
|
|
87
112
|
* Check if a service is enabled
|
|
88
113
|
*/
|
|
89
|
-
|
|
114
|
+
isServiceEnabled(service: TServiceName): boolean;
|
|
90
115
|
/**
|
|
91
116
|
* Prepare a service's data directory: create it and record tool ownership.
|
|
92
117
|
*
|
|
@@ -94,6 +119,7 @@ export declare class ServiceManager {
|
|
|
94
119
|
* prove the directory is reclaimable instead of guessing from its path.
|
|
95
120
|
*/
|
|
96
121
|
private prepareDataDirectory;
|
|
122
|
+
private createDataDirectory;
|
|
97
123
|
/**
|
|
98
124
|
* Register this project with the global registry.
|
|
99
125
|
*
|
|
@@ -124,6 +150,8 @@ export declare class ServiceManager {
|
|
|
124
150
|
* (localhost:MONGODB_PORT) is reachable from host and container alike.
|
|
125
151
|
*/
|
|
126
152
|
startMongoDB(): Promise<void>;
|
|
153
|
+
private assertNoPendingDataDeletion;
|
|
154
|
+
private startMongoDBLocked;
|
|
127
155
|
/**
|
|
128
156
|
* Create the MongoDB container as a single-node replica set
|
|
129
157
|
*/
|
|
@@ -150,31 +178,42 @@ export declare class ServiceManager {
|
|
|
150
178
|
* Initiate the single-node replica set once mongod is reachable
|
|
151
179
|
*/
|
|
152
180
|
private ensureMongoReplicaSetInitiated;
|
|
153
|
-
private
|
|
154
|
-
private
|
|
155
|
-
private
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
private
|
|
181
|
+
private inspectObjectStorageContainer;
|
|
182
|
+
private inspectObjectStorageIdentity;
|
|
183
|
+
private discoverContainerIdByExactName;
|
|
184
|
+
private assertObjectStorageOwnership;
|
|
185
|
+
private revalidateObjectStorageContainer;
|
|
186
|
+
private objectStorageConfigurationMatches;
|
|
187
|
+
private assertNoSymlinkedObjectStoragePath;
|
|
188
|
+
private prepareObjectStorageDataDirectory;
|
|
189
|
+
private repairObjectStorageMarkerFromOwnedContainer;
|
|
190
|
+
private assertNoLegacyMinioResources;
|
|
191
|
+
/** Read-only preflight used before restart or reconfigure may stop anything. */
|
|
192
|
+
assertObjectStorageStartupAllowed(): Promise<void>;
|
|
193
|
+
private assertObjectStorageConfigurationSafe;
|
|
194
|
+
private waitForObjectStorageReadiness;
|
|
195
|
+
private createObjectStorageContainer;
|
|
196
|
+
/** Start or reconcile the canonical ObjectStorage service. */
|
|
197
|
+
startObjectStorage(): Promise<void>;
|
|
198
|
+
private startObjectStorageLocked;
|
|
162
199
|
/**
|
|
163
200
|
* Start Elasticsearch service
|
|
164
201
|
*/
|
|
165
202
|
startElasticsearch(): Promise<void>;
|
|
203
|
+
private startElasticsearchLocked;
|
|
166
204
|
/**
|
|
167
205
|
* Stop MongoDB service
|
|
168
206
|
*/
|
|
169
207
|
stopMongoDB(): Promise<void>;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
208
|
+
private stopMongoDBLocked;
|
|
209
|
+
/** Stop only an exactly owned canonical ObjectStorage container. */
|
|
210
|
+
stopObjectStorage(): Promise<void>;
|
|
211
|
+
private stopObjectStorageLocked;
|
|
174
212
|
/**
|
|
175
213
|
* Stop Elasticsearch service
|
|
176
214
|
*/
|
|
177
215
|
stopElasticsearch(): Promise<void>;
|
|
216
|
+
private stopElasticsearchLocked;
|
|
178
217
|
/**
|
|
179
218
|
* Collect service status as structured data.
|
|
180
219
|
*
|
|
@@ -210,6 +249,8 @@ export declare class ServiceManager {
|
|
|
210
249
|
* Remove containers
|
|
211
250
|
*/
|
|
212
251
|
removeContainers(): Promise<void>;
|
|
252
|
+
private removeContainersLocked;
|
|
253
|
+
private withProjectServiceLocks;
|
|
213
254
|
/**
|
|
214
255
|
* Clean data directories
|
|
215
256
|
*/
|
|
@@ -222,4 +263,5 @@ export declare class ServiceManager {
|
|
|
222
263
|
* Reconfigure services with new ports
|
|
223
264
|
*/
|
|
224
265
|
reconfigure(): Promise<void>;
|
|
266
|
+
private reconfigureLocked;
|
|
225
267
|
}
|