@intentius/chant-lexicon-k8s 0.0.13 → 0.0.15

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 (54) hide show
  1. package/dist/integrity.json +20 -15
  2. package/dist/manifest.json +1 -1
  3. package/dist/rules/wk8204.ts +33 -1
  4. package/dist/rules/wk8304.ts +70 -0
  5. package/dist/rules/wk8305.ts +115 -0
  6. package/dist/rules/wk8306.ts +50 -0
  7. package/dist/skills/chant-k8s-eks.md +156 -0
  8. package/dist/skills/chant-k8s-patterns.md +245 -0
  9. package/dist/skills/chant-k8s.md +36 -227
  10. package/package.json +27 -24
  11. package/src/codegen/docs.ts +5 -5
  12. package/src/composites/adot-collector.ts +245 -0
  13. package/src/composites/agic-ingress.ts +149 -0
  14. package/src/composites/alb-ingress.ts +152 -0
  15. package/src/composites/autoscaled-service.ts +51 -0
  16. package/src/composites/azure-disk-storage-class.ts +82 -0
  17. package/src/composites/azure-file-storage-class.ts +77 -0
  18. package/src/composites/azure-monitor-collector.ts +232 -0
  19. package/src/composites/batch-job.ts +221 -0
  20. package/src/composites/composites.test.ts +1584 -0
  21. package/src/composites/config-connector-context.ts +62 -0
  22. package/src/composites/configured-app.ts +224 -0
  23. package/src/composites/cron-workload.ts +6 -0
  24. package/src/composites/ebs-storage-class.ts +96 -0
  25. package/src/composites/efs-storage-class.ts +77 -0
  26. package/src/composites/external-dns-agent.ts +174 -0
  27. package/src/composites/filestore-storage-class.ts +79 -0
  28. package/src/composites/fluent-bit-agent.ts +220 -0
  29. package/src/composites/gce-pd-storage-class.ts +85 -0
  30. package/src/composites/gke-gateway.ts +143 -0
  31. package/src/composites/index.ts +47 -0
  32. package/src/composites/irsa-service-account.ts +114 -0
  33. package/src/composites/metrics-server.ts +224 -0
  34. package/src/composites/monitored-service.ts +221 -0
  35. package/src/composites/network-isolated-app.ts +202 -0
  36. package/src/composites/node-agent.ts +6 -0
  37. package/src/composites/secure-ingress.ts +149 -0
  38. package/src/composites/security-context.ts +10 -0
  39. package/src/composites/sidecar-app.ts +207 -0
  40. package/src/composites/stateful-app.ts +67 -15
  41. package/src/composites/web-app.ts +104 -35
  42. package/src/composites/worker-pool.ts +38 -4
  43. package/src/composites/workload-identity-sa.ts +118 -0
  44. package/src/composites/workload-identity-service-account.ts +116 -0
  45. package/src/index.ts +24 -2
  46. package/src/lint/post-synth/post-synth.test.ts +362 -1
  47. package/src/lint/post-synth/wk8204.ts +33 -1
  48. package/src/lint/post-synth/wk8304.ts +70 -0
  49. package/src/lint/post-synth/wk8305.ts +115 -0
  50. package/src/lint/post-synth/wk8306.ts +50 -0
  51. package/src/plugin.test.ts +2 -2
  52. package/src/plugin.ts +556 -242
  53. package/src/serializer.test.ts +120 -0
  54. package/src/serializer.ts +16 -4
