1/**
2 * Internal helpers for binding Kubernetes objects onto an `AWS.EKS.Cluster`
3 * through its `KubernetesObjectBinding` contract. The cluster's reconciler
4 * server-side-applies every bound object after the control plane is ACTIVE.
5 * Not exported from the EKS index — the public path for raw manifests is
6 * `Kubernetes.Manifest`.
7 */
8import * as Effect from "effect/Effect";
9import type { Cluster } from "../Cluster.ts";
10import {
11 kubernetesObjectKey,
12 toKubernetesObjectRef,
13 type KubernetesObjectDefinition,
14 type KubernetesObjectMetadata,
15} from "../../../Kubernetes/internal/objects.ts";
16
17export interface ClusterObjectProps {
18 /** Target EKS cluster that will own this Kubernetes object. */
19 cluster: Cluster;
20 /** Kubernetes API version. */
21 apiVersion: string;
22 /** Kubernetes kind. */
23 kind: string;
24 /** Object metadata. `name` defaults to the logical id. */
25 metadata?: Omit<KubernetesObjectMetadata, "name"> & {
26 name?: string;
27 };
28 /** Extra top-level fields merged into the final Kubernetes object. */
29 body?: Record<string, unknown>;
30}
31
32export interface ClusterObjectRef {
33 cluster: Cluster;
34 apiVersion: string;
35 kind: string;
36 name: string;
37 namespace: string | undefined;
38 key: string;
39 object: KubernetesObjectDefinition;
40}
41
42export const kubernetesBindingSid = (object: KubernetesObjectDefinition) =>
43 `Kubernetes.Object(${kubernetesObjectKey(toKubernetesObjectRef(object))})`;
44
45export const ClusterObject = Effect.fn(function* (
46 id: string,
47 props: ClusterObjectProps,
48) {
49 const object = {
50 apiVersion: props.apiVersion,
51 kind: props.kind,
52 metadata: {
53 name: props.metadata?.name ?? id,
54 namespace: props.metadata?.namespace,
55 labels: props.metadata?.labels,
56 annotations: props.metadata?.annotations,
57 },
58 ...props.body,
59 } satisfies KubernetesObjectDefinition;
60
61 yield* props.cluster.bind(kubernetesBindingSid(object), {
62 type: "kubernetes-object",
63 object,
64 });
65
66 const ref = toKubernetesObjectRef(object);
67
68 return {
69 cluster: props.cluster,
70 apiVersion: ref.apiVersion,
71 kind: ref.kind,
72 name: ref.name,
73 namespace: ref.namespace,
74 key: kubernetesObjectKey(ref),
75 object,
76 } satisfies ClusterObjectRef;
77});
78
79export const namespaceNameOf = (
80 namespace: string | { name: string } | ClusterObjectRef,
81): string => (typeof namespace === "string" ? namespace : namespace.name);
82
83export const clusterServiceAccount = (
84 id: string,
85 props: {
86 cluster: Cluster;
87 namespace: string | { name: string } | ClusterObjectRef;
88 name?: string;
89 labels?: Record<string, string>;
90 annotations?: Record<string, string>;
91 },
92) =>
93 ClusterObject(id, {
94 cluster: props.cluster,
95 apiVersion: "v1",
96 kind: "ServiceAccount",
97 metadata: {
98 name: props.name,
99 namespace: namespaceNameOf(props.namespace),
100 labels: props.labels,
101 annotations: props.annotations,
102 },
103 });