@fnndsc/stratus 0.0.0 → 0.2.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.
Files changed (134) hide show
  1. package/README.md +6 -1
  2. package/dist/args.d.ts +20 -6
  3. package/dist/args.js +45 -2
  4. package/dist/args.js.map +1 -1
  5. package/dist/backend.d.ts +35 -4
  6. package/dist/backend.js +77 -12
  7. package/dist/backend.js.map +1 -1
  8. package/dist/cloud/builder.d.ts +172 -0
  9. package/dist/cloud/builder.js +41 -0
  10. package/dist/cloud/builder.js.map +1 -0
  11. package/dist/cloud/driver.d.ts +149 -0
  12. package/dist/cloud/fake/builder.d.ts +147 -0
  13. package/dist/cloud/fake/builder.js +213 -0
  14. package/dist/cloud/fake/builder.js.map +1 -0
  15. package/dist/cloud/fake/driver.d.ts +73 -1
  16. package/dist/cloud/fake/driver.js +122 -0
  17. package/dist/cloud/fake/driver.js.map +1 -1
  18. package/dist/cloud/oci/api.d.ts +3 -2
  19. package/dist/cloud/oci/api.js +2 -0
  20. package/dist/cloud/oci/api.js.map +1 -1
  21. package/dist/cloud/oci/buildApi.d.ts +61 -0
  22. package/dist/cloud/oci/buildApi.js +132 -0
  23. package/dist/cloud/oci/buildApi.js.map +1 -0
  24. package/dist/cloud/oci/builder.d.ts +172 -0
  25. package/dist/cloud/oci/builder.js +370 -0
  26. package/dist/cloud/oci/builder.js.map +1 -0
  27. package/dist/cloud/oci/driver.d.ts +23 -2
  28. package/dist/cloud/oci/driver.js +107 -1
  29. package/dist/cloud/oci/driver.js.map +1 -1
  30. package/dist/cloud/oci/planRead.d.ts +38 -0
  31. package/dist/cloud/oci/planRead.js +67 -0
  32. package/dist/cloud/oci/planRead.js.map +1 -0
  33. package/dist/cloud/oci/prices.d.ts +22 -1
  34. package/dist/cloud/oci/prices.js +35 -0
  35. package/dist/cloud/oci/prices.js.map +1 -1
  36. package/dist/cloud/oci/resourceApi.d.ts +114 -0
  37. package/dist/cloud/oci/resourceApi.js +261 -0
  38. package/dist/cloud/oci/resourceApi.js.map +1 -0
  39. package/dist/cloud/oci/resourceMap.d.ts +44 -0
  40. package/dist/cloud/oci/resourceMap.js +70 -0
  41. package/dist/cloud/oci/resourceMap.js.map +1 -0
  42. package/dist/cloud/oci/rmApi.d.ts +74 -0
  43. package/dist/cloud/oci/rmApi.js +141 -0
  44. package/dist/cloud/oci/rmApi.js.map +1 -0
  45. package/dist/cloud/oci/stackVars.d.ts +49 -0
  46. package/dist/cloud/oci/stackVars.js +70 -0
  47. package/dist/cloud/oci/stackVars.js.map +1 -0
  48. package/dist/cluster/fakeKube.d.ts +43 -0
  49. package/dist/cluster/fakeKube.js +86 -0
  50. package/dist/cluster/fakeKube.js.map +1 -0
  51. package/dist/cluster/kube.d.ts +40 -0
  52. package/dist/cluster/kube.js +46 -0
  53. package/dist/cluster/kube.js.map +1 -0
  54. package/dist/cluster/kubeHttp.d.ts +16 -0
  55. package/dist/cluster/kubeHttp.js +86 -0
  56. package/dist/cluster/kubeHttp.js.map +1 -0
  57. package/dist/commands/build.d.ts +90 -0
  58. package/dist/commands/build.js +358 -0
  59. package/dist/commands/build.js.map +1 -0
  60. package/dist/commands/capacity.d.ts +37 -0
  61. package/dist/commands/capacity.js +93 -0
  62. package/dist/commands/capacity.js.map +1 -0
  63. package/dist/commands/domain.d.ts +45 -0
  64. package/dist/commands/domain.js +150 -0
  65. package/dist/commands/domain.js.map +1 -0
  66. package/dist/commands/spend.d.ts +22 -0
  67. package/dist/commands/spend.js +65 -0
  68. package/dist/commands/spend.js.map +1 -0
  69. package/dist/commands/teardown.d.ts +10 -0
  70. package/dist/commands/teardown.js +72 -0
  71. package/dist/commands/teardown.js.map +1 -0
  72. package/dist/commands/verify.d.ts +28 -0
  73. package/dist/commands/verify.js +98 -0
  74. package/dist/commands/verify.js.map +1 -0
  75. package/dist/domain/adopt.d.ts +60 -0
  76. package/dist/domain/adopt.js +143 -0
  77. package/dist/domain/adopt.js.map +1 -0
  78. package/dist/domain/sizing.d.ts +55 -0
  79. package/dist/domain/sizing.js +66 -0
  80. package/dist/domain/sizing.js.map +1 -0
  81. package/dist/domain/spec.d.ts +101 -0
  82. package/dist/domain/spec.js +191 -0
  83. package/dist/domain/spec.js.map +1 -0
  84. package/dist/domain/spend.d.ts +84 -0
  85. package/dist/domain/spend.js +109 -0
  86. package/dist/domain/spend.js.map +1 -0
  87. package/dist/domain/state.d.ts +149 -0
  88. package/dist/domain/state.js +182 -0
  89. package/dist/domain/state.js.map +1 -0
  90. package/dist/domain/steps.d.ts +82 -0
  91. package/dist/domain/steps.js +311 -0
  92. package/dist/domain/steps.js.map +1 -0
  93. package/dist/domain/teardown.d.ts +38 -0
  94. package/dist/domain/teardown.js +48 -0
  95. package/dist/domain/teardown.js.map +1 -0
  96. package/dist/domain/verify.d.ts +68 -0
  97. package/dist/domain/verify.js +216 -0
  98. package/dist/domain/verify.js.map +1 -0
  99. package/dist/domain/view.d.ts +24 -0
  100. package/dist/domain/view.js +38 -0
  101. package/dist/domain/view.js.map +1 -0
  102. package/dist/domains/harborOci.d.ts +75 -0
  103. package/dist/domains/harborOci.js +165 -0
  104. package/dist/domains/harborOci.js.map +1 -0
  105. package/dist/index.d.ts +7 -0
  106. package/dist/index.js +6 -0
  107. package/dist/index.js.map +1 -1
  108. package/dist/installer/assisted.d.ts +97 -0
  109. package/dist/installer/assisted.js +171 -0
  110. package/dist/installer/assisted.js.map +1 -0
  111. package/dist/installer/installer.d.ts +86 -0
  112. package/dist/installer/installer.js +15 -0
  113. package/dist/installer/installer.js.map +1 -0
  114. package/dist/prompt.d.ts +33 -0
  115. package/dist/prompt.js +46 -0
  116. package/dist/prompt.js.map +1 -0
  117. package/dist/session.d.ts +2 -0
  118. package/dist/session.js +4 -0
  119. package/dist/session.js.map +1 -1
  120. package/dist/stratus.js +75 -3
  121. package/dist/stratus.js.map +1 -1
  122. package/dist/vfs/domains.d.ts +39 -0
  123. package/dist/vfs/domains.js +128 -0
  124. package/dist/vfs/domains.js.map +1 -0
  125. package/dist/vfs/look.d.ts +10 -0
  126. package/dist/vfs/look.js +43 -8
  127. package/dist/vfs/look.js.map +1 -1
  128. package/dist/vfs/resources.d.ts +136 -0
  129. package/dist/vfs/resources.js +325 -0
  130. package/dist/vfs/resources.js.map +1 -0
  131. package/dist/vfs/tenancy.d.ts +15 -2
  132. package/dist/vfs/tenancy.js +53 -17
  133. package/dist/vfs/tenancy.js.map +1 -1
  134. package/package.json +14 -7