@@ -0,0 +1,82 @@
1
+ /**
2
+ * AzureDiskStorageClass composite — StorageClass for Azure Disk CSI driver.
3
+ *
4
+ * @aks Creates a StorageClass with the `disk.csi.azure.com` provisioner.
5
+ */
6
+
7
+ export interface AzureDiskStorageClassProps {
8
+ /** StorageClass name. */
9
+ name: string;
10
+ /** Azure Disk SKU name (default: "Premium_LRS"). */
11
+ skuName?: string;
12
+ /** OS disk caching mode (default: "ReadOnly"). */
13
+ cachingMode?: string;
14
+ /** Network access policy (default: "AllowAll"). */
15
+ networkAccessPolicy?: string;
16
+ /** Reclaim policy (default: "Delete"). */
17
+ reclaimPolicy?: string;
18
+ /** Volume binding mode (default: "WaitForFirstConsumer"). */
19
+ volumeBindingMode?: string;
20
+ /** Allow volume expansion (default: true). */
21
+ allowVolumeExpansion?: boolean;
22
+ /** Additional labels. */
23
+ labels?: Record<string, string>;
24
+ }
25
+
26
+ export interface AzureDiskStorageClassResult {
27
+ storageClass: Record<string, unknown>;
28
+ }
29
+
30
+ /**
31
+ * Create an AzureDiskStorageClass composite — returns prop objects for
32
+ * a StorageClass with the Azure Disk CSI provisioner.
33
+ *
34
+ * @aks
35
+ * @example
36
+ * ```ts
37
+ * import { AzureDiskStorageClass } from "@intentius/chant-lexicon-k8s";
38
+ *
39
+ * const { storageClass } = AzureDiskStorageClass({
40
+ * name: "premium-disk",
41
+ * skuName: "Premium_LRS",
42
+ * });
43
+ * ```
44
+ */
45
+ export function AzureDiskStorageClass(props: AzureDiskStorageClassProps): AzureDiskStorageClassResult {
46
+ const {
47
+ name,
48
+ skuName = "Premium_LRS",
49
+ cachingMode = "ReadOnly",
50
+ networkAccessPolicy = "AllowAll",
51
+ reclaimPolicy = "Delete",
52
+ volumeBindingMode = "WaitForFirstConsumer",
53
+ allowVolumeExpansion = true,
54
+ labels: extraLabels = {},
55
+ } = props;
56
+
57
+ const commonLabels: Record<string, string> = {
58
+ "app.kubernetes.io/name": name,
59
+ "app.kubernetes.io/managed-by": "chant",
60
+ ...extraLabels,
61
+ };
62
+
63
+ const parameters: Record<string, string> = {
64
+ skuName,
65
+ cachingMode,
66
+ networkAccessPolicy,
67
+ };
68
+
69
+ const storageClassProps: Record<string, unknown> = {
70
+ metadata: {
71
+ name,
72
+ labels: { ...commonLabels, "app.kubernetes.io/component": "storage" },
73
+ },
74
+ provisioner: "disk.csi.azure.com",
75
+ parameters,
76
+ reclaimPolicy,
77
+ volumeBindingMode,
78
+ allowVolumeExpansion,
79
+ };
80
+
81
+ return { storageClass: storageClassProps };
82
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * AzureFileStorageClass composite — StorageClass for Azure Files CSI driver.
3
+ *
4
+ * @aks Creates a StorageClass with the `file.csi.azure.com` provisioner.
5
+ * Azure Files provides ReadWriteMany access mode (shared across pods/nodes).
6
+ */
7
+
8
+ export interface AzureFileStorageClassProps {
9
+ /** StorageClass name. */
10
+ name: string;
11
+ /** Azure Files SKU name (default: "Premium_LRS"). */
12
+ skuName?: string;
13
+ /** Protocol for Azure Files (default: "smb"). */
14
+ protocol?: string;
15
+ /** Specific Azure file share name (optional; dynamically provisioned if omitted). */
16
+ shareName?: string;
17
+ /** Reclaim policy (default: "Delete"). */
18
+ reclaimPolicy?: string;
19
+ /** Additional labels. */
20
+ labels?: Record<string, string>;
21
+ }
22
+
23
+ export interface AzureFileStorageClassResult {
24
+ storageClass: Record<string, unknown>;
25
+ }
26
+
27
+ /**
28
+ * Create an AzureFileStorageClass composite — returns prop objects for
29
+ * a StorageClass with the Azure Files CSI provisioner.
30
+ *
31
+ * @aks
32
+ * @example
33
+ * ```ts
34
+ * import { AzureFileStorageClass } from "@intentius/chant-lexicon-k8s";
35
+ *
36
+ * const { storageClass } = AzureFileStorageClass({
37
+ * name: "azure-files-shared",
38
+ * skuName: "Premium_LRS",
39
+ * protocol: "nfs",
40
+ * });
41
+ * ```
42
+ */
43
+ export function AzureFileStorageClass(props: AzureFileStorageClassProps): AzureFileStorageClassResult {
44
+ const {
45
+ name,
46
+ skuName = "Premium_LRS",
47
+ protocol = "smb",
48
+ shareName,
49
+ reclaimPolicy = "Delete",
50
+ labels: extraLabels = {},
51
+ } = props;
52
+
53
+ const commonLabels: Record<string, string> = {
54
+ "app.kubernetes.io/name": name,
55
+ "app.kubernetes.io/managed-by": "chant",
56
+ ...extraLabels,
57
+ };
58
+
59
+ const parameters: Record<string, string> = {
60
+ skuName,
61
+ protocol,
62
+ };
63
+
64
+ if (shareName) parameters.shareName = shareName;
65
+
66
+ const storageClassProps: Record<string, unknown> = {
67
+ metadata: {
68
+ name,
69
+ labels: { ...commonLabels, "app.kubernetes.io/component": "storage" },
70
+ },
71
+ provisioner: "file.csi.azure.com",
72
+ parameters,
73
+ reclaimPolicy,
74
+ };
75
+
76
+ return { storageClass: storageClassProps };
77
+ }
@@ -0,0 +1,232 @@
1
+ /**
2
+ * AzureMonitorCollector composite — DaemonSet + RBAC + ConfigMap for Azure Monitor / OTel collector.
3
+ *
4
+ * @aks Azure Monitor agent with OpenTelemetry collector config for
5
+ * Log Analytics workspace integration on AKS clusters.
6
+ */
7
+
8
+ export interface AzureMonitorCollectorProps {
9
+ /** Azure Log Analytics workspace ID. */
10
+ workspaceId: string;
11
+ /** AKS cluster name. */
12
+ clusterName: string;
13
+ /** Agent name (default: "azure-monitor-collector"). */
14
+ name?: string;
15
+ /** Collector image (default: "mcr.microsoft.com/azuremonitor/containerinsights/ciprod:latest"). */
16
+ image?: string;
17
+ /** Namespace (default: "azure-monitor"). */
18
+ namespace?: string;
19
+ /** Additional labels. */
20
+ labels?: Record<string, string>;
21
+ /** CPU request (default: "100m"). */
22
+ cpuRequest?: string;
23
+ /** Memory request (default: "256Mi"). */
24
+ memoryRequest?: string;
25
+ /** CPU limit (default: "500m"). */
26
+ cpuLimit?: string;
27
+ /** Memory limit (default: "512Mi"). */
28
+ memoryLimit?: string;
29
+ /** Azure AD client ID for Workload Identity (adds azure.workload.identity annotations to ServiceAccount). */
30
+ clientId?: string;
31
+ }
32
+
33
+ export interface AzureMonitorCollectorResult {
34
+ daemonSet: Record<string, unknown>;
35
+ serviceAccount: Record<string, unknown>;
36
+ clusterRole: Record<string, unknown>;
37
+ clusterRoleBinding: Record<string, unknown>;
38
+ configMap: Record<string, unknown>;
39
+ }
40
+
41
+ /**
42
+ * Create an AzureMonitorCollector composite — returns prop objects for
43
+ * a DaemonSet, ServiceAccount, ClusterRole, ClusterRoleBinding, and ConfigMap.
44
+ *
45
+ * @aks
46
+ * @example
47
+ * ```ts
48
+ * import { AzureMonitorCollector } from "@intentius/chant-lexicon-k8s";
49
+ *
50
+ * const { daemonSet, serviceAccount, clusterRole, clusterRoleBinding, configMap } = AzureMonitorCollector({
51
+ * workspaceId: "00000000-0000-0000-0000-000000000000",
52
+ * clusterName: "my-aks-cluster",
53
+ * });
54
+ * ```
55
+ */
56
+ export function AzureMonitorCollector(props: AzureMonitorCollectorProps): AzureMonitorCollectorResult {
57
+ const {
58
+ workspaceId,
59
+ clusterName,
60
+ name = "azure-monitor-collector",
61
+ image = "mcr.microsoft.com/azuremonitor/containerinsights/ciprod:latest",
62
+ namespace = "azure-monitor",
63
+ labels: extraLabels = {},
64
+ cpuRequest = "100m",
65
+ memoryRequest = "256Mi",
66
+ cpuLimit = "500m",
67
+ memoryLimit = "512Mi",
68
+ clientId,
69
+ } = props;
70
+
71
+ const saName = `${name}-sa`;
72
+ const clusterRoleName = `${name}-role`;
73
+ const bindingName = `${name}-binding`;
74
+ const configMapName = `${name}-config`;
75
+
76
+ const commonLabels: Record<string, string> = {
77
+ "app.kubernetes.io/name": name,
78
+ "app.kubernetes.io/managed-by": "chant",
79
+ ...extraLabels,
80
+ };
81
+
82
+ // Build OTel collector config YAML for Azure Monitor
83
+ const collectorConfig = `receivers:
84
+ otlp:
85
+ protocols:
86
+ grpc:
87
+ endpoint: 0.0.0.0:4317
88
+ http:
89
+ endpoint: 0.0.0.0:4318
90
+
91
+ processors:
92
+ batch:
93
+ timeout: 30s
94
+ send_batch_size: 8192
95
+
96
+ exporters:
97
+ azuremonitor:
98
+ connection_string: InstrumentationKey=\${APPINSIGHTS_INSTRUMENTATIONKEY}
99
+ endpoint: https://dc.services.visualstudio.com/v2/track
100
+ azuremonitor/logs:
101
+ workspace_id: ${workspaceId}
102
+ cluster_name: ${clusterName}
103
+
104
+ service:
105
+ pipelines:
106
+ metrics:
107
+ receivers: [otlp]
108
+ processors: [batch]
109
+ exporters: [azuremonitor]
110
+ traces:
111
+ receivers: [otlp]
112
+ processors: [batch]
113
+ exporters: [azuremonitor]
114
+ logs:
115
+ receivers: [otlp]
116
+ processors: [batch]
117
+ exporters: [azuremonitor/logs]
118
+ `;
119
+
120
+ const container: Record<string, unknown> = {
121
+ name,
122
+ image,
123
+ ports: [
124
+ { containerPort: 4317, name: "otlp-grpc" },
125
+ { containerPort: 4318, name: "otlp-http" },
126
+ ],
127
+ env: [
128
+ { name: "AKS_CLUSTER_NAME", value: clusterName },
129
+ { name: "WORKSPACE_ID", value: workspaceId },
130
+ ],
131
+ resources: {
132
+ requests: { cpu: cpuRequest, memory: memoryRequest },
133
+ limits: { cpu: cpuLimit, memory: memoryLimit },
134
+ },
135
+ volumeMounts: [
136
+ { name: "config", mountPath: "/etc/otel", readOnly: true },
137
+ ],
138
+ };
139
+
140
+ const daemonSetProps: Record<string, unknown> = {
141
+ metadata: {
142
+ name,
143
+ namespace,
144
+ labels: { ...commonLabels, "app.kubernetes.io/component": "agent" },
145
+ },
146
+ spec: {
147
+ selector: { matchLabels: { "app.kubernetes.io/name": name } },
148
+ template: {
149
+ metadata: { labels: { "app.kubernetes.io/name": name, ...extraLabels } },
150
+ spec: {
151
+ serviceAccountName: saName,
152
+ containers: [container],
153
+ volumes: [
154
+ { name: "config", configMap: { name: configMapName } },
155
+ ],
156
+ tolerations: [{ operator: "Exists" }],
157
+ },
158
+ },
159
+ },
160
+ };
161
+
162
+ const saLabels: Record<string, string> = {
163
+ ...commonLabels,
164
+ "app.kubernetes.io/component": "agent",
165
+ };
166
+
167
+ if (clientId) {
168
+ saLabels["azure.workload.identity/use"] = "true";
169
+ }
170
+
171
+ const serviceAccountProps: Record<string, unknown> = {
172
+ metadata: {
173
+ name: saName,
174
+ namespace,
175
+ labels: saLabels,
176
+ ...(clientId ? { annotations: { "azure.workload.identity/client-id": clientId } } : {}),
177
+ },
178
+ };
179
+
180
+ const clusterRoleProps: Record<string, unknown> = {
181
+ metadata: {
182
+ name: clusterRoleName,
183
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
184
+ },
185
+ rules: [
186
+ { apiGroups: [""], resources: ["pods", "nodes", "endpoints"], verbs: ["get", "list", "watch"] },
187
+ { apiGroups: ["apps"], resources: ["replicasets"], verbs: ["get", "list", "watch"] },
188
+ { apiGroups: ["batch"], resources: ["jobs"], verbs: ["get", "list", "watch"] },
189
+ { apiGroups: [""], resources: ["nodes/proxy"], verbs: ["get"] },
190
+ { apiGroups: [""], resources: ["nodes/stats", "configmaps", "events"], verbs: ["create", "get"] },
191
+ { apiGroups: [""], resources: ["configmaps"], verbs: ["get", "update", "create"], resourceNames: ["otel-container-insight-clusterleader"] },
192
+ ],
193
+ };
194
+
195
+ const clusterRoleBindingProps: Record<string, unknown> = {
196
+ metadata: {
197
+ name: bindingName,
198
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
199
+ },
200
+ roleRef: {
201
+ apiGroup: "rbac.authorization.k8s.io",
202
+ kind: "ClusterRole",
203
+ name: clusterRoleName,
204
+ },
205
+ subjects: [
206
+ {
207
+ kind: "ServiceAccount",
208
+ name: saName,
209
+ namespace,
210
+ },
211
+ ],
212
+ };
213
+
214
+ const configMapProps: Record<string, unknown> = {
215
+ metadata: {
216
+ name: configMapName,
217
+ namespace,
218
+ labels: { ...commonLabels, "app.kubernetes.io/component": "config" },
219
+ },
220
+ data: {
221
+ "config.yaml": collectorConfig,
222
+ },
223
+ };
224
+
225
+ return {
226
+ daemonSet: daemonSetProps,
227
+ serviceAccount: serviceAccountProps,
228
+ clusterRole: clusterRoleProps,
229
+ clusterRoleBinding: clusterRoleBindingProps,
230
+ configMap: configMapProps,
231
+ };
232
+ }
@@ -0,0 +1,221 @@
1
+ /**
2
+ * BatchJob composite — Job + optional RBAC (ServiceAccount + Role + RoleBinding).
3
+ *
4
+ * A higher-level construct for one-shot batch jobs (data migrations,
5
+ * seed tasks, backups). For scheduled workloads, use CronWorkload instead.
6
+ */
7
+
8
+ import type { ContainerSecurityContext } from "./security-context";
9
+
10
+ /** Parse a K8s memory string (e.g. "256Mi", "1Gi") to bytes for comparison. */
11
+ function parseMemoryBytes(mem: string): number {
12
+ const match = mem.match(/^(\d+(?:\.\d+)?)\s*(Ki|Mi|Gi|Ti|k|M|G|T|[eE]\d+)?$/);
13
+ if (!match) return 0;
14
+ const value = parseFloat(match[1]);
15
+ const unit = match[2] ?? "";
16
+ const multipliers: Record<string, number> = {
17
+ "": 1, Ki: 1024, Mi: 1024 ** 2, Gi: 1024 ** 3, Ti: 1024 ** 4,
18
+ k: 1e3, M: 1e6, G: 1e9, T: 1e12,
19
+ };
20
+ if (unit.startsWith("e") || unit.startsWith("E")) return value * 10 ** parseInt(unit.slice(1));
21
+ return value * (multipliers[unit] ?? 1);
22
+ }
23
+
24
+ /** Parse a K8s CPU string (e.g. "500m", "1") to millicores for comparison. */
25
+ function parseCpuMillis(cpu: string): number {
26
+ if (cpu.endsWith("m")) return parseFloat(cpu.slice(0, -1));
27
+ return parseFloat(cpu) * 1000;
28
+ }
29
+
30
+ export interface BatchJobProps {
31
+ /** Job name — used in metadata and labels. */
32
+ name: string;
33
+ /** Container image. */
34
+ image: string;
35
+ /** Command to run in the container. */
36
+ command?: string[];
37
+ /** Arguments to the command. */
38
+ args?: string[];
39
+ /** Number of retries before marking the job as failed (default: 6). */
40
+ backoffLimit?: number;
41
+ /** Seconds after completion before the job is eligible for GC. */
42
+ ttlSecondsAfterFinished?: number;
43
+ /** Number of completions required (default: 1). */
44
+ completions?: number;
45
+ /** Number of pods running in parallel (default: 1). */
46
+ parallelism?: number;
47
+ /** Restart policy (default: "OnFailure"). */
48
+ restartPolicy?: string;
49
+ /** RBAC rules for the service account. Omit for defaults; pass [] to skip RBAC entirely. */
50
+ rbacRules?: Array<{
51
+ apiGroups: string[];
52
+ resources: string[];
53
+ verbs: string[];
54
+ }>;
55
+ /** Additional labels to apply to all resources. */
56
+ labels?: Record<string, string>;
57
+ /** Namespace for all resources. */
58
+ namespace?: string;
59
+ /** CPU request (default: "100m"). */
60
+ cpuRequest?: string;
61
+ /** Memory request (default: "128Mi"). */
62
+ memoryRequest?: string;
63
+ /** CPU limit (default: "500m"). */
64
+ cpuLimit?: string;
65
+ /** Memory limit (default: "256Mi"). */
66
+ memoryLimit?: string;
67
+ /** Environment variables for the container. */
68
+ env?: Array<{ name: string; value: string }>;
69
+ /** Container security context (supports PSS restricted fields). */
70
+ securityContext?: ContainerSecurityContext;
71
+ }
72
+
73
+ export interface BatchJobResult {
74
+ job: Record<string, unknown>;
75
+ serviceAccount?: Record<string, unknown>;
76
+ role?: Record<string, unknown>;
77
+ roleBinding?: Record<string, unknown>;
78
+ }
79
+
80
+ /**
81
+ * Create a BatchJob composite — returns prop objects for
82
+ * a Job, and optional ServiceAccount, Role, and RoleBinding.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * import { BatchJob } from "@intentius/chant-lexicon-k8s";
87
+ *
88
+ * const { job, serviceAccount, role, roleBinding } = BatchJob({
89
+ * name: "db-migrate",
90
+ * image: "migrate:1.0",
91
+ * command: ["python", "manage.py", "migrate"],
92
+ * backoffLimit: 3,
93
+ * ttlSecondsAfterFinished: 3600,
94
+ * });
95
+ * ```
96
+ */
97
+ export function BatchJob(props: BatchJobProps): BatchJobResult {
98
+ const {
99
+ name,
100
+ image,
101
+ command,
102
+ args,
103
+ backoffLimit = 6,
104
+ ttlSecondsAfterFinished,
105
+ completions = 1,
106
+ parallelism = 1,
107
+ restartPolicy = "OnFailure",
108
+ rbacRules,
109
+ labels: extraLabels = {},
110
+ namespace,
111
+ cpuRequest = "100m",
112
+ memoryRequest: rawMemoryRequest = "128Mi",
113
+ cpuLimit: rawCpuLimit = "500m",
114
+ memoryLimit: rawMemoryLimit = "256Mi",
115
+ env,
116
+ securityContext,
117
+ } = props;
118
+
119
+ // Ensure limits >= requests (K8s rejects pods where request > limit).
120
+ const memoryRequest = rawMemoryRequest;
121
+ const memoryLimit = parseMemoryBytes(rawMemoryRequest) > parseMemoryBytes(rawMemoryLimit)
122
+ ? rawMemoryRequest : rawMemoryLimit;
123
+ const cpuLimit = parseCpuMillis(cpuRequest) > parseCpuMillis(rawCpuLimit)
124
+ ? cpuRequest : rawCpuLimit;
125
+
126
+ const saName = `${name}-sa`;
127
+ const roleName = `${name}-role`;
128
+ const bindingName = `${name}-binding`;
129
+
130
+ const commonLabels: Record<string, string> = {
131
+ "app.kubernetes.io/name": name,
132
+ "app.kubernetes.io/managed-by": "chant",
133
+ ...extraLabels,
134
+ };
135
+
136
+ // undefined → default RBAC rules; explicit [] → no RBAC resources
137
+ const createRbac = rbacRules === undefined || rbacRules.length > 0;
138
+ const effectiveRbacRules = rbacRules === undefined
139
+ ? [{ apiGroups: [""], resources: ["pods"], verbs: ["get", "list"] }]
140
+ : rbacRules;
141
+
142
+ const container: Record<string, unknown> = {
143
+ name,
144
+ image,
145
+ ...(command && { command }),
146
+ ...(args && { args }),
147
+ resources: {
148
+ limits: { cpu: cpuLimit, memory: memoryLimit },
149
+ requests: { cpu: cpuRequest, memory: memoryRequest },
150
+ },
151
+ ...(env && { env }),
152
+ ...(securityContext && { securityContext }),
153
+ };
154
+
155
+ const jobProps: Record<string, unknown> = {
156
+ metadata: {
157
+ name,
158
+ ...(namespace && { namespace }),
159
+ labels: { ...commonLabels, "app.kubernetes.io/component": "batch" },
160
+ },
161
+ spec: {
162
+ backoffLimit,
163
+ completions,
164
+ parallelism,
165
+ ...(ttlSecondsAfterFinished !== undefined && { ttlSecondsAfterFinished }),
166
+ template: {
167
+ metadata: { labels: { "app.kubernetes.io/name": name, ...extraLabels } },
168
+ spec: {
169
+ ...(createRbac && { serviceAccountName: saName }),
170
+ restartPolicy,
171
+ containers: [container],
172
+ },
173
+ },
174
+ },
175
+ };
176
+
177
+ const result: BatchJobResult = {
178
+ job: jobProps,
179
+ };
180
+
181
+ if (createRbac) {
182
+ result.serviceAccount = {
183
+ metadata: {
184
+ name: saName,
185
+ ...(namespace && { namespace }),
186
+ labels: { ...commonLabels, "app.kubernetes.io/component": "batch" },
187
+ },
188
+ };
189
+
190
+ result.role = {
191
+ metadata: {
192
+ name: roleName,
193
+ ...(namespace && { namespace }),
194
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
195
+ },
196
+ rules: effectiveRbacRules,
197
+ };
198
+
199
+ result.roleBinding = {
200
+ metadata: {
201
+ name: bindingName,
202
+ ...(namespace && { namespace }),
203
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
204
+ },
205
+ roleRef: {
206
+ apiGroup: "rbac.authorization.k8s.io",
207
+ kind: "Role",
208
+ name: roleName,
209
+ },
210
+ subjects: [
211
+ {
212
+ kind: "ServiceAccount",
213
+ name: saName,
214
+ ...(namespace && { namespace }),
215
+ },
216
+ ],
217
+ };
218
+ }
219
+
220
+ return result;
221
+ }