@intentius/chant-lexicon-k8s 0.0.14 → 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.
- package/dist/integrity.json +6 -3
- package/dist/manifest.json +1 -1
- package/dist/rules/wk8204.ts +33 -1
- package/dist/rules/wk8304.ts +70 -0
- package/dist/rules/wk8305.ts +115 -0
- package/dist/rules/wk8306.ts +50 -0
- package/package.json +27 -24
- package/src/codegen/docs.ts +1 -1
- package/src/composites/adot-collector.ts +8 -2
- package/src/composites/agic-ingress.ts +149 -0
- package/src/composites/alb-ingress.ts +2 -1
- package/src/composites/autoscaled-service.ts +25 -7
- package/src/composites/azure-disk-storage-class.ts +82 -0
- package/src/composites/azure-file-storage-class.ts +77 -0
- package/src/composites/azure-monitor-collector.ts +232 -0
- package/src/composites/batch-job.ts +36 -3
- package/src/composites/composites.test.ts +701 -0
- package/src/composites/config-connector-context.ts +62 -0
- package/src/composites/configured-app.ts +6 -0
- package/src/composites/cron-workload.ts +6 -0
- package/src/composites/ebs-storage-class.ts +4 -4
- package/src/composites/external-dns-agent.ts +6 -0
- package/src/composites/filestore-storage-class.ts +79 -0
- package/src/composites/fluent-bit-agent.ts +5 -0
- package/src/composites/gce-pd-storage-class.ts +85 -0
- package/src/composites/gke-gateway.ts +143 -0
- package/src/composites/index.ts +19 -0
- package/src/composites/metrics-server.ts +1 -1
- package/src/composites/monitored-service.ts +6 -0
- package/src/composites/network-isolated-app.ts +6 -0
- package/src/composites/node-agent.ts +6 -0
- package/src/composites/security-context.ts +10 -0
- package/src/composites/sidecar-app.ts +6 -0
- package/src/composites/stateful-app.ts +4 -7
- package/src/composites/web-app.ts +4 -7
- package/src/composites/worker-pool.ts +4 -7
- package/src/composites/workload-identity-sa.ts +118 -0
- package/src/composites/workload-identity-service-account.ts +116 -0
- package/src/index.ts +6 -1
- package/src/lint/post-synth/post-synth.test.ts +362 -1
- package/src/lint/post-synth/wk8204.ts +33 -1
- package/src/lint/post-synth/wk8304.ts +70 -0
- package/src/lint/post-synth/wk8305.ts +115 -0
- package/src/lint/post-synth/wk8306.ts +50 -0
- package/src/plugin.test.ts +2 -2
- package/src/plugin.ts +4 -1
- package/src/serializer.test.ts +120 -0
- package/src/serializer.ts +16 -4
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* PDB selectors match pod labels, and resource requests are set.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import type { ContainerSecurityContext } from "./security-context";
|
|
10
|
+
|
|
9
11
|
export interface AutoscaledServiceProps {
|
|
10
12
|
/** Application name — used in metadata and labels. */
|
|
11
13
|
name: string;
|
|
@@ -47,13 +49,8 @@ export interface AutoscaledServiceProps {
|
|
|
47
49
|
command?: string[];
|
|
48
50
|
args?: string[];
|
|
49
51
|
}>;
|
|
50
|
-
/**
|
|
51
|
-
securityContext?:
|
|
52
|
-
runAsNonRoot?: boolean;
|
|
53
|
-
readOnlyRootFilesystem?: boolean;
|
|
54
|
-
runAsUser?: number;
|
|
55
|
-
runAsGroup?: number;
|
|
56
|
-
};
|
|
52
|
+
/** Container security context (supports PSS restricted fields). */
|
|
53
|
+
securityContext?: ContainerSecurityContext;
|
|
57
54
|
/** Termination grace period in seconds. */
|
|
58
55
|
terminationGracePeriodSeconds?: number;
|
|
59
56
|
/** Priority class name for pod scheduling. */
|
|
@@ -64,6 +61,14 @@ export interface AutoscaledServiceProps {
|
|
|
64
61
|
namespace?: string;
|
|
65
62
|
/** Environment variables for the container. */
|
|
66
63
|
env?: Array<{ name: string; value: string }>;
|
|
64
|
+
/** Service account name for the pod. */
|
|
65
|
+
serviceAccountName?: string;
|
|
66
|
+
/** Volumes to attach to the pod. */
|
|
67
|
+
volumes?: Array<Record<string, unknown>>;
|
|
68
|
+
/** Volume mounts for the primary container. */
|
|
69
|
+
volumeMounts?: Array<Record<string, unknown>>;
|
|
70
|
+
/** Convenience: auto-generate emptyDir volumes + mounts for writable temp dirs (e.g. ["/tmp", "/var/cache/nginx"]). */
|
|
71
|
+
tmpDirs?: string[];
|
|
67
72
|
}
|
|
68
73
|
|
|
69
74
|
export interface AutoscaledServiceResult {
|
|
@@ -114,6 +119,10 @@ export function AutoscaledService(props: AutoscaledServiceProps): AutoscaledServ
|
|
|
114
119
|
labels: extraLabels = {},
|
|
115
120
|
namespace,
|
|
116
121
|
env,
|
|
122
|
+
serviceAccountName,
|
|
123
|
+
volumes: explicitVolumes = [],
|
|
124
|
+
volumeMounts: explicitMounts = [],
|
|
125
|
+
tmpDirs = [],
|
|
117
126
|
} = props;
|
|
118
127
|
|
|
119
128
|
const commonLabels: Record<string, string> = {
|
|
@@ -137,6 +146,12 @@ export function AutoscaledService(props: AutoscaledServiceProps): AutoscaledServ
|
|
|
137
146
|
}];
|
|
138
147
|
})();
|
|
139
148
|
|
|
149
|
+
// Generate emptyDir volumes/mounts from tmpDirs, then merge with explicit
|
|
150
|
+
const tmpVolumes = tmpDirs.map((_, i) => ({ name: `tmp-${i}`, emptyDir: {} }));
|
|
151
|
+
const tmpMounts = tmpDirs.map((dir, i) => ({ name: `tmp-${i}`, mountPath: dir }));
|
|
152
|
+
const allVolumes = [...explicitVolumes, ...tmpVolumes];
|
|
153
|
+
const allMounts = [...explicitMounts, ...tmpMounts];
|
|
154
|
+
|
|
140
155
|
const resources: Record<string, unknown> = {
|
|
141
156
|
requests: { cpu: cpuRequest, memory: memoryRequest },
|
|
142
157
|
...(cpuLimit || memoryLimit
|
|
@@ -179,6 +194,7 @@ export function AutoscaledService(props: AutoscaledServiceProps): AutoscaledServ
|
|
|
179
194
|
},
|
|
180
195
|
...(env && { env }),
|
|
181
196
|
...(securityContext && { securityContext }),
|
|
197
|
+
...(allMounts.length > 0 && { volumeMounts: allMounts }),
|
|
182
198
|
},
|
|
183
199
|
],
|
|
184
200
|
...(initContainers && {
|
|
@@ -192,6 +208,8 @@ export function AutoscaledService(props: AutoscaledServiceProps): AutoscaledServ
|
|
|
192
208
|
...(topologyConstraints && { topologySpreadConstraints: topologyConstraints }),
|
|
193
209
|
...(terminationGracePeriodSeconds !== undefined && { terminationGracePeriodSeconds }),
|
|
194
210
|
...(priorityClassName && { priorityClassName }),
|
|
211
|
+
...(serviceAccountName && { serviceAccountName }),
|
|
212
|
+
...(allVolumes.length > 0 && { volumes: allVolumes }),
|
|
195
213
|
},
|
|
196
214
|
},
|
|
197
215
|
},
|
|
@@ -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
|
+
}
|
|
@@ -5,6 +5,28 @@
|
|
|
5
5
|
* seed tasks, backups). For scheduled workloads, use CronWorkload instead.
|
|
6
6
|
*/
|
|
7
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
|
+
|
|
8
30
|
export interface BatchJobProps {
|
|
9
31
|
/** Job name — used in metadata and labels. */
|
|
10
32
|
name: string;
|
|
@@ -44,6 +66,8 @@ export interface BatchJobProps {
|
|
|
44
66
|
memoryLimit?: string;
|
|
45
67
|
/** Environment variables for the container. */
|
|
46
68
|
env?: Array<{ name: string; value: string }>;
|
|
69
|
+
/** Container security context (supports PSS restricted fields). */
|
|
70
|
+
securityContext?: ContainerSecurityContext;
|
|
47
71
|
}
|
|
48
72
|
|
|
49
73
|
export interface BatchJobResult {
|
|
@@ -85,12 +109,20 @@ export function BatchJob(props: BatchJobProps): BatchJobResult {
|
|
|
85
109
|
labels: extraLabels = {},
|
|
86
110
|
namespace,
|
|
87
111
|
cpuRequest = "100m",
|
|
88
|
-
memoryRequest = "128Mi",
|
|
89
|
-
cpuLimit = "500m",
|
|
90
|
-
memoryLimit = "256Mi",
|
|
112
|
+
memoryRequest: rawMemoryRequest = "128Mi",
|
|
113
|
+
cpuLimit: rawCpuLimit = "500m",
|
|
114
|
+
memoryLimit: rawMemoryLimit = "256Mi",
|
|
91
115
|
env,
|
|
116
|
+
securityContext,
|
|
92
117
|
} = props;
|
|
93
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
|
+
|
|
94
126
|
const saName = `${name}-sa`;
|
|
95
127
|
const roleName = `${name}-role`;
|
|
96
128
|
const bindingName = `${name}-binding`;
|
|
@@ -117,6 +149,7 @@ export function BatchJob(props: BatchJobProps): BatchJobResult {
|
|
|
117
149
|
requests: { cpu: cpuRequest, memory: memoryRequest },
|
|
118
150
|
},
|
|
119
151
|
...(env && { env }),
|
|
152
|
+
...(securityContext && { securityContext }),
|
|
120
153
|
};
|
|
121
154
|
|
|
122
155
|
const jobProps: Record<string, unknown> = {
|