@@ -0,0 +1,48 @@
1
+ /** The CSI driver whose volumes are the cloud's block volumes. */
2
+ export const OCI_BLOCK_DRIVER = 'blockvolume.csi.oraclecloud.com';
3
+ /**
4
+ * The block volumes a cluster's claims hold, from its PersistentVolumes.
5
+ *
6
+ * @param kube - The cluster.
7
+ * @returns The volumes' ids.
8
+ */
9
+ export async function clusterVolumes_read(kube) {
10
+ const answer = await kube.json_get('/api/v1/persistentvolumes');
11
+ return (answer.items ?? [])
12
+ .filter((volume) => volume.spec?.csi?.driver === OCI_BLOCK_DRIVER && typeof volume.spec.csi.volumeHandle === 'string')
13
+ .map((volume) => volume.spec?.csi?.volumeHandle);
14
+ }
15
+ /**
16
+ * The job that tears a domain down.
17
+ *
18
+ * @param store - The domains.
19
+ * @param builder - The cloud's build half.
20
+ * @param installer - The installer, or null when none is reachable.
21
+ * @param name - The domain.
22
+ * @param volumeIds - The cluster's own volumes, read before.
23
+ * @returns The job's work.
24
+ */
25
+ export function teardownRun_make(store, builder, installer, name, volumeIds) {
26
+ return async (context) => {
27
+ const record = store.record_read(name);
28
+ if (record === null)
29
+ throw new Error(`${name}: no such domain`);
30
+ if (builder.teardown_run === undefined)
31
+ throw new Error(`${builder.id}: this cloud cannot tear a domain down`);
32
+ const gone = await builder.teardown_run({
33
+ domain: name, region: record.region, compartmentId: record.compartmentId ?? '', baseDomain: record.baseDomain, volumeIds,
34
+ ...(record.ids['stackRef'] !== undefined ? { stackRef: record.ids['stackRef'] } : {}),
35
+ ...(record.ids['isoObject'] !== undefined ? { isoObject: record.ids['isoObject'] } : {}),
36
+ ...(record.ids['isoLinkId'] !== undefined ? { isoLinkId: record.ids['isoLinkId'] } : {}),
37
+ }, { log: (line) => context.log_write(line), signal: context.signal });
38
+ if (context.signal.aborted)
39
+ return;
40
+ if (installer !== null && record.ids['clusterId'] !== undefined && record.ids['infraEnvId'] !== undefined) {
41
+ await installer.cluster_delete({ clusterId: record.ids['clusterId'], infraEnvId: record.ids['infraEnvId'] });
42
+ gone.push('the installer\'s cluster and infra-env');
43
+ }
44
+ store.record_update(name, (current) => { current.gone = new Date().toISOString(); });
45
+ context.log_write(`gone: ${gone.join('; ')}`);
46
+ };
47
+ }
48
+ //# sourceMappingURL=teardown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"teardown.js","sourceRoot":"","sources":["../../src/domain/teardown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @file `verify`: a domain's cluster is healthy and does what ChRIS needs,
3
+ * by `harbor-oci`'s ten checks, through the Kubernetes API and DNS rather
4
+ * than `oc` and `dig` (docs/stratus.adoc, D3, D7).
5
+ *
6
+ * Nine checks only read. The block-volume probe writes (a namespace with a
7
+ * 50 GiB claim and a pod, deleted again), so it runs only under the `tasks`
8
+ * tier and, without it, says so by name instead (decided 2026-10-22). Each
9
+ * check is independent: a failure is a failed check, never the end of the
10
+ * rest.
11
+ *
12
+ * @module
13
+ */
14
+ import type { KubeApi } from '../cluster/kube.js';
15
+ /** The storage class ChRIS's claims use. */
16
+ export declare const STORAGE_CLASS: string;
17
+ /** The cores one ChRIS plugin job asks for. */
18
+ export declare const PLUGIN_CPU_CORES: number;
19
+ /** The namespace the volume probe makes and deletes. */
20
+ export declare const PROBE_NAMESPACE: string;
21
+ /** One check's answer. */
22
+ export interface VerifyCheck {
23
+ readonly name: string;
24
+ /** True passed, false failed, null not run. */
25
+ readonly ok: boolean | null;
26
+ readonly detail: string;
27
+ /** Whether it only reads, or writes. */
28
+ readonly how: 'reads' | 'writes';
29
+ }
30
+ /** What every check reads. */
31
+ export interface VerifyContext {
32
+ readonly kube: KubeApi;
33
+ /** The addresses a name has, from a public resolver. */
34
+ readonly resolve: (name: string) => Promise<string[]>;
35
+ /** The status a URL answers with, trusting a CA. */
36
+ readonly https_status: (url: string, ca: string | null) => Promise<number>;
37
+ /** The cluster's name and DNS zone. */
38
+ readonly domain: string;
39
+ readonly baseDomain: string;
40
+ /** The shape every node should be, or null when not known. */
41
+ readonly shape: string | null;
42
+ readonly expectedNodes: number;
43
+ /** The load balancers' addresses the build recorded. */
44
+ readonly addresses: {
45
+ readonly api?: string;
46
+ readonly apiInt?: string;
47
+ readonly apps?: string;
48
+ };
49
+ /** Whether the probe may write (the `tasks` tier). */
50
+ readonly probe: boolean;
51
+ readonly probeTimeoutMs: number;
52
+ readonly pollMs: number;
53
+ readonly signal?: AbortSignal;
54
+ }
55
+ /**
56
+ * A CPU quantity in cores: `500m` is a half, `2` is two.
57
+ *
58
+ * @param quantity - The quantity.
59
+ * @returns Cores.
60
+ */
61
+ export declare function cpuQuantity_parse(quantity: string): number;
62
+ /**
63
+ * Runs every check, in order.
64
+ *
65
+ * @param context - What they read.
66
+ * @returns Each check's answer.
67
+ */
68
+ export declare function verify_run(context: VerifyContext): Promise<VerifyCheck[]>;
@@ -0,0 +1,216 @@
1
+ /** The storage class ChRIS's claims use. */
2
+ export const STORAGE_CLASS = 'oci-bv';
3
+ /** The annotation that makes a storage class the default. */
4
+ const DEFAULT_CLASS_ANNOTATION = 'storageclass.kubernetes.io/is-default-class';
5
+ /** The cores one ChRIS plugin job asks for. */
6
+ export const PLUGIN_CPU_CORES = 2;
7
+ /** The namespace the volume probe makes and deletes. */
8
+ export const PROBE_NAMESPACE = 'stratus-verify';
9
+ /** What the probe writes and reads back. */
10
+ const PROBE_TEXT = 'stratus';
11
+ /**
12
+ * A resource's conditions, by type.
13
+ *
14
+ * @param conditions - Its conditions.
15
+ * @returns Type to status.
16
+ */
17
+ function conditions_of(conditions) {
18
+ return Object.fromEntries((conditions ?? []).map((condition) => [condition.type, condition.status]));
19
+ }
20
+ /**
21
+ * A CPU quantity in cores: `500m` is a half, `2` is two.
22
+ *
23
+ * @param quantity - The quantity.
24
+ * @returns Cores.
25
+ */
26
+ export function cpuQuantity_parse(quantity) {
27
+ return quantity.endsWith('m') ? Number(quantity.slice(0, -1)) / 1000 : Number(quantity);
28
+ }
29
+ /**
30
+ * Waits, unless stopped.
31
+ *
32
+ * @param ms - How long.
33
+ * @param signal - Stops it.
34
+ */
35
+ function wait(ms, signal) {
36
+ if (ms <= 0 || signal?.aborted === true)
37
+ return Promise.resolve();
38
+ return new Promise((resolve) => {
39
+ const timer = setTimeout(resolve, ms);
40
+ signal?.addEventListener('abort', () => { clearTimeout(timer); resolve(); }, { once: true });
41
+ });
42
+ }
43
+ /** The checks, in `harbor-oci`'s order. */
44
+ const CHECKS = [
45
+ {
46
+ name: 'API', how: 'reads',
47
+ run: async (context) => {
48
+ const answer = (await context.kube.text_get('/readyz')).trim();
49
+ return { ok: answer === 'ok', detail: `/readyz ${answer}` };
50
+ },
51
+ },
52
+ {
53
+ name: 'cluster version', how: 'reads',
54
+ run: async (context) => {
55
+ const version = await context.kube.json_get('/apis/config.openshift.io/v1/clusterversions/version');
56
+ const conditions = conditions_of(version.status?.conditions);
57
+ return { ok: conditions['Available'] === 'True' && conditions['Failing'] !== 'True', detail: `${version.status?.desired?.version ?? '?'}, Available=${conditions['Available'] ?? '?'}` };
58
+ },
59
+ },
60
+ {
61
+ name: 'nodes', how: 'reads',
62
+ run: async (context) => {
63
+ const nodes = (await context.kube.json_get('/api/v1/nodes')).items ?? [];
64
+ const ready = nodes.filter((node) => conditions_of(node.status?.conditions)['Ready'] === 'True').length;
65
+ return { ok: nodes.length === context.expectedNodes && ready === context.expectedNodes, detail: `${ready}/${context.expectedNodes} Ready` };
66
+ },
67
+ },
68
+ {
69
+ name: 'OCI CCM', how: 'reads',
70
+ run: async (context) => {
71
+ const nodes = (await context.kube.json_get('/api/v1/nodes')).items ?? [];
72
+ const problems = [];
73
+ const zones = new Set();
74
+ for (const node of nodes) {
75
+ const labels = node.metadata.labels ?? {};
76
+ if (!(node.spec?.providerID ?? '').startsWith('oci://'))
77
+ problems.push(`${node.metadata.name} has no oci:// providerID`);
78
+ if (context.shape !== null && labels['node.kubernetes.io/instance-type'] !== context.shape)
79
+ problems.push(`${node.metadata.name} is ${labels['node.kubernetes.io/instance-type'] ?? '?'}`);
80
+ zones.add(labels['topology.kubernetes.io/zone'] ?? '?');
81
+ }
82
+ return { ok: problems.length === 0, detail: problems.length > 0 ? problems.join('; ') : `${nodes.length} nodes over ${zones.size} zones, providerIDs set` };
83
+ },
84
+ },
85
+ {
86
+ name: 'operators', how: 'reads',
87
+ run: async (context) => {
88
+ const operators = (await context.kube.json_get('/apis/config.openshift.io/v1/clusteroperators')).items ?? [];
89
+ const unhealthy = operators.filter((operator) => {
90
+ const conditions = conditions_of(operator.status?.conditions);
91
+ return conditions['Available'] !== 'True' || conditions['Progressing'] !== 'False' || conditions['Degraded'] !== 'False';
92
+ }).map((operator) => operator.metadata.name);
93
+ return { ok: unhealthy.length === 0, detail: `${operators.length} operators, ${unhealthy.length === 0 ? 'all available, none degraded' : `not settled: ${unhealthy.join(', ')}`}` };
94
+ },
95
+ },
96
+ {
97
+ name: 'storage class', how: 'reads',
98
+ run: async (context) => {
99
+ const classes = (await context.kube.json_get('/apis/storage.k8s.io/v1/storageclasses')).items ?? [];
100
+ const defaults = classes.filter((entry) => entry.metadata.annotations?.[DEFAULT_CLASS_ANNOTATION] === 'true').map((entry) => entry.metadata.name);
101
+ return { ok: defaults.length === 1 && defaults[0] === STORAGE_CLASS, detail: `default: ${defaults.join(', ') || 'none'}` };
102
+ },
103
+ },
104
+ {
105
+ name: 'DNS', how: 'reads',
106
+ run: async (context) => {
107
+ const cluster = `${context.domain}.${context.baseDomain}`;
108
+ const wanted = [
109
+ [`api.${cluster}`, `api.${cluster}`, context.addresses.api],
110
+ [`api-int.${cluster}`, `api-int.${cluster}`, context.addresses.apiInt],
111
+ [`*.apps.${cluster}`, `verify.apps.${cluster}`, context.addresses.apps],
112
+ ];
113
+ const problems = [];
114
+ for (const [label, name, address] of wanted) {
115
+ if (address === undefined) {
116
+ problems.push(`${label}: no address recorded`);
117
+ continue;
118
+ }
119
+ const answer = await context.resolve(name).catch(() => []);
120
+ if (!answer.includes(address))
121
+ problems.push(`${label} -> ${answer.join(' ') || 'nothing'} (wanted ${address})`);
122
+ }
123
+ return { ok: problems.length === 0, detail: problems.join('; ') || '3 records answer from a public resolver' };
124
+ },
125
+ },
126
+ {
127
+ name: 'console', how: 'reads',
128
+ run: async (context) => {
129
+ const secret = await context.kube.json_get('/api/v1/namespaces/openshift-ingress-operator/secrets/router-ca');
130
+ const ca = secret.data?.['tls.crt'] === undefined ? null : Buffer.from(secret.data['tls.crt'], 'base64').toString('utf-8');
131
+ const url = `https://console-openshift-console.apps.${context.domain}.${context.baseDomain}/`;
132
+ const status = await context.https_status(url, ca);
133
+ return { ok: status === 200, detail: `${url} HTTP ${status}` };
134
+ },
135
+ },
136
+ {
137
+ name: 'CPU headroom', how: 'reads',
138
+ run: async (context) => {
139
+ const nodes = (await context.kube.json_get('/api/v1/nodes')).items ?? [];
140
+ const pods = (await context.kube.json_get('/api/v1/pods')).items ?? [];
141
+ const requested = new Map();
142
+ for (const pod of pods) {
143
+ if (pod.status?.phase === 'Succeeded' || pod.status?.phase === 'Failed' || pod.spec?.nodeName === undefined)
144
+ continue;
145
+ for (const container of pod.spec.containers ?? []) {
146
+ const cpu = container.resources?.requests?.cpu;
147
+ if (cpu !== undefined)
148
+ requested.set(pod.spec.nodeName, (requested.get(pod.spec.nodeName) ?? 0) + cpuQuantity_parse(cpu));
149
+ }
150
+ }
151
+ const free = nodes.map((node) => cpuQuantity_parse(node.status?.allocatable?.cpu ?? '0') - (requested.get(node.metadata.name) ?? 0));
152
+ return { ok: Math.max(0, ...free) >= PLUGIN_CPU_CORES, detail: `unrequested cores: ${free.map((cores) => cores.toFixed(1)).join(' / ')} (a plugin job asks ${PLUGIN_CPU_CORES})` };
153
+ },
154
+ },
155
+ {
156
+ name: 'block volume', how: 'writes',
157
+ run: async (context) => {
158
+ if (!context.probe)
159
+ return { ok: null, detail: `not run: it makes a 50 GiB ${STORAGE_CLASS} claim and a pod, which needs the tasks tier` };
160
+ const ns = `/api/v1/namespaces/${PROBE_NAMESPACE}`;
161
+ await context.kube.delete(ns).catch(() => undefined);
162
+ await context.kube.json_post('/api/v1/namespaces', { apiVersion: 'v1', kind: 'Namespace', metadata: { name: PROBE_NAMESPACE } });
163
+ const started = Date.now();
164
+ let phase = '';
165
+ let output = '';
166
+ try {
167
+ await context.kube.json_post(`${ns}/persistentvolumeclaims`, { apiVersion: 'v1', kind: 'PersistentVolumeClaim', metadata: { name: 'probe' }, spec: { accessModes: ['ReadWriteOnce'], resources: { requests: { storage: '50Gi' } } } });
168
+ await context.kube.json_post(`${ns}/pods`, {
169
+ apiVersion: 'v1', kind: 'Pod', metadata: { name: 'probe' },
170
+ spec: {
171
+ restartPolicy: 'Never',
172
+ containers: [{
173
+ name: 'probe', image: 'registry.access.redhat.com/ubi9/ubi-minimal',
174
+ command: ['sh', '-c', `echo ${PROBE_TEXT} > /data/probe && cat /data/probe`],
175
+ volumeMounts: [{ name: 'data', mountPath: '/data' }],
176
+ securityContext: { allowPrivilegeEscalation: false, capabilities: { drop: ['ALL'] }, runAsNonRoot: true, seccompProfile: { type: 'RuntimeDefault' } },
177
+ }],
178
+ volumes: [{ name: 'data', persistentVolumeClaim: { claimName: 'probe' } }],
179
+ },
180
+ });
181
+ while (Date.now() - started < context.probeTimeoutMs && context.signal?.aborted !== true) {
182
+ phase = (await context.kube.json_get(`${ns}/pods/probe`)).status?.phase ?? '';
183
+ if (phase === 'Succeeded' || phase === 'Failed')
184
+ break;
185
+ await wait(context.pollMs, context.signal);
186
+ }
187
+ if (phase === 'Succeeded')
188
+ output = (await context.kube.text_get(`${ns}/pods/probe/log`)).trim();
189
+ }
190
+ finally {
191
+ await context.kube.delete(ns).catch(() => undefined);
192
+ }
193
+ return { ok: phase === 'Succeeded' && output === PROBE_TEXT, detail: `50Gi ${STORAGE_CLASS} pod ${phase || 'timed out'}, read back '${output}', ${Math.round((Date.now() - started) / 1000)}s` };
194
+ },
195
+ },
196
+ ];
197
+ /**
198
+ * Runs every check, in order.
199
+ *
200
+ * @param context - What they read.
201
+ * @returns Each check's answer.
202
+ */
203
+ export async function verify_run(context) {
204
+ const results = [];
205
+ for (const check of CHECKS) {
206
+ try {
207
+ const answer = await check.run(context);
208
+ results.push({ name: check.name, how: check.how, ...answer });
209
+ }
210
+ catch (error) {
211
+ results.push({ name: check.name, how: check.how, ok: false, detail: error instanceof Error ? error.message : String(error) });
212
+ }
213
+ }
214
+ return results;
215
+ }
216
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/domain/verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @file A domain this daemon builds, seen as every domain is seen: the same
3
+ * shape the tree, `domain status` and the DOMAINS tile read for a domain
4
+ * read from a `harbor-oci` checkout, from its own state on the host.
5
+ *
6
+ * @module
7
+ */
8
+ import type { HarborDomain, StepState } from '../domains/harborOci.js';
9
+ import type { DomainRecord, DomainStore } from './state.js';
10
+ /**
11
+ * A built domain's steps, numbered in build order.
12
+ *
13
+ * @param record - Its state.
14
+ * @returns Every step, with its state and what it rests on.
15
+ */
16
+ export declare function builtSteps_of(record: DomainRecord): StepState[];
17
+ /**
18
+ * A built domain, read now.
19
+ *
20
+ * @param store - The domains this daemon builds.
21
+ * @param name - The domain.
22
+ * @returns It, or null when none of that name is kept.
23
+ */
24
+ export declare function builtDomain_read(store: DomainStore, name: string): HarborDomain | null;
@@ -0,0 +1,38 @@
1
+ import { BUILD_STEPS, STEPS_WRITTEN } from './steps.js';
2
+ /**
3
+ * A built domain's steps, numbered in build order.
4
+ *
5
+ * @param record - Its state.
6
+ * @returns Every step, with its state and what it rests on.
7
+ */
8
+ export function builtSteps_of(record) {
9
+ return BUILD_STEPS.map((step, index) => {
10
+ const kept = record.steps[step];
11
+ const evidence = kept?.note ?? (STEPS_WRITTEN.includes(step) ? 'not run yet' : 'not a step this session has yet');
12
+ return { folder: `${String(index + 1).padStart(2, '0')}-${step}`, name: step, state: kept?.state ?? 'not done', evidence };
13
+ });
14
+ }
15
+ /**
16
+ * A built domain, read now.
17
+ *
18
+ * @param store - The domains this daemon builds.
19
+ * @param name - The domain.
20
+ * @returns It, or null when none of that name is kept.
21
+ */
22
+ export function builtDomain_read(store, name) {
23
+ const record = store.record_read(name);
24
+ if (record === null)
25
+ return null;
26
+ return {
27
+ name,
28
+ root: store.folder_of(name),
29
+ spec: store.spec_read(name)?.text ?? null,
30
+ settings: { CLUSTER_NAME: name, BASE_DOMAIN: record.baseDomain, OCI_REGION: record.region, ...(record.compartmentId !== undefined ? { OCI_COMPARTMENT_OCID: record.compartmentId } : {}) },
31
+ state: { ...record },
32
+ steps: builtSteps_of(record),
33
+ secrets: store.secrets_list(name),
34
+ cluster: `${name}.${record.baseDomain}`,
35
+ origin: 'built',
36
+ };
37
+ }
38
+ //# sourceMappingURL=view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.js","sourceRoot":"","sources":["../../src/domain/view.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGxD;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,MAAoB;IAChD,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,IAAY,EAAE,KAAa,EAAa,EAAE;QAChE,MAAM,IAAI,GAA2B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACxD,MAAM,QAAQ,GAAW,IAAI,EAAE,IAAI,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC;QAC1H,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,UAAU,EAAE,QAAQ,EAAE,CAAC;IAC7H,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAkB,EAAE,IAAY;IAC/D,MAAM,MAAM,GAAwB,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAC5D,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,OAAO;QACL,IAAI;QACJ,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC;QAC3B,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,IAAI;QACzC,QAAQ,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,oBAAoB,EAAE,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;QAC1L,KAAK,EAAE,EAAE,GAAG,MAAM,EAAE;QACpB,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC;QAC5B,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC;QACjC,OAAO,EAAE,GAAG,IAAI,IAAI,MAAM,CAAC,UAAU,EAAE;QACvC,MAAM,EAAE,OAAO;KAChB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,75 @@
1
+ /** The build's steps, in the order `just install` runs them. */
2
+ export declare const HARBOR_STEPS: ReadonlyArray<string>;
3
+ /** Where one step stands. */
4
+ export interface StepState {
5
+ /** Its folder name, numbered in build order (`05-infra-apply`). */
6
+ readonly folder: string;
7
+ readonly name: string;
8
+ /** `done`, `not done`, `expired`, or `unknown` when the host keeps nothing to tell. */
9
+ readonly state: string;
10
+ /** What the state rests on, in a line. */
11
+ readonly evidence: string;
12
+ }
13
+ /** A secret the domain holds on the host. */
14
+ export interface DomainSecret {
15
+ readonly name: string;
16
+ /** Where it is on the host; the only thing about it a surface is told. */
17
+ readonly hostPath: string;
18
+ }
19
+ /** A domain read from a `harbor-oci` checkout. */
20
+ export interface HarborDomain {
21
+ readonly name: string;
22
+ /** The checkout. */
23
+ readonly root: string;
24
+ /** `spec.yaml` as written, or null when there is none. */
25
+ readonly spec: string | null;
26
+ /** The shown settings, by key. */
27
+ readonly settings: Readonly<Record<string, string>>;
28
+ /** `state/harbor.json` with its secrets withheld, or null when there is none. */
29
+ readonly state: Readonly<Record<string, unknown>> | null;
30
+ /** Every step, in build order. */
31
+ readonly steps: ReadonlyArray<StepState>;
32
+ /** The credential files in `state/auth/`. */
33
+ readonly secrets: ReadonlyArray<DomainSecret>;
34
+ /** The cluster's DNS name, `<CLUSTER_NAME>.<BASE_DOMAIN>`, or null. */
35
+ readonly cluster: string | null;
36
+ /** Where it comes from: a `harbor-oci` checkout read, or built by this daemon (absent: a checkout). */
37
+ readonly origin?: 'checkout' | 'built';
38
+ }
39
+ /** Where a domain is read from: its name and its checkout. */
40
+ export interface DomainSource {
41
+ readonly name: string;
42
+ readonly root: string;
43
+ }
44
+ /**
45
+ * Reads `KEY=value` lines; comments, blanks and quotes handled as a shell
46
+ * `.env` writes them.
47
+ *
48
+ * @param text - The file's text.
49
+ * @returns The values, by key.
50
+ */
51
+ export declare function envFile_parse(text: string): Record<string, string>;
52
+ /**
53
+ * Where each step stands, from the evidence the checkout keeps.
54
+ *
55
+ * @param root - The checkout.
56
+ * @param state - The state document as read (secrets withheld does not matter here).
57
+ * @param now - The clock.
58
+ * @returns One state per step, in build order.
59
+ */
60
+ export declare function steps_read(root: string, state: Readonly<Record<string, unknown>> | null, now?: Date): StepState[];
61
+ /**
62
+ * Reads a domain from its checkout.
63
+ *
64
+ * @param source - The domain's name and checkout.
65
+ * @param now - The clock, for the ISO link's expiry.
66
+ * @returns The domain.
67
+ */
68
+ export declare function harborDomain_read(source: DomainSource, now?: Date): HarborDomain;
69
+ /**
70
+ * The step a domain last finished, in build order; null when none is done.
71
+ *
72
+ * @param domain - The domain.
73
+ * @returns The step.
74
+ */
75
+ export declare function lastDone_of(domain: HarborDomain): StepState | null;