@ankhorage/kubernetes 0.1.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.
- package/README.md +6 -6
- package/dist/features/workload-reconciliation/application/use-cases/createKubernetesController.d.ts +13 -0
- package/dist/features/workload-reconciliation/application/use-cases/createKubernetesController.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/createKubernetesController.js +130 -0
- package/dist/features/workload-reconciliation/application/use-cases/createKubernetesController.js.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/createKubernetesExposure.d.ts +12 -0
- package/dist/features/workload-reconciliation/application/use-cases/createKubernetesExposure.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/createKubernetesExposure.js +89 -0
- package/dist/features/workload-reconciliation/application/use-cases/createKubernetesExposure.js.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/createKubernetesPrerequisites.d.ts +18 -0
- package/dist/features/workload-reconciliation/application/use-cases/createKubernetesPrerequisites.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/createKubernetesPrerequisites.js +98 -0
- package/dist/features/workload-reconciliation/application/use-cases/createKubernetesPrerequisites.js.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/getKubernetesOutputsAsync.d.ts +5 -0
- package/dist/features/workload-reconciliation/application/use-cases/getKubernetesOutputsAsync.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/getKubernetesOutputsAsync.js +33 -0
- package/dist/features/workload-reconciliation/application/use-cases/getKubernetesOutputsAsync.js.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/getKubernetesStatusAsync.d.ts +5 -0
- package/dist/features/workload-reconciliation/application/use-cases/getKubernetesStatusAsync.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/getKubernetesStatusAsync.js +35 -0
- package/dist/features/workload-reconciliation/application/use-cases/getKubernetesStatusAsync.js.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/materializeKubernetesSecretsAsync.d.ts +6 -0
- package/dist/features/workload-reconciliation/application/use-cases/materializeKubernetesSecretsAsync.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/materializeKubernetesSecretsAsync.js +32 -0
- package/dist/features/workload-reconciliation/application/use-cases/materializeKubernetesSecretsAsync.js.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/planKubernetesResourcesAsync.d.ts +5 -0
- package/dist/features/workload-reconciliation/application/use-cases/planKubernetesResourcesAsync.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/planKubernetesResourcesAsync.js +9 -0
- package/dist/features/workload-reconciliation/application/use-cases/planKubernetesResourcesAsync.js.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/prepareKubernetesChangesAsync.d.ts +6 -0
- package/dist/features/workload-reconciliation/application/use-cases/prepareKubernetesChangesAsync.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/prepareKubernetesChangesAsync.js +84 -0
- package/dist/features/workload-reconciliation/application/use-cases/prepareKubernetesChangesAsync.js.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/projectKubernetesResourcesAsync.d.ts +11 -0
- package/dist/features/workload-reconciliation/application/use-cases/projectKubernetesResourcesAsync.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/projectKubernetesResourcesAsync.js +53 -0
- package/dist/features/workload-reconciliation/application/use-cases/projectKubernetesResourcesAsync.js.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/projectKubernetesWorkload.d.ts +12 -0
- package/dist/features/workload-reconciliation/application/use-cases/projectKubernetesWorkload.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/projectKubernetesWorkload.js +45 -0
- package/dist/features/workload-reconciliation/application/use-cases/projectKubernetesWorkload.js.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/reconcileKubernetesResourcesAsync.d.ts +5 -0
- package/dist/features/workload-reconciliation/application/use-cases/reconcileKubernetesResourcesAsync.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/reconcileKubernetesResourcesAsync.js +51 -0
- package/dist/features/workload-reconciliation/application/use-cases/reconcileKubernetesResourcesAsync.js.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/removeKubernetesResourcesAsync.d.ts +5 -0
- package/dist/features/workload-reconciliation/application/use-cases/removeKubernetesResourcesAsync.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/removeKubernetesResourcesAsync.js +75 -0
- package/dist/features/workload-reconciliation/application/use-cases/removeKubernetesResourcesAsync.js.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/resolveKubernetesWorkloadValues.d.ts +5 -0
- package/dist/features/workload-reconciliation/application/use-cases/resolveKubernetesWorkloadValues.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/resolveKubernetesWorkloadValues.js +45 -0
- package/dist/features/workload-reconciliation/application/use-cases/resolveKubernetesWorkloadValues.js.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/validateKubernetesWorkloads.d.ts +4 -0
- package/dist/features/workload-reconciliation/application/use-cases/validateKubernetesWorkloads.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/validateKubernetesWorkloads.js +26 -0
- package/dist/features/workload-reconciliation/application/use-cases/validateKubernetesWorkloads.js.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/waitForKubernetesReadinessAsync.d.ts +5 -0
- package/dist/features/workload-reconciliation/application/use-cases/waitForKubernetesReadinessAsync.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/application/use-cases/waitForKubernetesReadinessAsync.js +56 -0
- package/dist/features/workload-reconciliation/application/use-cases/waitForKubernetesReadinessAsync.js.map +1 -0
- package/dist/features/workload-reconciliation/composition/createKubernetesDriver.d.ts +4 -4
- package/dist/features/workload-reconciliation/composition/createKubernetesDriver.d.ts.map +1 -1
- package/dist/features/workload-reconciliation/composition/createKubernetesDriver.js +20 -4
- package/dist/features/workload-reconciliation/composition/createKubernetesDriver.js.map +1 -1
- package/dist/features/workload-reconciliation/constants.d.ts +14 -0
- package/dist/features/workload-reconciliation/constants.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/constants.js +14 -0
- package/dist/features/workload-reconciliation/constants.js.map +1 -0
- package/dist/features/workload-reconciliation/utils/areKubernetesResourcesEquivalent.d.ts +4 -0
- package/dist/features/workload-reconciliation/utils/areKubernetesResourcesEquivalent.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/utils/areKubernetesResourcesEquivalent.js +41 -0
- package/dist/features/workload-reconciliation/utils/areKubernetesResourcesEquivalent.js.map +1 -0
- package/dist/features/workload-reconciliation/utils/createKubernetesDesiredResource.d.ts +14 -0
- package/dist/features/workload-reconciliation/utils/createKubernetesDesiredResource.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/utils/createKubernetesDesiredResource.js +45 -0
- package/dist/features/workload-reconciliation/utils/createKubernetesDesiredResource.js.map +1 -0
- package/dist/features/workload-reconciliation/utils/createKubernetesIdentity.d.ts +5 -0
- package/dist/features/workload-reconciliation/utils/createKubernetesIdentity.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/utils/createKubernetesIdentity.js +10 -0
- package/dist/features/workload-reconciliation/utils/createKubernetesIdentity.js.map +1 -0
- package/dist/features/workload-reconciliation/utils/getKubernetesOwnershipQuery.d.ts +5 -0
- package/dist/features/workload-reconciliation/utils/getKubernetesOwnershipQuery.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/utils/getKubernetesOwnershipQuery.js +16 -0
- package/dist/features/workload-reconciliation/utils/getKubernetesOwnershipQuery.js.map +1 -0
- package/dist/features/workload-reconciliation/utils/getKubernetesResourceKey.d.ts +4 -0
- package/dist/features/workload-reconciliation/utils/getKubernetesResourceKey.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/utils/getKubernetesResourceKey.js +5 -0
- package/dist/features/workload-reconciliation/utils/getKubernetesResourceKey.js.map +1 -0
- package/dist/features/workload-reconciliation/utils/getKubernetesResourceReference.d.ts +4 -0
- package/dist/features/workload-reconciliation/utils/getKubernetesResourceReference.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/utils/getKubernetesResourceReference.js +12 -0
- package/dist/features/workload-reconciliation/utils/getKubernetesResourceReference.js.map +1 -0
- package/dist/features/workload-reconciliation/utils/readKubernetesOwnedResource.d.ts +6 -0
- package/dist/features/workload-reconciliation/utils/readKubernetesOwnedResource.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/utils/readKubernetesOwnedResource.js +49 -0
- package/dist/features/workload-reconciliation/utils/readKubernetesOwnedResource.js.map +1 -0
- package/dist/features/workload-reconciliation/utils/sortKubernetesResourcesForRemoval.d.ts +9 -0
- package/dist/features/workload-reconciliation/utils/sortKubernetesResourcesForRemoval.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/utils/sortKubernetesResourcesForRemoval.js +21 -0
- package/dist/features/workload-reconciliation/utils/sortKubernetesResourcesForRemoval.js.map +1 -0
- package/dist/features/workload-reconciliation/utils/toKubernetesName.d.ts +3 -0
- package/dist/features/workload-reconciliation/utils/toKubernetesName.d.ts.map +1 -0
- package/dist/features/workload-reconciliation/utils/toKubernetesName.js +21 -0
- package/dist/features/workload-reconciliation/utils/toKubernetesName.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types/kubernetesDriver.d.ts +21 -1
- package/dist/types/kubernetesDriver.d.ts.map +1 -1
- package/dist/types/kubernetesDriver.js.map +1 -1
- package/dist/types/kubernetesResources.d.ts +87 -0
- package/dist/types/kubernetesResources.d.ts.map +1 -0
- package/dist/types/kubernetesResources.js +2 -0
- package/dist/types/kubernetesResources.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { getKubernetesResourceKey } from '../../utils/getKubernetesResourceKey';
|
|
2
|
+
/*** Resolve referenced secrets into ephemeral Kubernetes apply resources. */
|
|
3
|
+
export async function materializeKubernetesSecretsAsync(request, projection) {
|
|
4
|
+
const values = new Map();
|
|
5
|
+
const diagnostics = [];
|
|
6
|
+
for (const binding of projection.secretBindings) {
|
|
7
|
+
const resolved = await request.context.secrets.resolveAsync(binding.reference);
|
|
8
|
+
if (!resolved.ok) {
|
|
9
|
+
diagnostics.push(...resolved.diagnostics);
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
const resourceValues = values.get(getKubernetesResourceKey(binding.resource)) ?? {};
|
|
13
|
+
resourceValues[binding.key] = resolved.value;
|
|
14
|
+
values.set(getKubernetesResourceKey(binding.resource), resourceValues);
|
|
15
|
+
}
|
|
16
|
+
if (diagnostics.length > 0)
|
|
17
|
+
return { ok: false, diagnostics };
|
|
18
|
+
return {
|
|
19
|
+
ok: true,
|
|
20
|
+
value: projection.resources.map((desired) => {
|
|
21
|
+
const secretValues = values.get(desired.owner.externalId ?? '');
|
|
22
|
+
if (secretValues === undefined)
|
|
23
|
+
return desired;
|
|
24
|
+
return {
|
|
25
|
+
...desired,
|
|
26
|
+
resource: { ...desired.resource, stringData: secretValues },
|
|
27
|
+
};
|
|
28
|
+
}),
|
|
29
|
+
diagnostics: [],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=materializeKubernetesSecretsAsync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materializeKubernetesSecretsAsync.js","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/materializeKubernetesSecretsAsync.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAEhF,6EAA6E;AAC7E,MAAM,CAAC,KAAK,UAAU,iCAAiC,CACrD,OAAgC,EAChC,UAAgC;IAEhC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkC,CAAC;IACzD,MAAM,WAAW,GAAsB,EAAE,CAAC;IAE1C,KAAK,MAAM,OAAO,IAAI,UAAU,CAAC,cAAc,EAAE,CAAC;QAChD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC/E,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,WAAW,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;YAC1C,SAAS;QACX,CAAC;QACD,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAC,wBAAwB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACpF,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;QAC7C,MAAM,CAAC,GAAG,CAAC,wBAAwB,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IAE9D,OAAO;QACL,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;YAC1C,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;YAChE,IAAI,YAAY,KAAK,SAAS;gBAAE,OAAO,OAAO,CAAC;YAC/C,OAAO;gBACL,GAAG,OAAO;gBACV,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE;aAC5D,CAAC;QACJ,CAAC,CAAC;QACF,WAAW,EAAE,EAAE;KAChB,CAAC;AACJ,CAAC","sourcesContent":["import type { InfraDiagnostic, InfraResult } from '@ankhorage/contracts/infra';\n\nimport type { KubernetesDriverRequest } from '../../../../types/kubernetesDriver';\nimport type {\n KubernetesDesiredResource,\n KubernetesProjection,\n} from '../../../../types/kubernetesResources';\nimport { getKubernetesResourceKey } from '../../utils/getKubernetesResourceKey';\n\n/*** Resolve referenced secrets into ephemeral Kubernetes apply resources. */\nexport async function materializeKubernetesSecretsAsync(\n request: KubernetesDriverRequest,\n projection: KubernetesProjection,\n): Promise<InfraResult<readonly KubernetesDesiredResource[]>> {\n const values = new Map<string, Record<string, string>>();\n const diagnostics: InfraDiagnostic[] = [];\n\n for (const binding of projection.secretBindings) {\n const resolved = await request.context.secrets.resolveAsync(binding.reference);\n if (!resolved.ok) {\n diagnostics.push(...resolved.diagnostics);\n continue;\n }\n const resourceValues = values.get(getKubernetesResourceKey(binding.resource)) ?? {};\n resourceValues[binding.key] = resolved.value;\n values.set(getKubernetesResourceKey(binding.resource), resourceValues);\n }\n\n if (diagnostics.length > 0) return { ok: false, diagnostics };\n\n return {\n ok: true,\n value: projection.resources.map((desired) => {\n const secretValues = values.get(desired.owner.externalId ?? '');\n if (secretValues === undefined) return desired;\n return {\n ...desired,\n resource: { ...desired.resource, stringData: secretValues },\n };\n }),\n diagnostics: [],\n };\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { InfraPlanAction, InfraResult } from '@ankhorage/contracts/infra';
|
|
2
|
+
import type { KubernetesDriverOptions, KubernetesDriverRequest } from '../../../../types/kubernetesDriver';
|
|
3
|
+
/*** Produce a side-effect-free Kubernetes reconciliation plan. */
|
|
4
|
+
export declare function planKubernetesResourcesAsync(options: KubernetesDriverOptions, request: KubernetesDriverRequest): Promise<InfraResult<readonly InfraPlanAction[]>>;
|
|
5
|
+
//# sourceMappingURL=planKubernetesResourcesAsync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planKubernetesResourcesAsync.d.ts","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/planKubernetesResourcesAsync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE/E,OAAO,KAAK,EACV,uBAAuB,EACvB,uBAAuB,EACxB,MAAM,oCAAoC,CAAC;AAG5C,kEAAkE;AAClE,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,uBAAuB,EAChC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,WAAW,CAAC,SAAS,eAAe,EAAE,CAAC,CAAC,CAKlD"}
|
package/dist/features/workload-reconciliation/application/use-cases/planKubernetesResourcesAsync.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { prepareKubernetesChangesAsync } from './prepareKubernetesChangesAsync';
|
|
2
|
+
/*** Produce a side-effect-free Kubernetes reconciliation plan. */
|
|
3
|
+
export async function planKubernetesResourcesAsync(options, request) {
|
|
4
|
+
const prepared = await prepareKubernetesChangesAsync(options, request);
|
|
5
|
+
return prepared.ok
|
|
6
|
+
? { ok: true, value: prepared.value.changes.map(({ action }) => action), diagnostics: [] }
|
|
7
|
+
: prepared;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=planKubernetesResourcesAsync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planKubernetesResourcesAsync.js","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/planKubernetesResourcesAsync.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAEhF,kEAAkE;AAClE,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,OAAgC,EAChC,OAAgC;IAEhC,MAAM,QAAQ,GAAG,MAAM,6BAA6B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACvE,OAAO,QAAQ,CAAC,EAAE;QAChB,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE;QAC1F,CAAC,CAAC,QAAQ,CAAC;AACf,CAAC","sourcesContent":["import type { InfraPlanAction, InfraResult } from '@ankhorage/contracts/infra';\n\nimport type {\n KubernetesDriverOptions,\n KubernetesDriverRequest,\n} from '../../../../types/kubernetesDriver';\nimport { prepareKubernetesChangesAsync } from './prepareKubernetesChangesAsync';\n\n/*** Produce a side-effect-free Kubernetes reconciliation plan. */\nexport async function planKubernetesResourcesAsync(\n options: KubernetesDriverOptions,\n request: KubernetesDriverRequest,\n): Promise<InfraResult<readonly InfraPlanAction[]>> {\n const prepared = await prepareKubernetesChangesAsync(options, request);\n return prepared.ok\n ? { ok: true, value: prepared.value.changes.map(({ action }) => action), diagnostics: [] }\n : prepared;\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { InfraResult } from '@ankhorage/contracts/infra';
|
|
2
|
+
import type { KubernetesDriverOptions, KubernetesDriverRequest } from '../../../../types/kubernetesDriver';
|
|
3
|
+
import type { KubernetesPreparedChanges } from '../../../../types/kubernetesResources';
|
|
4
|
+
/*** Prepare deterministic create, update, no-op, retain and stale-delete changes. */
|
|
5
|
+
export declare function prepareKubernetesChangesAsync(options: KubernetesDriverOptions, request: KubernetesDriverRequest): Promise<InfraResult<KubernetesPreparedChanges>>;
|
|
6
|
+
//# sourceMappingURL=prepareKubernetesChangesAsync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepareKubernetesChangesAsync.d.ts","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/prepareKubernetesChangesAsync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE/E,OAAO,KAAK,EACV,uBAAuB,EACvB,uBAAuB,EACxB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAGV,yBAAyB,EAE1B,MAAM,uCAAuC,CAAC;AAU/C,qFAAqF;AACrF,wBAAsB,6BAA6B,CACjD,OAAO,EAAE,uBAAuB,EAChC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,WAAW,CAAC,yBAAyB,CAAC,CAAC,CAwBjD"}
|
package/dist/features/workload-reconciliation/application/use-cases/prepareKubernetesChangesAsync.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { areKubernetesResourcesEquivalent } from '../../utils/areKubernetesResourcesEquivalent';
|
|
2
|
+
import { getKubernetesOwnershipQuery } from '../../utils/getKubernetesOwnershipQuery';
|
|
3
|
+
import { getKubernetesResourceKey } from '../../utils/getKubernetesResourceKey';
|
|
4
|
+
import { getKubernetesResourceReference } from '../../utils/getKubernetesResourceReference';
|
|
5
|
+
import { readKubernetesOwnedResource } from '../../utils/readKubernetesOwnedResource';
|
|
6
|
+
import { sortKubernetesResourcesForRemoval } from '../../utils/sortKubernetesResourcesForRemoval';
|
|
7
|
+
import { materializeKubernetesSecretsAsync } from './materializeKubernetesSecretsAsync';
|
|
8
|
+
import { projectKubernetesResourcesAsync } from './projectKubernetesResourcesAsync';
|
|
9
|
+
/*** Prepare deterministic create, update, no-op, retain and stale-delete changes. */
|
|
10
|
+
export async function prepareKubernetesChangesAsync(options, request) {
|
|
11
|
+
try {
|
|
12
|
+
const projection = await projectKubernetesResourcesAsync(request);
|
|
13
|
+
if (!projection.ok)
|
|
14
|
+
return projection;
|
|
15
|
+
const materialized = await materializeKubernetesSecretsAsync(request, projection.value);
|
|
16
|
+
if (!materialized.ok)
|
|
17
|
+
return materialized;
|
|
18
|
+
const observed = await options.api.listOwnedAsync(getKubernetesOwnershipQuery(request));
|
|
19
|
+
const desiredChanges = createDesiredChanges(materialized.value, observed);
|
|
20
|
+
const desiredKeys = new Set(materialized.value.map(({ owner }) => owner.externalId ?? ''));
|
|
21
|
+
const staleChanges = createStaleChanges(request, observed, desiredKeys);
|
|
22
|
+
const changes = [...desiredChanges, ...staleChanges];
|
|
23
|
+
return { ok: true, value: { changes, projection: projection.value }, diagnostics: [] };
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return {
|
|
27
|
+
ok: false,
|
|
28
|
+
diagnostics: [
|
|
29
|
+
{
|
|
30
|
+
severity: 'error',
|
|
31
|
+
code: 'kubernetes-plan-failed',
|
|
32
|
+
message: 'Kubernetes desired and observed resources could not be compared safely.',
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/*** Compare desired resources against the observed resource map. */
|
|
39
|
+
function createDesiredChanges(desiredResources, observed) {
|
|
40
|
+
const actual = new Map(observed.map((resource) => [
|
|
41
|
+
getKubernetesResourceKey(getKubernetesResourceReference(resource)),
|
|
42
|
+
resource,
|
|
43
|
+
]));
|
|
44
|
+
return desiredResources.map((desired) => {
|
|
45
|
+
const current = actual.get(desired.owner.externalId ?? '');
|
|
46
|
+
const operation = current === undefined
|
|
47
|
+
? 'create'
|
|
48
|
+
: areKubernetesResourcesEquivalent(desired.resource, current)
|
|
49
|
+
? 'noop'
|
|
50
|
+
: 'update';
|
|
51
|
+
return {
|
|
52
|
+
action: createAction(desired.owner.identity, desired.owner.dependsOn, operation),
|
|
53
|
+
desired,
|
|
54
|
+
...(current === undefined ? {} : { actual: current }),
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/*** Identify obsolete owned resources without admitting malformed ownership metadata. */
|
|
59
|
+
function createStaleChanges(request, observed, desiredKeys) {
|
|
60
|
+
const stale = observed.flatMap((resource) => {
|
|
61
|
+
const key = getKubernetesResourceKey(getKubernetesResourceReference(resource));
|
|
62
|
+
if (desiredKeys.has(key))
|
|
63
|
+
return [];
|
|
64
|
+
const owner = readKubernetesOwnedResource(resource, request);
|
|
65
|
+
if (owner === undefined)
|
|
66
|
+
return [];
|
|
67
|
+
return [{ resource, owner }];
|
|
68
|
+
});
|
|
69
|
+
return sortKubernetesResourcesForRemoval(stale).map(({ resource, owner }) => ({
|
|
70
|
+
action: createAction(owner.identity, owner.dependsOn, owner.persistent ? 'retain' : 'delete'),
|
|
71
|
+
actual: resource,
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
/*** Create one non-secret plan action. */
|
|
75
|
+
function createAction(owner, dependsOn, operation) {
|
|
76
|
+
return {
|
|
77
|
+
owner,
|
|
78
|
+
operation,
|
|
79
|
+
impact: operation === 'delete' ? 'interrupts-service' : 'none',
|
|
80
|
+
detail: `Kubernetes resource ${owner.resourceId}: ${operation}.`,
|
|
81
|
+
dependsOn,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=prepareKubernetesChangesAsync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepareKubernetesChangesAsync.js","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/prepareKubernetesChangesAsync.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InfraPlanAction, InfraResult } from '@ankhorage/contracts/infra';\n\nimport type {\n KubernetesDriverOptions,\n KubernetesDriverRequest,\n} from '../../../../types/kubernetesDriver';\nimport type {\n KubernetesDesiredResource,\n KubernetesPreparedChange,\n KubernetesPreparedChanges,\n KubernetesResource,\n} from '../../../../types/kubernetesResources';\nimport { areKubernetesResourcesEquivalent } from '../../utils/areKubernetesResourcesEquivalent';\nimport { getKubernetesOwnershipQuery } from '../../utils/getKubernetesOwnershipQuery';\nimport { getKubernetesResourceKey } from '../../utils/getKubernetesResourceKey';\nimport { getKubernetesResourceReference } from '../../utils/getKubernetesResourceReference';\nimport { readKubernetesOwnedResource } from '../../utils/readKubernetesOwnedResource';\nimport { sortKubernetesResourcesForRemoval } from '../../utils/sortKubernetesResourcesForRemoval';\nimport { materializeKubernetesSecretsAsync } from './materializeKubernetesSecretsAsync';\nimport { projectKubernetesResourcesAsync } from './projectKubernetesResourcesAsync';\n\n/*** Prepare deterministic create, update, no-op, retain and stale-delete changes. */\nexport async function prepareKubernetesChangesAsync(\n options: KubernetesDriverOptions,\n request: KubernetesDriverRequest,\n): Promise<InfraResult<KubernetesPreparedChanges>> {\n try {\n const projection = await projectKubernetesResourcesAsync(request);\n if (!projection.ok) return projection;\n const materialized = await materializeKubernetesSecretsAsync(request, projection.value);\n if (!materialized.ok) return materialized;\n const observed = await options.api.listOwnedAsync(getKubernetesOwnershipQuery(request));\n const desiredChanges = createDesiredChanges(materialized.value, observed);\n const desiredKeys = new Set(materialized.value.map(({ owner }) => owner.externalId ?? ''));\n const staleChanges = createStaleChanges(request, observed, desiredKeys);\n const changes = [...desiredChanges, ...staleChanges];\n return { ok: true, value: { changes, projection: projection.value }, diagnostics: [] };\n } catch {\n return {\n ok: false,\n diagnostics: [\n {\n severity: 'error',\n code: 'kubernetes-plan-failed',\n message: 'Kubernetes desired and observed resources could not be compared safely.',\n },\n ],\n };\n }\n}\n\n/*** Compare desired resources against the observed resource map. */\nfunction createDesiredChanges(\n desiredResources: readonly KubernetesDesiredResource[],\n observed: readonly KubernetesResource[],\n): readonly KubernetesPreparedChange[] {\n const actual = new Map(\n observed.map((resource) => [\n getKubernetesResourceKey(getKubernetesResourceReference(resource)),\n resource,\n ]),\n );\n return desiredResources.map((desired) => {\n const current = actual.get(desired.owner.externalId ?? '');\n const operation =\n current === undefined\n ? 'create'\n : areKubernetesResourcesEquivalent(desired.resource, current)\n ? 'noop'\n : 'update';\n return {\n action: createAction(desired.owner.identity, desired.owner.dependsOn, operation),\n desired,\n ...(current === undefined ? {} : { actual: current }),\n };\n });\n}\n\n/*** Identify obsolete owned resources without admitting malformed ownership metadata. */\nfunction createStaleChanges(\n request: KubernetesDriverRequest,\n observed: readonly KubernetesResource[],\n desiredKeys: ReadonlySet<string>,\n): readonly KubernetesPreparedChange[] {\n const stale = observed.flatMap((resource) => {\n const key = getKubernetesResourceKey(getKubernetesResourceReference(resource));\n if (desiredKeys.has(key)) return [];\n const owner = readKubernetesOwnedResource(resource, request);\n if (owner === undefined) return [];\n return [{ resource, owner }];\n });\n return sortKubernetesResourcesForRemoval(stale).map(({ resource, owner }) => ({\n action: createAction(owner.identity, owner.dependsOn, owner.persistent ? 'retain' : 'delete'),\n actual: resource,\n }));\n}\n\n/*** Create one non-secret plan action. */\nfunction createAction(\n owner: InfraPlanAction['owner'],\n dependsOn: InfraPlanAction['dependsOn'],\n operation: InfraPlanAction['operation'],\n): InfraPlanAction {\n return {\n owner,\n operation,\n impact: operation === 'delete' ? 'interrupts-service' : 'none',\n detail: `Kubernetes resource ${owner.resourceId}: ${operation}.`,\n dependsOn,\n };\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { InfraResult } from '@ankhorage/contracts/infra';
|
|
2
|
+
import type { KubernetesDriverRequest } from '../../../../types/kubernetesDriver';
|
|
3
|
+
import type { KubernetesProjection } from '../../../../types/kubernetesResources';
|
|
4
|
+
/***
|
|
5
|
+
* Project portable workload desired state into deterministic standard Kubernetes resources.
|
|
6
|
+
*
|
|
7
|
+
* Resolved secret values are deliberately absent. The projection carries only references for
|
|
8
|
+
* runtime materialization immediately before apply.
|
|
9
|
+
*/
|
|
10
|
+
export declare function projectKubernetesResourcesAsync(request: KubernetesDriverRequest): Promise<InfraResult<KubernetesProjection>>;
|
|
11
|
+
//# sourceMappingURL=projectKubernetesResourcesAsync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectKubernetesResourcesAsync.d.ts","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/projectKubernetesResourcesAsync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE9D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAClF,OAAO,KAAK,EAEV,oBAAoB,EAErB,MAAM,uCAAuC,CAAC;AAO/C;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,CA8B5C"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createKubernetesDesiredResource } from '../../utils/createKubernetesDesiredResource';
|
|
2
|
+
import { createKubernetesIdentity } from '../../utils/createKubernetesIdentity';
|
|
3
|
+
import { getKubernetesOwnershipQuery } from '../../utils/getKubernetesOwnershipQuery';
|
|
4
|
+
import { projectKubernetesWorkload } from './projectKubernetesWorkload';
|
|
5
|
+
import { validateKubernetesWorkloads } from './validateKubernetesWorkloads';
|
|
6
|
+
/***
|
|
7
|
+
* Project portable workload desired state into deterministic standard Kubernetes resources.
|
|
8
|
+
*
|
|
9
|
+
* Resolved secret values are deliberately absent. The projection carries only references for
|
|
10
|
+
* runtime materialization immediately before apply.
|
|
11
|
+
*/
|
|
12
|
+
export function projectKubernetesResourcesAsync(request) {
|
|
13
|
+
const validation = validateKubernetesWorkloads(request.workloads);
|
|
14
|
+
if (validation.length > 0)
|
|
15
|
+
return Promise.resolve({ ok: false, diagnostics: validation });
|
|
16
|
+
const { namespace } = getKubernetesOwnershipQuery(request);
|
|
17
|
+
const namespaceResource = createNamespace(request, namespace);
|
|
18
|
+
const workloadOwners = new Map(request.workloads.map((workload) => [
|
|
19
|
+
workload.id,
|
|
20
|
+
createKubernetesIdentity(request, `workload:${workload.id}`),
|
|
21
|
+
]));
|
|
22
|
+
const resources = [namespaceResource];
|
|
23
|
+
const secretBindings = [];
|
|
24
|
+
for (const workload of request.workloads) {
|
|
25
|
+
const projected = projectKubernetesWorkload(request, {
|
|
26
|
+
namespace,
|
|
27
|
+
namespaceOwner: namespaceResource.owner.identity,
|
|
28
|
+
workloadOwners,
|
|
29
|
+
workload,
|
|
30
|
+
});
|
|
31
|
+
if (!projected.ok)
|
|
32
|
+
return Promise.resolve(projected);
|
|
33
|
+
resources.push(...projected.value.resources);
|
|
34
|
+
secretBindings.push(...projected.value.secretBindings);
|
|
35
|
+
}
|
|
36
|
+
return Promise.resolve({
|
|
37
|
+
ok: true,
|
|
38
|
+
value: { resources, secretBindings },
|
|
39
|
+
diagnostics: [],
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/*** Create the environment namespace before all namespaced resources. */
|
|
43
|
+
function createNamespace(request, namespace) {
|
|
44
|
+
return createKubernetesDesiredResource(request, {
|
|
45
|
+
resourceId: `namespace:${namespace}`,
|
|
46
|
+
resource: {
|
|
47
|
+
apiVersion: 'v1',
|
|
48
|
+
kind: 'Namespace',
|
|
49
|
+
metadata: { name: namespace, labels: {}, annotations: {} },
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=projectKubernetesResourcesAsync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectKubernetesResourcesAsync.js","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/projectKubernetesResourcesAsync.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,+BAA+B,EAAE,MAAM,6CAA6C,CAAC;AAC9F,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAChF,OAAO,EAAE,2BAA2B,EAAE,MAAM,yCAAyC,CAAC;AACtF,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAE5E;;;;;GAKG;AACH,MAAM,UAAU,+BAA+B,CAC7C,OAAgC;IAEhC,MAAM,UAAU,GAAG,2BAA2B,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAClE,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC;IAE1F,MAAM,EAAE,SAAS,EAAE,GAAG,2BAA2B,CAAC,OAAO,CAAC,CAAC;IAC3D,MAAM,iBAAiB,GAAG,eAAe,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC9D,MAAM,cAAc,GAAG,IAAI,GAAG,CAC5B,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC;QAClC,QAAQ,CAAC,EAAE;QACX,wBAAwB,CAAC,OAAO,EAAE,YAAY,QAAQ,CAAC,EAAE,EAAE,CAAC;KAC7D,CAAC,CACH,CAAC;IACF,MAAM,SAAS,GAAgC,CAAC,iBAAiB,CAAC,CAAC;IACnE,MAAM,cAAc,GAA8B,EAAE,CAAC;IACrD,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,yBAAyB,CAAC,OAAO,EAAE;YACnD,SAAS;YACT,cAAc,EAAE,iBAAiB,CAAC,KAAK,CAAC,QAAQ;YAChD,cAAc;YACd,QAAQ;SACT,CAAC,CAAC;QACH,IAAI,CAAC,SAAS,CAAC,EAAE;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACrD,SAAS,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC7C,cAAc,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,OAAO,CAAC,OAAO,CAAC;QACrB,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE;QACpC,WAAW,EAAE,EAAE;KAChB,CAAC,CAAC;AACL,CAAC;AAED,yEAAyE;AACzE,SAAS,eAAe,CACtB,OAAgC,EAChC,SAAiB;IAEjB,OAAO,+BAA+B,CAAC,OAAO,EAAE;QAC9C,UAAU,EAAE,aAAa,SAAS,EAAE;QACpC,QAAQ,EAAE;YACR,UAAU,EAAE,IAAI;YAChB,IAAI,EAAE,WAAW;YACjB,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;SAC3D;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { InfraResult } from '@ankhorage/contracts/infra';\n\nimport type { KubernetesDriverRequest } from '../../../../types/kubernetesDriver';\nimport type {\n KubernetesDesiredResource,\n KubernetesProjection,\n KubernetesSecretBinding,\n} from '../../../../types/kubernetesResources';\nimport { createKubernetesDesiredResource } from '../../utils/createKubernetesDesiredResource';\nimport { createKubernetesIdentity } from '../../utils/createKubernetesIdentity';\nimport { getKubernetesOwnershipQuery } from '../../utils/getKubernetesOwnershipQuery';\nimport { projectKubernetesWorkload } from './projectKubernetesWorkload';\nimport { validateKubernetesWorkloads } from './validateKubernetesWorkloads';\n\n/***\n * Project portable workload desired state into deterministic standard Kubernetes resources.\n *\n * Resolved secret values are deliberately absent. The projection carries only references for\n * runtime materialization immediately before apply.\n */\nexport function projectKubernetesResourcesAsync(\n request: KubernetesDriverRequest,\n): Promise<InfraResult<KubernetesProjection>> {\n const validation = validateKubernetesWorkloads(request.workloads);\n if (validation.length > 0) return Promise.resolve({ ok: false, diagnostics: validation });\n\n const { namespace } = getKubernetesOwnershipQuery(request);\n const namespaceResource = createNamespace(request, namespace);\n const workloadOwners = new Map(\n request.workloads.map((workload) => [\n workload.id,\n createKubernetesIdentity(request, `workload:${workload.id}`),\n ]),\n );\n const resources: KubernetesDesiredResource[] = [namespaceResource];\n const secretBindings: KubernetesSecretBinding[] = [];\n for (const workload of request.workloads) {\n const projected = projectKubernetesWorkload(request, {\n namespace,\n namespaceOwner: namespaceResource.owner.identity,\n workloadOwners,\n workload,\n });\n if (!projected.ok) return Promise.resolve(projected);\n resources.push(...projected.value.resources);\n secretBindings.push(...projected.value.secretBindings);\n }\n return Promise.resolve({\n ok: true,\n value: { resources, secretBindings },\n diagnostics: [],\n });\n}\n\n/*** Create the environment namespace before all namespaced resources. */\nfunction createNamespace(\n request: KubernetesDriverRequest,\n namespace: string,\n): KubernetesDesiredResource {\n return createKubernetesDesiredResource(request, {\n resourceId: `namespace:${namespace}`,\n resource: {\n apiVersion: 'v1',\n kind: 'Namespace',\n metadata: { name: namespace, labels: {}, annotations: {} },\n },\n });\n}\n"]}
|
package/dist/features/workload-reconciliation/application/use-cases/projectKubernetesWorkload.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { InfraResourceIdentity, InfraResult, InfraWorkloadSpec } from '@ankhorage/contracts/infra';
|
|
2
|
+
import type { KubernetesDriverRequest } from '../../../../types/kubernetesDriver';
|
|
3
|
+
import type { KubernetesWorkloadProjection } from '../../../../types/kubernetesResources';
|
|
4
|
+
/*** Project one workload while retaining dependency-first resource ordering. */
|
|
5
|
+
export declare function projectKubernetesWorkload(request: KubernetesDriverRequest, input: ProjectKubernetesWorkloadInput): InfraResult<KubernetesWorkloadProjection>;
|
|
6
|
+
export interface ProjectKubernetesWorkloadInput {
|
|
7
|
+
readonly namespace: string;
|
|
8
|
+
readonly namespaceOwner: InfraResourceIdentity;
|
|
9
|
+
readonly workloadOwners: ReadonlyMap<string, InfraResourceIdentity>;
|
|
10
|
+
readonly workload: InfraWorkloadSpec;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=projectKubernetesWorkload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectKubernetesWorkload.d.ts","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/projectKubernetesWorkload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,WAAW,EACX,iBAAiB,EAClB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAClF,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,uCAAuC,CAAC;AAO1F,gFAAgF;AAChF,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,uBAAuB,EAChC,KAAK,EAAE,8BAA8B,GACpC,WAAW,CAAC,4BAA4B,CAAC,CAoC3C;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,qBAAqB,CAAC;IAC/C,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IACpE,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;CACtC"}
|
package/dist/features/workload-reconciliation/application/use-cases/projectKubernetesWorkload.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { toKubernetesName } from '../../utils/toKubernetesName';
|
|
2
|
+
import { createKubernetesController } from './createKubernetesController';
|
|
3
|
+
import { createKubernetesExposure } from './createKubernetesExposure';
|
|
4
|
+
import { createKubernetesPrerequisites } from './createKubernetesPrerequisites';
|
|
5
|
+
import { resolveKubernetesWorkloadValues } from './resolveKubernetesWorkloadValues';
|
|
6
|
+
/*** Project one workload while retaining dependency-first resource ordering. */
|
|
7
|
+
export function projectKubernetesWorkload(request, input) {
|
|
8
|
+
const workloadName = toKubernetesName(input.workload.id);
|
|
9
|
+
const values = resolveKubernetesWorkloadValues(request.availableOutputs ?? [], input.workload);
|
|
10
|
+
if (!values.ok)
|
|
11
|
+
return values;
|
|
12
|
+
const prerequisites = createKubernetesPrerequisites(request, {
|
|
13
|
+
namespace: input.namespace,
|
|
14
|
+
namespaceOwner: input.namespaceOwner,
|
|
15
|
+
workloadName,
|
|
16
|
+
workload: input.workload,
|
|
17
|
+
values: values.value,
|
|
18
|
+
});
|
|
19
|
+
const declaredDependencies = (input.workload.dependsOn ?? []).flatMap((id) => {
|
|
20
|
+
const owner = input.workloadOwners.get(id);
|
|
21
|
+
return owner === undefined ? [] : [owner];
|
|
22
|
+
});
|
|
23
|
+
const controller = createKubernetesController(request, {
|
|
24
|
+
namespace: input.namespace,
|
|
25
|
+
workloadName,
|
|
26
|
+
workload: input.workload,
|
|
27
|
+
values: values.value,
|
|
28
|
+
dependsOn: [...prerequisites.owners, ...declaredDependencies],
|
|
29
|
+
});
|
|
30
|
+
const exposure = createKubernetesExposure(request, {
|
|
31
|
+
namespace: input.namespace,
|
|
32
|
+
workloadName,
|
|
33
|
+
workload: input.workload,
|
|
34
|
+
controller: controller.owner.identity,
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
ok: true,
|
|
38
|
+
value: {
|
|
39
|
+
resources: [...prerequisites.resources, controller, ...exposure],
|
|
40
|
+
secretBindings: prerequisites.secretBindings,
|
|
41
|
+
},
|
|
42
|
+
diagnostics: [],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=projectKubernetesWorkload.js.map
|
package/dist/features/workload-reconciliation/application/use-cases/projectKubernetesWorkload.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectKubernetesWorkload.js","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/projectKubernetesWorkload.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAChF,OAAO,EAAE,+BAA+B,EAAE,MAAM,mCAAmC,CAAC;AAEpF,gFAAgF;AAChF,MAAM,UAAU,yBAAyB,CACvC,OAAgC,EAChC,KAAqC;IAErC,MAAM,YAAY,GAAG,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,+BAA+B,CAAC,OAAO,CAAC,gBAAgB,IAAI,EAAE,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/F,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,MAAM,CAAC;IAC9B,MAAM,aAAa,GAAG,6BAA6B,CAAC,OAAO,EAAE;QAC3D,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,YAAY;QACZ,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,MAAM,CAAC,KAAK;KACrB,CAAC,CAAC;IACH,MAAM,oBAAoB,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE;QAC3E,MAAM,KAAK,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3C,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,0BAA0B,CAAC,OAAO,EAAE;QACrD,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,YAAY;QACZ,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,MAAM,CAAC,KAAK;QACpB,SAAS,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,GAAG,oBAAoB,CAAC;KAC9D,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,wBAAwB,CAAC,OAAO,EAAE;QACjD,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,YAAY;QACZ,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,QAAQ;KACtC,CAAC,CAAC;IACH,OAAO;QACL,EAAE,EAAE,IAAI;QACR,KAAK,EAAE;YACL,SAAS,EAAE,CAAC,GAAG,aAAa,CAAC,SAAS,EAAE,UAAU,EAAE,GAAG,QAAQ,CAAC;YAChE,cAAc,EAAE,aAAa,CAAC,cAAc;SAC7C;QACD,WAAW,EAAE,EAAE;KAChB,CAAC;AACJ,CAAC","sourcesContent":["import type {\n InfraResourceIdentity,\n InfraResult,\n InfraWorkloadSpec,\n} from '@ankhorage/contracts/infra';\n\nimport type { KubernetesDriverRequest } from '../../../../types/kubernetesDriver';\nimport type { KubernetesWorkloadProjection } from '../../../../types/kubernetesResources';\nimport { toKubernetesName } from '../../utils/toKubernetesName';\nimport { createKubernetesController } from './createKubernetesController';\nimport { createKubernetesExposure } from './createKubernetesExposure';\nimport { createKubernetesPrerequisites } from './createKubernetesPrerequisites';\nimport { resolveKubernetesWorkloadValues } from './resolveKubernetesWorkloadValues';\n\n/*** Project one workload while retaining dependency-first resource ordering. */\nexport function projectKubernetesWorkload(\n request: KubernetesDriverRequest,\n input: ProjectKubernetesWorkloadInput,\n): InfraResult<KubernetesWorkloadProjection> {\n const workloadName = toKubernetesName(input.workload.id);\n const values = resolveKubernetesWorkloadValues(request.availableOutputs ?? [], input.workload);\n if (!values.ok) return values;\n const prerequisites = createKubernetesPrerequisites(request, {\n namespace: input.namespace,\n namespaceOwner: input.namespaceOwner,\n workloadName,\n workload: input.workload,\n values: values.value,\n });\n const declaredDependencies = (input.workload.dependsOn ?? []).flatMap((id) => {\n const owner = input.workloadOwners.get(id);\n return owner === undefined ? [] : [owner];\n });\n const controller = createKubernetesController(request, {\n namespace: input.namespace,\n workloadName,\n workload: input.workload,\n values: values.value,\n dependsOn: [...prerequisites.owners, ...declaredDependencies],\n });\n const exposure = createKubernetesExposure(request, {\n namespace: input.namespace,\n workloadName,\n workload: input.workload,\n controller: controller.owner.identity,\n });\n return {\n ok: true,\n value: {\n resources: [...prerequisites.resources, controller, ...exposure],\n secretBindings: prerequisites.secretBindings,\n },\n diagnostics: [],\n };\n}\n\nexport interface ProjectKubernetesWorkloadInput {\n readonly namespace: string;\n readonly namespaceOwner: InfraResourceIdentity;\n readonly workloadOwners: ReadonlyMap<string, InfraResourceIdentity>;\n readonly workload: InfraWorkloadSpec;\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { InfraReconcileResult, InfraResult } from '@ankhorage/contracts/infra';
|
|
2
|
+
import type { KubernetesDriverOptions, KubernetesDriverRequest } from '../../../../types/kubernetesDriver';
|
|
3
|
+
/*** Apply desired changes and prune only obsolete, non-persistent Infra-owned resources. */
|
|
4
|
+
export declare function reconcileKubernetesResourcesAsync(options: KubernetesDriverOptions, request: KubernetesDriverRequest): Promise<InfraResult<InfraReconcileResult>>;
|
|
5
|
+
//# sourceMappingURL=reconcileKubernetesResourcesAsync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcileKubernetesResourcesAsync.d.ts","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/reconcileKubernetesResourcesAsync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,oBAAoB,EACpB,WAAW,EACZ,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EACV,uBAAuB,EACvB,uBAAuB,EACxB,MAAM,oCAAoC,CAAC;AAM5C,4FAA4F;AAC5F,wBAAsB,iCAAiC,CACrD,OAAO,EAAE,uBAAuB,EAChC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,CA+C5C"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { getKubernetesResourceReference } from '../../utils/getKubernetesResourceReference';
|
|
2
|
+
import { readKubernetesOwnedResource } from '../../utils/readKubernetesOwnedResource';
|
|
3
|
+
import { getKubernetesOutputsAsync } from './getKubernetesOutputsAsync';
|
|
4
|
+
import { prepareKubernetesChangesAsync } from './prepareKubernetesChangesAsync';
|
|
5
|
+
/*** Apply desired changes and prune only obsolete, non-persistent Infra-owned resources. */
|
|
6
|
+
export async function reconcileKubernetesResourcesAsync(options, request) {
|
|
7
|
+
const prepared = await prepareKubernetesChangesAsync(options, request);
|
|
8
|
+
if (!prepared.ok)
|
|
9
|
+
return prepared;
|
|
10
|
+
try {
|
|
11
|
+
const retained = [];
|
|
12
|
+
for (const change of prepared.value.changes) {
|
|
13
|
+
if ((change.action.operation === 'create' || change.action.operation === 'update') &&
|
|
14
|
+
change.desired !== undefined) {
|
|
15
|
+
await options.api.applyAsync(change.desired.resource, request.context.signal);
|
|
16
|
+
}
|
|
17
|
+
if (change.action.operation === 'delete' && change.actual !== undefined) {
|
|
18
|
+
await options.api.deleteAsync(getKubernetesResourceReference(change.actual), request.context.signal);
|
|
19
|
+
}
|
|
20
|
+
if (change.action.operation === 'retain' && change.actual !== undefined) {
|
|
21
|
+
const owner = readKubernetesOwnedResource(change.actual, request);
|
|
22
|
+
if (owner !== undefined)
|
|
23
|
+
retained.push(owner);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const outputs = await getKubernetesOutputsAsync(options, request);
|
|
27
|
+
if (!outputs.ok)
|
|
28
|
+
return outputs;
|
|
29
|
+
return {
|
|
30
|
+
ok: true,
|
|
31
|
+
value: {
|
|
32
|
+
resources: [...prepared.value.projection.resources.map(({ owner }) => owner), ...retained],
|
|
33
|
+
outputs: outputs.value,
|
|
34
|
+
},
|
|
35
|
+
diagnostics: [],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return {
|
|
40
|
+
ok: false,
|
|
41
|
+
diagnostics: [
|
|
42
|
+
{
|
|
43
|
+
severity: 'error',
|
|
44
|
+
code: 'kubernetes-reconcile-failed',
|
|
45
|
+
message: 'Kubernetes resources could not be reconciled safely.',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=reconcileKubernetesResourcesAsync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcileKubernetesResourcesAsync.js","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/reconcileKubernetesResourcesAsync.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,8BAA8B,EAAE,MAAM,4CAA4C,CAAC;AAC5F,OAAO,EAAE,2BAA2B,EAAE,MAAM,yCAAyC,CAAC;AACtF,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAEhF,4FAA4F;AAC5F,MAAM,CAAC,KAAK,UAAU,iCAAiC,CACrD,OAAgC,EAChC,OAAgC;IAEhC,MAAM,QAAQ,GAAG,MAAM,6BAA6B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACvE,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,OAAO,QAAQ,CAAC;IAElC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAyB,EAAE,CAAC;QAC1C,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YAC5C,IACE,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,KAAK,QAAQ,CAAC;gBAC9E,MAAM,CAAC,OAAO,KAAK,SAAS,EAC5B,CAAC;gBACD,MAAM,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAChF,CAAC;YACD,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBACxE,MAAM,OAAO,CAAC,GAAG,CAAC,WAAW,CAC3B,8BAA8B,CAAC,MAAM,CAAC,MAAM,CAAC,EAC7C,OAAO,CAAC,OAAO,CAAC,MAAM,CACvB,CAAC;YACJ,CAAC;YACD,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBACxE,MAAM,KAAK,GAAG,2BAA2B,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAClE,IAAI,KAAK,KAAK,SAAS;oBAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,yBAAyB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAClE,IAAI,CAAC,OAAO,CAAC,EAAE;YAAE,OAAO,OAAO,CAAC;QAChC,OAAO;YACL,EAAE,EAAE,IAAI;YACR,KAAK,EAAE;gBACL,SAAS,EAAE,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,QAAQ,CAAC;gBAC1F,OAAO,EAAE,OAAO,CAAC,KAAK;aACvB;YACD,WAAW,EAAE,EAAE;SAChB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,EAAE,EAAE,KAAK;YACT,WAAW,EAAE;gBACX;oBACE,QAAQ,EAAE,OAAO;oBACjB,IAAI,EAAE,6BAA6B;oBACnC,OAAO,EAAE,sDAAsD;iBAChE;aACF;SACF,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["import type {\n InfraOwnedResource,\n InfraReconcileResult,\n InfraResult,\n} from '@ankhorage/contracts/infra';\n\nimport type {\n KubernetesDriverOptions,\n KubernetesDriverRequest,\n} from '../../../../types/kubernetesDriver';\nimport { getKubernetesResourceReference } from '../../utils/getKubernetesResourceReference';\nimport { readKubernetesOwnedResource } from '../../utils/readKubernetesOwnedResource';\nimport { getKubernetesOutputsAsync } from './getKubernetesOutputsAsync';\nimport { prepareKubernetesChangesAsync } from './prepareKubernetesChangesAsync';\n\n/*** Apply desired changes and prune only obsolete, non-persistent Infra-owned resources. */\nexport async function reconcileKubernetesResourcesAsync(\n options: KubernetesDriverOptions,\n request: KubernetesDriverRequest,\n): Promise<InfraResult<InfraReconcileResult>> {\n const prepared = await prepareKubernetesChangesAsync(options, request);\n if (!prepared.ok) return prepared;\n\n try {\n const retained: InfraOwnedResource[] = [];\n for (const change of prepared.value.changes) {\n if (\n (change.action.operation === 'create' || change.action.operation === 'update') &&\n change.desired !== undefined\n ) {\n await options.api.applyAsync(change.desired.resource, request.context.signal);\n }\n if (change.action.operation === 'delete' && change.actual !== undefined) {\n await options.api.deleteAsync(\n getKubernetesResourceReference(change.actual),\n request.context.signal,\n );\n }\n if (change.action.operation === 'retain' && change.actual !== undefined) {\n const owner = readKubernetesOwnedResource(change.actual, request);\n if (owner !== undefined) retained.push(owner);\n }\n }\n\n const outputs = await getKubernetesOutputsAsync(options, request);\n if (!outputs.ok) return outputs;\n return {\n ok: true,\n value: {\n resources: [...prepared.value.projection.resources.map(({ owner }) => owner), ...retained],\n outputs: outputs.value,\n },\n diagnostics: [],\n };\n } catch {\n return {\n ok: false,\n diagnostics: [\n {\n severity: 'error',\n code: 'kubernetes-reconcile-failed',\n message: 'Kubernetes resources could not be reconciled safely.',\n },\n ],\n };\n }\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { InfraDestroyRequest, InfraReconcileResult, InfraResult } from '@ankhorage/contracts/infra';
|
|
2
|
+
import type { KubernetesDriverOptions, KubernetesDriverRequest } from '../../../../types/kubernetesDriver';
|
|
3
|
+
/*** Remove owned resources in reverse dependency order while enforcing persistence authorization. */
|
|
4
|
+
export declare function removeKubernetesResourcesAsync(options: KubernetesDriverOptions, request: KubernetesDriverRequest, destroy: InfraDestroyRequest): Promise<InfraResult<InfraReconcileResult>>;
|
|
5
|
+
//# sourceMappingURL=removeKubernetesResourcesAsync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"removeKubernetesResourcesAsync.d.ts","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/removeKubernetesResourcesAsync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EAEnB,oBAAoB,EAEpB,WAAW,EACZ,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EACV,uBAAuB,EACvB,uBAAuB,EACxB,MAAM,oCAAoC,CAAC;AAM5C,qGAAqG;AACrG,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,uBAAuB,EAChC,OAAO,EAAE,uBAAuB,EAChC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,CA6B5C"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { getKubernetesOwnershipQuery } from '../../utils/getKubernetesOwnershipQuery';
|
|
2
|
+
import { getKubernetesResourceReference } from '../../utils/getKubernetesResourceReference';
|
|
3
|
+
import { readKubernetesOwnedResource } from '../../utils/readKubernetesOwnedResource';
|
|
4
|
+
import { sortKubernetesResourcesForRemoval } from '../../utils/sortKubernetesResourcesForRemoval';
|
|
5
|
+
/*** Remove owned resources in reverse dependency order while enforcing persistence authorization. */
|
|
6
|
+
export async function removeKubernetesResourcesAsync(options, request, destroy) {
|
|
7
|
+
if (!isConfirmed(request, destroy)) {
|
|
8
|
+
return {
|
|
9
|
+
ok: false,
|
|
10
|
+
diagnostics: [
|
|
11
|
+
{
|
|
12
|
+
severity: 'error',
|
|
13
|
+
code: 'kubernetes-destroy-unconfirmed',
|
|
14
|
+
message: 'Kubernetes removal requires matching explicit project and environment confirmation.',
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
return await performRemovalAsync(options, request, destroy);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return {
|
|
24
|
+
ok: false,
|
|
25
|
+
diagnostics: [
|
|
26
|
+
{
|
|
27
|
+
severity: 'error',
|
|
28
|
+
code: 'kubernetes-remove-failed',
|
|
29
|
+
message: 'Kubernetes resources could not be removed safely.',
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/*** Execute the already-confirmed removal against the narrow owned-resource selector. */
|
|
36
|
+
async function performRemovalAsync(options, request, destroy) {
|
|
37
|
+
const observed = await options.api.listOwnedAsync(getKubernetesOwnershipQuery(request));
|
|
38
|
+
const owned = observed.flatMap((resource) => {
|
|
39
|
+
const owner = readKubernetesOwnedResource(resource, request);
|
|
40
|
+
return owner === undefined ? [] : [{ resource, owner }];
|
|
41
|
+
});
|
|
42
|
+
const retained = [];
|
|
43
|
+
const retainNamespace = owned.some(({ owner }) => owner.persistent && !canDelete(owner, destroy));
|
|
44
|
+
for (const { resource, owner } of sortKubernetesResourcesForRemoval(owned)) {
|
|
45
|
+
if ((resource.kind === 'Namespace' && retainNamespace) || !canDelete(owner, destroy)) {
|
|
46
|
+
retained.push(owner);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
await options.api.deleteAsync(getKubernetesResourceReference(resource), request.context.signal);
|
|
50
|
+
}
|
|
51
|
+
return { ok: true, value: { resources: retained, outputs: [] }, diagnostics: [] };
|
|
52
|
+
}
|
|
53
|
+
/*** Confirm request identity at both destroy boundaries. */
|
|
54
|
+
function isConfirmed(request, destroy) {
|
|
55
|
+
return (destroy.projectId === request.context.projectId &&
|
|
56
|
+
destroy.environment === request.context.environment &&
|
|
57
|
+
destroy.confirmation.projectId === request.context.projectId &&
|
|
58
|
+
destroy.confirmation.environment === request.context.environment);
|
|
59
|
+
}
|
|
60
|
+
/*** Decide whether explicit persistence policy authorizes this exact owner. */
|
|
61
|
+
function canDelete(owner, destroy) {
|
|
62
|
+
if (!owner.persistent)
|
|
63
|
+
return true;
|
|
64
|
+
return (owner.retention === 'delete-on-destroy' &&
|
|
65
|
+
destroy.persistence.policy === 'delete' &&
|
|
66
|
+
destroy.persistence.confirmedResources.some((identity) => identitiesEqual(identity, owner.identity)));
|
|
67
|
+
}
|
|
68
|
+
/*** Compare canonical resource identities without object-reference assumptions. */
|
|
69
|
+
function identitiesEqual(left, right) {
|
|
70
|
+
return (left.projectId === right.projectId &&
|
|
71
|
+
left.environment === right.environment &&
|
|
72
|
+
left.adapter === right.adapter &&
|
|
73
|
+
left.resourceId === right.resourceId);
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=removeKubernetesResourcesAsync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"removeKubernetesResourcesAsync.js","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/removeKubernetesResourcesAsync.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n InfraDestroyRequest,\n InfraOwnedResource,\n InfraReconcileResult,\n InfraResourceIdentity,\n InfraResult,\n} from '@ankhorage/contracts/infra';\n\nimport type {\n KubernetesDriverOptions,\n KubernetesDriverRequest,\n} from '../../../../types/kubernetesDriver';\nimport { getKubernetesOwnershipQuery } from '../../utils/getKubernetesOwnershipQuery';\nimport { getKubernetesResourceReference } from '../../utils/getKubernetesResourceReference';\nimport { readKubernetesOwnedResource } from '../../utils/readKubernetesOwnedResource';\nimport { sortKubernetesResourcesForRemoval } from '../../utils/sortKubernetesResourcesForRemoval';\n\n/*** Remove owned resources in reverse dependency order while enforcing persistence authorization. */\nexport async function removeKubernetesResourcesAsync(\n options: KubernetesDriverOptions,\n request: KubernetesDriverRequest,\n destroy: InfraDestroyRequest,\n): Promise<InfraResult<InfraReconcileResult>> {\n if (!isConfirmed(request, destroy)) {\n return {\n ok: false,\n diagnostics: [\n {\n severity: 'error',\n code: 'kubernetes-destroy-unconfirmed',\n message:\n 'Kubernetes removal requires matching explicit project and environment confirmation.',\n },\n ],\n };\n }\n\n try {\n return await performRemovalAsync(options, request, destroy);\n } catch {\n return {\n ok: false,\n diagnostics: [\n {\n severity: 'error',\n code: 'kubernetes-remove-failed',\n message: 'Kubernetes resources could not be removed safely.',\n },\n ],\n };\n }\n}\n\n/*** Execute the already-confirmed removal against the narrow owned-resource selector. */\nasync function performRemovalAsync(\n options: KubernetesDriverOptions,\n request: KubernetesDriverRequest,\n destroy: InfraDestroyRequest,\n): Promise<InfraResult<InfraReconcileResult>> {\n const observed = await options.api.listOwnedAsync(getKubernetesOwnershipQuery(request));\n const owned = observed.flatMap((resource) => {\n const owner = readKubernetesOwnedResource(resource, request);\n return owner === undefined ? [] : [{ resource, owner }];\n });\n const retained: InfraOwnedResource[] = [];\n const retainNamespace = owned.some(({ owner }) => owner.persistent && !canDelete(owner, destroy));\n for (const { resource, owner } of sortKubernetesResourcesForRemoval(owned)) {\n if ((resource.kind === 'Namespace' && retainNamespace) || !canDelete(owner, destroy)) {\n retained.push(owner);\n continue;\n }\n await options.api.deleteAsync(getKubernetesResourceReference(resource), request.context.signal);\n }\n return { ok: true, value: { resources: retained, outputs: [] }, diagnostics: [] };\n}\n\n/*** Confirm request identity at both destroy boundaries. */\nfunction isConfirmed(request: KubernetesDriverRequest, destroy: InfraDestroyRequest): boolean {\n return (\n destroy.projectId === request.context.projectId &&\n destroy.environment === request.context.environment &&\n destroy.confirmation.projectId === request.context.projectId &&\n destroy.confirmation.environment === request.context.environment\n );\n}\n\n/*** Decide whether explicit persistence policy authorizes this exact owner. */\nfunction canDelete(owner: InfraOwnedResource, destroy: InfraDestroyRequest): boolean {\n if (!owner.persistent) return true;\n return (\n owner.retention === 'delete-on-destroy' &&\n destroy.persistence.policy === 'delete' &&\n destroy.persistence.confirmedResources.some((identity) =>\n identitiesEqual(identity, owner.identity),\n )\n );\n}\n\n/*** Compare canonical resource identities without object-reference assumptions. */\nfunction identitiesEqual(left: InfraResourceIdentity, right: InfraResourceIdentity): boolean {\n return (\n left.projectId === right.projectId &&\n left.environment === right.environment &&\n left.adapter === right.adapter &&\n left.resourceId === right.resourceId\n );\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { InfraOutput, InfraResult, InfraWorkloadSpec } from '@ankhorage/contracts/infra';
|
|
2
|
+
import type { KubernetesResolvedWorkloadValues } from '../../../../types/kubernetesResources';
|
|
3
|
+
/*** Resolve public outputs while retaining privileged workload values as secret references. */
|
|
4
|
+
export declare function resolveKubernetesWorkloadValues(outputs: readonly InfraOutput[], workload: InfraWorkloadSpec): InfraResult<KubernetesResolvedWorkloadValues>;
|
|
5
|
+
//# sourceMappingURL=resolveKubernetesWorkloadValues.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveKubernetesWorkloadValues.d.ts","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/resolveKubernetesWorkloadValues.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,WAAW,EACX,WAAW,EACX,iBAAiB,EAElB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EACV,gCAAgC,EAEjC,MAAM,uCAAuC,CAAC;AAG/C,+FAA+F;AAC/F,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,QAAQ,EAAE,iBAAiB,GAC1B,WAAW,CAAC,gCAAgC,CAAC,CAkC/C"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { toKubernetesName } from '../../utils/toKubernetesName';
|
|
2
|
+
/*** Resolve public outputs while retaining privileged workload values as secret references. */
|
|
3
|
+
export function resolveKubernetesWorkloadValues(outputs, workload) {
|
|
4
|
+
const environment = {};
|
|
5
|
+
const files = {};
|
|
6
|
+
const secrets = [];
|
|
7
|
+
const diagnostics = [];
|
|
8
|
+
for (const [name, value] of Object.entries(workload.environment ?? {}).sort(([a], [b]) => a.localeCompare(b))) {
|
|
9
|
+
assignValue(outputs, value, { kind: 'environment', name }, environment, secrets, diagnostics, `env-${name}`);
|
|
10
|
+
}
|
|
11
|
+
for (const [index, file] of (workload.files ?? []).entries()) {
|
|
12
|
+
assignValue(outputs, file.content, { kind: 'file', path: file.path }, files, secrets, diagnostics, `file-${index}`);
|
|
13
|
+
}
|
|
14
|
+
return diagnostics.length > 0
|
|
15
|
+
? { ok: false, diagnostics }
|
|
16
|
+
: { ok: true, value: { environment, files, secrets }, diagnostics: [] };
|
|
17
|
+
}
|
|
18
|
+
/*** Assign one portable value without resolving privileged content. */
|
|
19
|
+
function assignValue(outputs, value, target, publicValues, secrets, diagnostics, key) {
|
|
20
|
+
const publicKey = target.kind === 'environment' ? target.name : target.path;
|
|
21
|
+
if (value.kind === 'literal') {
|
|
22
|
+
Object.assign(publicValues, { [publicKey]: value.value });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (value.kind === 'secret') {
|
|
26
|
+
secrets.push({ key: toKubernetesName(key), reference: value.reference, target });
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const matches = outputs.filter((output) => output.owner.resourceId === value.resourceId && output.name === value.output);
|
|
30
|
+
const [output] = matches;
|
|
31
|
+
if (matches.length !== 1 || output === undefined) {
|
|
32
|
+
diagnostics.push({
|
|
33
|
+
severity: 'error',
|
|
34
|
+
code: 'kubernetes-output-unresolved',
|
|
35
|
+
message: `Workload output ${value.resourceId}.${value.output} did not resolve uniquely.`,
|
|
36
|
+
});
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (output.visibility === 'secret') {
|
|
40
|
+
secrets.push({ key: toKubernetesName(key), reference: output.reference, target });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
Object.assign(publicValues, { [publicKey]: String(output.value) });
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=resolveKubernetesWorkloadValues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveKubernetesWorkloadValues.js","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/resolveKubernetesWorkloadValues.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n InfraDiagnostic,\n InfraOutput,\n InfraResult,\n InfraWorkloadSpec,\n InfraWorkloadValue,\n} from '@ankhorage/contracts/infra';\n\nimport type {\n KubernetesResolvedWorkloadValues,\n KubernetesSecretTarget,\n} from '../../../../types/kubernetesResources';\nimport { toKubernetesName } from '../../utils/toKubernetesName';\n\n/*** Resolve public outputs while retaining privileged workload values as secret references. */\nexport function resolveKubernetesWorkloadValues(\n outputs: readonly InfraOutput[],\n workload: InfraWorkloadSpec,\n): InfraResult<KubernetesResolvedWorkloadValues> {\n const environment: Record<string, string> = {};\n const files: Record<string, string> = {};\n const secrets: KubernetesSecretTarget[] = [];\n const diagnostics: InfraDiagnostic[] = [];\n\n for (const [name, value] of Object.entries(workload.environment ?? {}).sort(([a], [b]) =>\n a.localeCompare(b),\n )) {\n assignValue(\n outputs,\n value,\n { kind: 'environment', name },\n environment,\n secrets,\n diagnostics,\n `env-${name}`,\n );\n }\n for (const [index, file] of (workload.files ?? []).entries()) {\n assignValue(\n outputs,\n file.content,\n { kind: 'file', path: file.path },\n files,\n secrets,\n diagnostics,\n `file-${index}`,\n );\n }\n\n return diagnostics.length > 0\n ? { ok: false, diagnostics }\n : { ok: true, value: { environment, files, secrets }, diagnostics: [] };\n}\n\n/*** Assign one portable value without resolving privileged content. */\nfunction assignValue(\n outputs: readonly InfraOutput[],\n value: InfraWorkloadValue,\n target: KubernetesSecretTarget['target'],\n publicValues: Record<string, string>,\n secrets: KubernetesSecretTarget[],\n diagnostics: InfraDiagnostic[],\n key: string,\n): void {\n const publicKey = target.kind === 'environment' ? target.name : target.path;\n if (value.kind === 'literal') {\n Object.assign(publicValues, { [publicKey]: value.value });\n return;\n }\n if (value.kind === 'secret') {\n secrets.push({ key: toKubernetesName(key), reference: value.reference, target });\n return;\n }\n\n const matches = outputs.filter(\n (output) => output.owner.resourceId === value.resourceId && output.name === value.output,\n );\n const [output] = matches;\n if (matches.length !== 1 || output === undefined) {\n diagnostics.push({\n severity: 'error',\n code: 'kubernetes-output-unresolved',\n message: `Workload output ${value.resourceId}.${value.output} did not resolve uniquely.`,\n });\n return;\n }\n if (output.visibility === 'secret') {\n secrets.push({ key: toKubernetesName(key), reference: output.reference, target });\n return;\n }\n Object.assign(publicValues, { [publicKey]: String(output.value) });\n}\n"]}
|
package/dist/features/workload-reconciliation/application/use-cases/validateKubernetesWorkloads.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { InfraDiagnostic, InfraWorkloadSpec } from '@ankhorage/contracts/infra';
|
|
2
|
+
/*** Validate portable invariants required for deterministic Kubernetes projection. */
|
|
3
|
+
export declare function validateKubernetesWorkloads(workloads: readonly InfraWorkloadSpec[]): readonly InfraDiagnostic[];
|
|
4
|
+
//# sourceMappingURL=validateKubernetesWorkloads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateKubernetesWorkloads.d.ts","sourceRoot":"","sources":["../../../../../src/features/workload-reconciliation/application/use-cases/validateKubernetesWorkloads.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAErF,sFAAsF;AACtF,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,SAAS,iBAAiB,EAAE,GACtC,SAAS,eAAe,EAAE,CAuB5B"}
|