@intentius/chant-lexicon-k8s 0.0.14 → 0.0.16
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 +8 -4
- package/dist/manifest.json +1 -1
- package/dist/rules/latest-image-tag.ts +121 -0
- package/dist/rules/missing-resource-limits.ts +111 -0
- 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 +148 -0
- package/src/composites/aks-external-dns-agent.ts +199 -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 +1060 -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-ingress.ts +143 -0
- package/src/composites/gce-pd-storage-class.ts +85 -0
- package/src/composites/gke-external-dns-agent.ts +175 -0
- package/src/composites/gke-fluent-bit-agent.ts +219 -0
- package/src/composites/gke-gateway.ts +143 -0
- package/src/composites/gke-otel-collector.ts +229 -0
- package/src/composites/index.ts +31 -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 +20 -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/lint/rules/latest-image-tag.ts +121 -0
- package/src/lint/rules/missing-resource-limits.ts +111 -0
- package/src/lint/rules/rules.test.ts +192 -0
- package/src/plugin.test.ts +2 -2
- package/src/plugin.ts +129 -209
- package/src/serializer.test.ts +120 -0
- package/src/serializer.ts +16 -4
- package/src/skills/chant-k8s-aks.md +146 -0
- package/src/skills/chant-k8s-gke.md +191 -0
- package/src/skills/kubernetes-patterns.md +183 -0
- package/src/skills/kubernetes-security.md +237 -0
- /package/{dist → src}/skills/chant-k8s-eks.md +0 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgicIngress composite — Ingress with Azure Application Gateway Ingress Controller annotations.
|
|
3
|
+
*
|
|
4
|
+
* @aks Full `appgw.ingress.kubernetes.io/*` annotation set including SSL redirect,
|
|
5
|
+
* WAF policy, backend path prefix, and cookie-based affinity.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface AgicIngressHost {
|
|
9
|
+
/** Hostname (e.g., "api.example.com"). */
|
|
10
|
+
hostname: string;
|
|
11
|
+
/** Path rules for this host. */
|
|
12
|
+
paths: Array<{
|
|
13
|
+
path: string;
|
|
14
|
+
pathType?: string;
|
|
15
|
+
serviceName: string;
|
|
16
|
+
servicePort: number;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface AgicIngressProps {
|
|
21
|
+
/** Ingress name — used in metadata and labels. */
|
|
22
|
+
name: string;
|
|
23
|
+
/** Host definitions with paths. */
|
|
24
|
+
hosts: AgicIngressHost[];
|
|
25
|
+
/** Azure Key Vault certificate URI or secret name for TLS. */
|
|
26
|
+
certificateArn?: string;
|
|
27
|
+
/** WAF policy resource ID. */
|
|
28
|
+
wafPolicyId?: string;
|
|
29
|
+
/** Health check path for backend. */
|
|
30
|
+
healthCheckPath?: string;
|
|
31
|
+
/** Enable HTTP->HTTPS redirect (default: true when certificateArn set). */
|
|
32
|
+
sslRedirect?: boolean;
|
|
33
|
+
/** Backend path prefix override. */
|
|
34
|
+
backendPathPrefix?: string;
|
|
35
|
+
/** Enable cookie-based affinity (default: false). */
|
|
36
|
+
cookieAffinity?: boolean;
|
|
37
|
+
/** Additional annotations on the Ingress. */
|
|
38
|
+
annotations?: Record<string, string>;
|
|
39
|
+
/** Additional labels to apply to all resources. */
|
|
40
|
+
labels?: Record<string, string>;
|
|
41
|
+
/** Namespace for all resources. */
|
|
42
|
+
namespace?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface AgicIngressResult {
|
|
46
|
+
ingress: Record<string, unknown>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Create an AgicIngress composite — returns prop objects for
|
|
51
|
+
* an Ingress with Azure Application Gateway Ingress Controller annotations.
|
|
52
|
+
*
|
|
53
|
+
* @aks
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* import { AgicIngress } from "@intentius/chant-lexicon-k8s";
|
|
57
|
+
*
|
|
58
|
+
* const { ingress } = AgicIngress({
|
|
59
|
+
* name: "api-ingress",
|
|
60
|
+
* hosts: [
|
|
61
|
+
* {
|
|
62
|
+
* hostname: "api.example.com",
|
|
63
|
+
* paths: [{ path: "/", serviceName: "api", servicePort: 80 }],
|
|
64
|
+
* },
|
|
65
|
+
* ],
|
|
66
|
+
* certificateArn: "keyvault-secret-name",
|
|
67
|
+
* wafPolicyId: "/subscriptions/.../Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies/my-waf",
|
|
68
|
+
* });
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export function AgicIngress(props: AgicIngressProps): AgicIngressResult {
|
|
72
|
+
const {
|
|
73
|
+
name,
|
|
74
|
+
hosts,
|
|
75
|
+
certificateArn,
|
|
76
|
+
wafPolicyId,
|
|
77
|
+
healthCheckPath,
|
|
78
|
+
sslRedirect,
|
|
79
|
+
backendPathPrefix,
|
|
80
|
+
cookieAffinity = false,
|
|
81
|
+
annotations: extraAnnotations = {},
|
|
82
|
+
labels: extraLabels = {},
|
|
83
|
+
namespace,
|
|
84
|
+
} = props;
|
|
85
|
+
|
|
86
|
+
const commonLabels: Record<string, string> = {
|
|
87
|
+
"app.kubernetes.io/name": name,
|
|
88
|
+
"app.kubernetes.io/managed-by": "chant",
|
|
89
|
+
...extraLabels,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// Build AGIC annotations
|
|
93
|
+
const annotations: Record<string, string> = {
|
|
94
|
+
"kubernetes.io/ingress.class": "azure/application-gateway",
|
|
95
|
+
...extraAnnotations,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
if (sslRedirect ?? (certificateArn !== undefined)) {
|
|
99
|
+
annotations["appgw.ingress.kubernetes.io/ssl-redirect"] = "true";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (certificateArn) {
|
|
103
|
+
annotations["appgw.ingress.kubernetes.io/appgw-ssl-certificate"] = certificateArn;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (wafPolicyId) {
|
|
107
|
+
annotations["appgw.ingress.kubernetes.io/waf-policy-for-path"] = wafPolicyId;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (healthCheckPath) {
|
|
111
|
+
annotations["appgw.ingress.kubernetes.io/health-probe-path"] = healthCheckPath;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (backendPathPrefix) {
|
|
115
|
+
annotations["appgw.ingress.kubernetes.io/backend-path-prefix"] = backendPathPrefix;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (cookieAffinity) {
|
|
119
|
+
annotations["appgw.ingress.kubernetes.io/cookie-based-affinity"] = "true";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const ingressRules = hosts.map((host) => ({
|
|
123
|
+
host: host.hostname,
|
|
124
|
+
http: {
|
|
125
|
+
paths: host.paths.map((p) => ({
|
|
126
|
+
path: p.path,
|
|
127
|
+
pathType: p.pathType ?? "Prefix",
|
|
128
|
+
backend: {
|
|
129
|
+
service: { name: p.serviceName, port: { number: p.servicePort } },
|
|
130
|
+
},
|
|
131
|
+
})),
|
|
132
|
+
},
|
|
133
|
+
}));
|
|
134
|
+
|
|
135
|
+
const ingressProps: Record<string, unknown> = {
|
|
136
|
+
metadata: {
|
|
137
|
+
name,
|
|
138
|
+
...(namespace && { namespace }),
|
|
139
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "ingress" },
|
|
140
|
+
annotations,
|
|
141
|
+
},
|
|
142
|
+
spec: {
|
|
143
|
+
rules: ingressRules,
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
return { ingress: ingressProps };
|
|
148
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AksExternalDnsAgent composite — Deployment + ServiceAccount + ClusterRole + ClusterRoleBinding.
|
|
3
|
+
*
|
|
4
|
+
* @aks Like ExternalDnsAgent but uses --provider=azure and AKS Workload Identity
|
|
5
|
+
* instead of IRSA for Azure DNS management.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface AksExternalDnsAgentProps {
|
|
9
|
+
/** Azure managed identity client ID for Workload Identity. */
|
|
10
|
+
clientId: string;
|
|
11
|
+
/** Azure resource group containing the DNS zone. */
|
|
12
|
+
resourceGroup: string;
|
|
13
|
+
/** Azure subscription ID. */
|
|
14
|
+
subscriptionId: string;
|
|
15
|
+
/** Azure tenant ID. */
|
|
16
|
+
tenantId: string;
|
|
17
|
+
/** Domain filters — only manage DNS records for these domains. */
|
|
18
|
+
domainFilters: string[];
|
|
19
|
+
/** TXT record owner ID for identifying managed records. */
|
|
20
|
+
txtOwnerId?: string;
|
|
21
|
+
/** Source of DNS records (default: "ingress"). */
|
|
22
|
+
source?: string;
|
|
23
|
+
/** Agent name (default: "external-dns"). */
|
|
24
|
+
name?: string;
|
|
25
|
+
/** Container image (default: "registry.k8s.io/external-dns/external-dns:v0.14.0"). */
|
|
26
|
+
image?: string;
|
|
27
|
+
/** Namespace (default: "kube-system"). */
|
|
28
|
+
namespace?: string;
|
|
29
|
+
/** Additional labels. */
|
|
30
|
+
labels?: Record<string, string>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface AksExternalDnsAgentResult {
|
|
34
|
+
deployment: Record<string, unknown>;
|
|
35
|
+
serviceAccount: Record<string, unknown>;
|
|
36
|
+
clusterRole: Record<string, unknown>;
|
|
37
|
+
clusterRoleBinding: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Create an AksExternalDnsAgent composite — returns prop objects for
|
|
42
|
+
* a Deployment, ServiceAccount (with AKS Workload Identity), ClusterRole, and ClusterRoleBinding.
|
|
43
|
+
*
|
|
44
|
+
* @aks
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* import { AksExternalDnsAgent } from "@intentius/chant-lexicon-k8s";
|
|
48
|
+
*
|
|
49
|
+
* const { deployment, serviceAccount, clusterRole, clusterRoleBinding } = AksExternalDnsAgent({
|
|
50
|
+
* clientId: "00000000-0000-0000-0000-000000000000",
|
|
51
|
+
* resourceGroup: "my-rg",
|
|
52
|
+
* subscriptionId: "00000000-0000-0000-0000-000000000000",
|
|
53
|
+
* tenantId: "00000000-0000-0000-0000-000000000000",
|
|
54
|
+
* domainFilters: ["example.com"],
|
|
55
|
+
* txtOwnerId: "my-cluster",
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export function AksExternalDnsAgent(props: AksExternalDnsAgentProps): AksExternalDnsAgentResult {
|
|
60
|
+
const {
|
|
61
|
+
clientId,
|
|
62
|
+
resourceGroup,
|
|
63
|
+
subscriptionId,
|
|
64
|
+
tenantId,
|
|
65
|
+
domainFilters,
|
|
66
|
+
txtOwnerId,
|
|
67
|
+
source = "ingress",
|
|
68
|
+
name = "external-dns",
|
|
69
|
+
image = "registry.k8s.io/external-dns/external-dns:v0.14.0",
|
|
70
|
+
namespace = "kube-system",
|
|
71
|
+
labels: extraLabels = {},
|
|
72
|
+
} = props;
|
|
73
|
+
|
|
74
|
+
const saName = `${name}-sa`;
|
|
75
|
+
const clusterRoleName = `${name}-role`;
|
|
76
|
+
const bindingName = `${name}-binding`;
|
|
77
|
+
|
|
78
|
+
const commonLabels: Record<string, string> = {
|
|
79
|
+
"app.kubernetes.io/name": name,
|
|
80
|
+
"app.kubernetes.io/managed-by": "chant",
|
|
81
|
+
...extraLabels,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const args: string[] = [
|
|
85
|
+
`--source=${source}`,
|
|
86
|
+
"--provider=azure",
|
|
87
|
+
`--azure-resource-group=${resourceGroup}`,
|
|
88
|
+
`--azure-subscription-id=${subscriptionId}`,
|
|
89
|
+
"--policy=upsert-only",
|
|
90
|
+
"--registry=txt",
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
for (const domain of domainFilters) {
|
|
94
|
+
args.push(`--domain-filter=${domain}`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (txtOwnerId) {
|
|
98
|
+
args.push(`--txt-owner-id=${txtOwnerId}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const deploymentProps: Record<string, unknown> = {
|
|
102
|
+
metadata: {
|
|
103
|
+
name,
|
|
104
|
+
namespace,
|
|
105
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "dns" },
|
|
106
|
+
},
|
|
107
|
+
spec: {
|
|
108
|
+
replicas: 1,
|
|
109
|
+
selector: { matchLabels: { "app.kubernetes.io/name": name } },
|
|
110
|
+
template: {
|
|
111
|
+
metadata: {
|
|
112
|
+
labels: {
|
|
113
|
+
"app.kubernetes.io/name": name,
|
|
114
|
+
"azure.workload.identity/use": "true",
|
|
115
|
+
...extraLabels,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
spec: {
|
|
119
|
+
serviceAccountName: saName,
|
|
120
|
+
containers: [
|
|
121
|
+
{
|
|
122
|
+
name,
|
|
123
|
+
image,
|
|
124
|
+
args,
|
|
125
|
+
env: [
|
|
126
|
+
{ name: "AZURE_TENANT_ID", value: tenantId },
|
|
127
|
+
{ name: "AZURE_SUBSCRIPTION_ID", value: subscriptionId },
|
|
128
|
+
{ name: "AZURE_RESOURCE_GROUP", value: resourceGroup },
|
|
129
|
+
],
|
|
130
|
+
resources: {
|
|
131
|
+
requests: { cpu: "50m", memory: "64Mi" },
|
|
132
|
+
limits: { cpu: "100m", memory: "128Mi" },
|
|
133
|
+
},
|
|
134
|
+
securityContext: {
|
|
135
|
+
runAsNonRoot: true,
|
|
136
|
+
runAsUser: 65534,
|
|
137
|
+
readOnlyRootFilesystem: true,
|
|
138
|
+
allowPrivilegeEscalation: false,
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const serviceAccountProps: Record<string, unknown> = {
|
|
148
|
+
metadata: {
|
|
149
|
+
name: saName,
|
|
150
|
+
namespace,
|
|
151
|
+
labels: {
|
|
152
|
+
...commonLabels,
|
|
153
|
+
"app.kubernetes.io/component": "dns",
|
|
154
|
+
"azure.workload.identity/use": "true",
|
|
155
|
+
},
|
|
156
|
+
annotations: {
|
|
157
|
+
"azure.workload.identity/client-id": clientId,
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const clusterRoleProps: Record<string, unknown> = {
|
|
163
|
+
metadata: {
|
|
164
|
+
name: clusterRoleName,
|
|
165
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
|
|
166
|
+
},
|
|
167
|
+
rules: [
|
|
168
|
+
{ apiGroups: [""], resources: ["services", "endpoints", "pods"], verbs: ["get", "watch", "list"] },
|
|
169
|
+
{ apiGroups: ["extensions", "networking.k8s.io"], resources: ["ingresses"], verbs: ["get", "watch", "list"] },
|
|
170
|
+
{ apiGroups: [""], resources: ["nodes"], verbs: ["list", "watch"] },
|
|
171
|
+
],
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const clusterRoleBindingProps: Record<string, unknown> = {
|
|
175
|
+
metadata: {
|
|
176
|
+
name: bindingName,
|
|
177
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
|
|
178
|
+
},
|
|
179
|
+
roleRef: {
|
|
180
|
+
apiGroup: "rbac.authorization.k8s.io",
|
|
181
|
+
kind: "ClusterRole",
|
|
182
|
+
name: clusterRoleName,
|
|
183
|
+
},
|
|
184
|
+
subjects: [
|
|
185
|
+
{
|
|
186
|
+
kind: "ServiceAccount",
|
|
187
|
+
name: saName,
|
|
188
|
+
namespace,
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
deployment: deploymentProps,
|
|
195
|
+
serviceAccount: serviceAccountProps,
|
|
196
|
+
clusterRole: clusterRoleProps,
|
|
197
|
+
clusterRoleBinding: clusterRoleBindingProps,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
@@ -13,6 +13,7 @@ export interface AlbIngressHost {
|
|
|
13
13
|
path: string;
|
|
14
14
|
pathType?: string;
|
|
15
15
|
serviceName: string;
|
|
16
|
+
/** Port on the Kubernetes Service (not the container port). */
|
|
16
17
|
servicePort: number;
|
|
17
18
|
}>;
|
|
18
19
|
}
|
|
@@ -105,7 +106,7 @@ export function AlbIngress(props: AlbIngressProps): AlbIngressResult {
|
|
|
105
106
|
annotations["alb.ingress.kubernetes.io/listen-ports"] = '[{"HTTPS":443}]';
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
if (sslRedirect ??
|
|
109
|
+
if (sslRedirect ?? !!certificateArn) {
|
|
109
110
|
annotations["alb.ingress.kubernetes.io/ssl-redirect"] = "443";
|
|
110
111
|
}
|
|
111
112
|
|
|
@@ -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
|
+
}
|