@intentius/chant-lexicon-k8s 0.0.18 → 0.0.24
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 +9 -4
- package/dist/manifest.json +1 -1
- package/dist/skills/chant-k8s-aks.md +146 -0
- package/{src/skills/kubernetes-patterns.md → dist/skills/chant-k8s-deployment-strategies.md} +1 -1
- package/dist/skills/chant-k8s-eks.md +156 -0
- package/dist/skills/chant-k8s-gke.md +246 -0
- package/{src/skills/kubernetes-security.md → dist/skills/chant-k8s-security.md} +1 -1
- package/dist/skills/chant-k8s.md +66 -3
- package/package.json +20 -2
- package/src/composites/adot-collector.ts +34 -22
- package/src/composites/agic-ingress.ts +14 -6
- package/src/composites/aks-external-dns-agent.ts +29 -18
- package/src/composites/alb-ingress.ts +14 -6
- package/src/composites/autoscaled-service.ts +25 -20
- package/src/composites/azure-disk-storage-class.ts +14 -6
- package/src/composites/azure-file-storage-class.ts +14 -6
- package/src/composites/azure-monitor-collector.ts +34 -22
- package/src/composites/batch-job.ts +25 -17
- package/src/composites/cockroachdb-cluster.ts +148 -58
- package/src/composites/composites.test.ts +369 -363
- package/src/composites/config-connector-context.ts +15 -8
- package/src/composites/configured-app.ts +21 -15
- package/src/composites/cron-workload.ts +25 -20
- package/src/composites/ebs-storage-class.ts +14 -6
- package/src/composites/efs-storage-class.ts +14 -6
- package/src/composites/external-dns-agent.ts +26 -20
- package/src/composites/filestore-storage-class.ts +14 -6
- package/src/composites/fluent-bit-agent.ts +30 -24
- package/src/composites/gce-ingress.ts +14 -6
- package/src/composites/gce-pd-storage-class.ts +14 -6
- package/src/composites/gke-external-dns-agent.ts +34 -21
- package/src/composites/gke-fluent-bit-agent.ts +34 -22
- package/src/composites/gke-gateway.ts +19 -12
- package/src/composites/gke-otel-collector.ts +34 -22
- package/src/composites/irsa-service-account.ts +22 -14
- package/src/composites/metrics-server.ts +41 -26
- package/src/composites/monitored-service.ts +26 -19
- package/src/composites/namespace-env.ts +26 -17
- package/src/composites/network-isolated-app.ts +21 -16
- package/src/composites/node-agent.ts +33 -22
- package/src/composites/secure-ingress.ts +19 -11
- package/src/composites/sidecar-app.ts +17 -12
- package/src/composites/stateful-app.ts +21 -12
- package/src/composites/web-app.ts +25 -21
- package/src/composites/worker-pool.ts +40 -26
- package/src/composites/workload-identity-sa.ts +22 -14
- package/src/composites/workload-identity-service-account.ts +22 -16
- package/src/plugin.ts +130 -614
- package/src/serializer.ts +3 -0
- package/src/skills/chant-k8s-deployment-strategies.md +183 -0
- package/src/skills/chant-k8s-gke.md +55 -0
- package/src/skills/chant-k8s-patterns.md +245 -0
- package/src/skills/chant-k8s-security.md +237 -0
- package/src/skills/chant-k8s.md +305 -0
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* security scanners) that need cluster-wide RBAC and tolerations.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
9
|
+
import { DaemonSet, ServiceAccount, ClusterRole, ClusterRoleBinding, ConfigMap } from "../generated";
|
|
8
10
|
import type { ContainerSecurityContext } from "./security-context";
|
|
9
11
|
|
|
10
12
|
export interface NodeAgentProps {
|
|
@@ -47,14 +49,22 @@ export interface NodeAgentProps {
|
|
|
47
49
|
env?: Array<{ name: string; value: string }>;
|
|
48
50
|
/** Container security context (supports PSS restricted fields). */
|
|
49
51
|
securityContext?: ContainerSecurityContext;
|
|
52
|
+
/** Per-member defaults for fine-grained overrides. */
|
|
53
|
+
defaults?: {
|
|
54
|
+
daemonSet?: Partial<Record<string, unknown>>;
|
|
55
|
+
serviceAccount?: Partial<Record<string, unknown>>;
|
|
56
|
+
clusterRole?: Partial<Record<string, unknown>>;
|
|
57
|
+
clusterRoleBinding?: Partial<Record<string, unknown>>;
|
|
58
|
+
configMap?: Partial<Record<string, unknown>>;
|
|
59
|
+
};
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
export interface NodeAgentResult {
|
|
53
|
-
daemonSet:
|
|
54
|
-
serviceAccount:
|
|
55
|
-
clusterRole:
|
|
56
|
-
clusterRoleBinding:
|
|
57
|
-
configMap?:
|
|
63
|
+
daemonSet: InstanceType<typeof DaemonSet>;
|
|
64
|
+
serviceAccount: InstanceType<typeof ServiceAccount>;
|
|
65
|
+
clusterRole: InstanceType<typeof ClusterRole>;
|
|
66
|
+
clusterRoleBinding: InstanceType<typeof ClusterRoleBinding>;
|
|
67
|
+
configMap?: InstanceType<typeof ConfigMap>;
|
|
58
68
|
}
|
|
59
69
|
|
|
60
70
|
/**
|
|
@@ -75,7 +85,7 @@ export interface NodeAgentResult {
|
|
|
75
85
|
* });
|
|
76
86
|
* ```
|
|
77
87
|
*/
|
|
78
|
-
export
|
|
88
|
+
export const NodeAgent = Composite<NodeAgentProps>((props) => {
|
|
79
89
|
const {
|
|
80
90
|
name,
|
|
81
91
|
image,
|
|
@@ -92,6 +102,7 @@ export function NodeAgent(props: NodeAgentProps): NodeAgentResult {
|
|
|
92
102
|
labels: extraLabels = {},
|
|
93
103
|
env,
|
|
94
104
|
securityContext,
|
|
105
|
+
defaults: defs,
|
|
95
106
|
} = props;
|
|
96
107
|
|
|
97
108
|
const saName = `${name}-sa`;
|
|
@@ -156,7 +167,7 @@ export function NodeAgent(props: NodeAgentProps): NodeAgentResult {
|
|
|
156
167
|
}),
|
|
157
168
|
};
|
|
158
169
|
|
|
159
|
-
const
|
|
170
|
+
const daemonSet = new DaemonSet(mergeDefaults({
|
|
160
171
|
metadata: {
|
|
161
172
|
name,
|
|
162
173
|
...(namespace && { namespace }),
|
|
@@ -169,27 +180,27 @@ export function NodeAgent(props: NodeAgentProps): NodeAgentResult {
|
|
|
169
180
|
spec: podSpec,
|
|
170
181
|
},
|
|
171
182
|
},
|
|
172
|
-
};
|
|
183
|
+
}, defs?.daemonSet));
|
|
173
184
|
|
|
174
|
-
const
|
|
185
|
+
const serviceAccount = new ServiceAccount(mergeDefaults({
|
|
175
186
|
metadata: {
|
|
176
187
|
name: saName,
|
|
177
188
|
...(namespace && { namespace }),
|
|
178
189
|
labels: { ...commonLabels, "app.kubernetes.io/component": "agent" },
|
|
179
190
|
},
|
|
180
|
-
};
|
|
191
|
+
}, defs?.serviceAccount));
|
|
181
192
|
|
|
182
193
|
// ClusterRole — cluster-scoped, no namespace
|
|
183
|
-
const
|
|
194
|
+
const clusterRole = new ClusterRole(mergeDefaults({
|
|
184
195
|
metadata: {
|
|
185
196
|
name: clusterRoleName,
|
|
186
197
|
labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
|
|
187
198
|
},
|
|
188
199
|
rules: rbacRules,
|
|
189
|
-
};
|
|
200
|
+
}, defs?.clusterRole));
|
|
190
201
|
|
|
191
202
|
// ClusterRoleBinding — cluster-scoped, no namespace
|
|
192
|
-
const
|
|
203
|
+
const clusterRoleBinding = new ClusterRoleBinding(mergeDefaults({
|
|
193
204
|
metadata: {
|
|
194
205
|
name: bindingName,
|
|
195
206
|
labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
|
|
@@ -206,25 +217,25 @@ export function NodeAgent(props: NodeAgentProps): NodeAgentResult {
|
|
|
206
217
|
...(namespace && { namespace }),
|
|
207
218
|
},
|
|
208
219
|
],
|
|
209
|
-
};
|
|
220
|
+
}, defs?.clusterRoleBinding));
|
|
210
221
|
|
|
211
|
-
const result:
|
|
212
|
-
daemonSet
|
|
213
|
-
serviceAccount
|
|
214
|
-
clusterRole
|
|
215
|
-
clusterRoleBinding
|
|
222
|
+
const result: Record<string, any> = {
|
|
223
|
+
daemonSet,
|
|
224
|
+
serviceAccount,
|
|
225
|
+
clusterRole,
|
|
226
|
+
clusterRoleBinding,
|
|
216
227
|
};
|
|
217
228
|
|
|
218
229
|
if (config) {
|
|
219
|
-
result.configMap = {
|
|
230
|
+
result.configMap = new ConfigMap(mergeDefaults({
|
|
220
231
|
metadata: {
|
|
221
232
|
name: configMapName,
|
|
222
233
|
...(namespace && { namespace }),
|
|
223
234
|
labels: { ...commonLabels, "app.kubernetes.io/component": "config" },
|
|
224
235
|
},
|
|
225
236
|
data: config,
|
|
226
|
-
};
|
|
237
|
+
}, defs?.configMap));
|
|
227
238
|
}
|
|
228
239
|
|
|
229
240
|
return result;
|
|
230
|
-
}
|
|
241
|
+
}, "NodeAgent");
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
* multiple hosts and paths (unlike the single-path Ingress in WebApp).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
9
|
+
import { Ingress } from "../generated";
|
|
10
|
+
|
|
8
11
|
export interface SecureIngressHost {
|
|
9
12
|
/** Hostname (e.g., "api.example.com"). */
|
|
10
13
|
hostname: string;
|
|
@@ -32,11 +35,16 @@ export interface SecureIngressProps {
|
|
|
32
35
|
labels?: Record<string, string>;
|
|
33
36
|
/** Namespace for all resources. */
|
|
34
37
|
namespace?: string;
|
|
38
|
+
/** Per-member defaults for fine-grained overrides. */
|
|
39
|
+
defaults?: {
|
|
40
|
+
ingress?: Partial<Record<string, unknown>>;
|
|
41
|
+
certificate?: Partial<Record<string, unknown>>;
|
|
42
|
+
};
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
export interface SecureIngressResult {
|
|
38
|
-
ingress:
|
|
39
|
-
certificate?:
|
|
46
|
+
ingress: InstanceType<typeof Ingress>;
|
|
47
|
+
certificate?: InstanceType<typeof Ingress>; // CRD — use Ingress as proxy Declarable
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
/**
|
|
@@ -60,7 +68,7 @@ export interface SecureIngressResult {
|
|
|
60
68
|
* });
|
|
61
69
|
* ```
|
|
62
70
|
*/
|
|
63
|
-
export
|
|
71
|
+
export const SecureIngress = Composite<SecureIngressProps>((props) => {
|
|
64
72
|
const {
|
|
65
73
|
name,
|
|
66
74
|
hosts,
|
|
@@ -69,6 +77,7 @@ export function SecureIngress(props: SecureIngressProps): SecureIngressResult {
|
|
|
69
77
|
annotations: extraAnnotations = {},
|
|
70
78
|
labels: extraLabels = {},
|
|
71
79
|
namespace,
|
|
80
|
+
defaults: defs,
|
|
72
81
|
} = props;
|
|
73
82
|
|
|
74
83
|
const commonLabels: Record<string, string> = {
|
|
@@ -102,7 +111,7 @@ export function SecureIngress(props: SecureIngressProps): SecureIngressResult {
|
|
|
102
111
|
|
|
103
112
|
const hasAnnotations = Object.keys(ingressAnnotations).length > 0;
|
|
104
113
|
|
|
105
|
-
const
|
|
114
|
+
const ingress = new Ingress(mergeDefaults({
|
|
106
115
|
metadata: {
|
|
107
116
|
name,
|
|
108
117
|
...(namespace && { namespace }),
|
|
@@ -121,14 +130,13 @@ export function SecureIngress(props: SecureIngressProps): SecureIngressResult {
|
|
|
121
130
|
],
|
|
122
131
|
}),
|
|
123
132
|
},
|
|
124
|
-
};
|
|
133
|
+
}, defs?.ingress));
|
|
125
134
|
|
|
126
|
-
const result:
|
|
127
|
-
ingress: ingressProps,
|
|
128
|
-
};
|
|
135
|
+
const result: Record<string, any> = { ingress };
|
|
129
136
|
|
|
130
137
|
if (clusterIssuer) {
|
|
131
|
-
|
|
138
|
+
// Certificate is a CRD — use Ingress constructor as a generic Declarable wrapper
|
|
139
|
+
result.certificate = new Ingress(mergeDefaults({
|
|
132
140
|
metadata: {
|
|
133
141
|
name: secretName,
|
|
134
142
|
...(namespace && { namespace }),
|
|
@@ -142,8 +150,8 @@ export function SecureIngress(props: SecureIngressProps): SecureIngressResult {
|
|
|
142
150
|
},
|
|
143
151
|
dnsNames: allHostnames,
|
|
144
152
|
},
|
|
145
|
-
};
|
|
153
|
+
}, defs?.certificate));
|
|
146
154
|
}
|
|
147
155
|
|
|
148
156
|
return result;
|
|
149
|
-
}
|
|
157
|
+
}, "SecureIngress");
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* DB migration init). Supports shared volumes between containers.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
9
|
+
import { Deployment, Service } from "../generated";
|
|
8
10
|
import type { ContainerSecurityContext } from "./security-context";
|
|
9
11
|
|
|
10
12
|
export interface SidecarContainer {
|
|
@@ -74,11 +76,16 @@ export interface SidecarAppProps {
|
|
|
74
76
|
env?: Array<{ name: string; value: string }>;
|
|
75
77
|
/** Container security context for the primary container (supports PSS restricted fields). */
|
|
76
78
|
securityContext?: ContainerSecurityContext;
|
|
79
|
+
/** Per-member defaults for fine-grained overrides. */
|
|
80
|
+
defaults?: {
|
|
81
|
+
deployment?: Partial<Record<string, unknown>>;
|
|
82
|
+
service?: Partial<Record<string, unknown>>;
|
|
83
|
+
};
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
export interface SidecarAppResult {
|
|
80
|
-
deployment:
|
|
81
|
-
service:
|
|
87
|
+
deployment: InstanceType<typeof Deployment>;
|
|
88
|
+
service: InstanceType<typeof Service>;
|
|
82
89
|
}
|
|
83
90
|
|
|
84
91
|
/**
|
|
@@ -103,7 +110,7 @@ export interface SidecarAppResult {
|
|
|
103
110
|
* });
|
|
104
111
|
* ```
|
|
105
112
|
*/
|
|
106
|
-
export
|
|
113
|
+
export const SidecarApp = Composite<SidecarAppProps>((props) => {
|
|
107
114
|
const {
|
|
108
115
|
name,
|
|
109
116
|
image,
|
|
@@ -120,6 +127,7 @@ export function SidecarApp(props: SidecarAppProps): SidecarAppResult {
|
|
|
120
127
|
namespace,
|
|
121
128
|
env,
|
|
122
129
|
securityContext,
|
|
130
|
+
defaults: defs,
|
|
123
131
|
} = props;
|
|
124
132
|
|
|
125
133
|
const commonLabels: Record<string, string> = {
|
|
@@ -171,7 +179,7 @@ export function SidecarApp(props: SidecarAppProps): SidecarAppResult {
|
|
|
171
179
|
...(volumes && volumes.length > 0 && { volumes }),
|
|
172
180
|
};
|
|
173
181
|
|
|
174
|
-
const
|
|
182
|
+
const deployment = new Deployment(mergeDefaults({
|
|
175
183
|
metadata: {
|
|
176
184
|
name,
|
|
177
185
|
...(namespace && { namespace }),
|
|
@@ -185,9 +193,9 @@ export function SidecarApp(props: SidecarAppProps): SidecarAppResult {
|
|
|
185
193
|
spec: podSpec,
|
|
186
194
|
},
|
|
187
195
|
},
|
|
188
|
-
};
|
|
196
|
+
}, defs?.deployment));
|
|
189
197
|
|
|
190
|
-
const
|
|
198
|
+
const service = new Service(mergeDefaults({
|
|
191
199
|
metadata: {
|
|
192
200
|
name,
|
|
193
201
|
...(namespace && { namespace }),
|
|
@@ -198,10 +206,7 @@ export function SidecarApp(props: SidecarAppProps): SidecarAppResult {
|
|
|
198
206
|
ports: [{ port: 80, targetPort: port, protocol: "TCP", name: "http" }],
|
|
199
207
|
type: "ClusterIP",
|
|
200
208
|
},
|
|
201
|
-
};
|
|
209
|
+
}, defs?.service));
|
|
202
210
|
|
|
203
|
-
return {
|
|
204
|
-
|
|
205
|
-
service: serviceProps,
|
|
206
|
-
};
|
|
207
|
-
}
|
|
211
|
+
return { deployment, service };
|
|
212
|
+
}, "SidecarApp");
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* like databases, caches, and message queues.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
9
|
+
import { StatefulSet, Service, PodDisruptionBudget } from "../generated";
|
|
8
10
|
import type { ContainerSecurityContext } from "./security-context";
|
|
9
11
|
|
|
10
12
|
export interface StatefulAppProps {
|
|
@@ -47,12 +49,18 @@ export interface StatefulAppProps {
|
|
|
47
49
|
namespace?: string;
|
|
48
50
|
/** Environment variables for the container. */
|
|
49
51
|
env?: Array<{ name: string; value: string }>;
|
|
52
|
+
/** Per-member defaults for fine-grained overrides. */
|
|
53
|
+
defaults?: {
|
|
54
|
+
statefulSet?: Partial<Record<string, unknown>>;
|
|
55
|
+
service?: Partial<Record<string, unknown>>;
|
|
56
|
+
pdb?: Partial<Record<string, unknown>>;
|
|
57
|
+
};
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
export interface StatefulAppResult {
|
|
53
|
-
statefulSet:
|
|
54
|
-
service:
|
|
55
|
-
pdb?:
|
|
61
|
+
statefulSet: InstanceType<typeof StatefulSet>;
|
|
62
|
+
service: InstanceType<typeof Service>;
|
|
63
|
+
pdb?: InstanceType<typeof PodDisruptionBudget>;
|
|
56
64
|
}
|
|
57
65
|
|
|
58
66
|
/**
|
|
@@ -72,7 +80,7 @@ export interface StatefulAppResult {
|
|
|
72
80
|
* });
|
|
73
81
|
* ```
|
|
74
82
|
*/
|
|
75
|
-
export
|
|
83
|
+
export const StatefulApp = Composite<StatefulAppProps>((props) => {
|
|
76
84
|
const {
|
|
77
85
|
name,
|
|
78
86
|
image,
|
|
@@ -91,6 +99,7 @@ export function StatefulApp(props: StatefulAppProps): StatefulAppResult {
|
|
|
91
99
|
memoryLimit = "1Gi",
|
|
92
100
|
namespace,
|
|
93
101
|
env,
|
|
102
|
+
defaults: defs,
|
|
94
103
|
} = props;
|
|
95
104
|
|
|
96
105
|
const commonLabels: Record<string, string> = {
|
|
@@ -125,7 +134,7 @@ export function StatefulApp(props: StatefulAppProps): StatefulAppResult {
|
|
|
125
134
|
...(priorityClassName && { priorityClassName }),
|
|
126
135
|
};
|
|
127
136
|
|
|
128
|
-
const
|
|
137
|
+
const statefulSet = new StatefulSet(mergeDefaults({
|
|
129
138
|
metadata: {
|
|
130
139
|
name,
|
|
131
140
|
...(namespace && { namespace }),
|
|
@@ -150,10 +159,10 @@ export function StatefulApp(props: StatefulAppProps): StatefulAppResult {
|
|
|
150
159
|
},
|
|
151
160
|
],
|
|
152
161
|
},
|
|
153
|
-
};
|
|
162
|
+
}, defs?.statefulSet));
|
|
154
163
|
|
|
155
164
|
// Headless service (clusterIP: None) for StatefulSet DNS
|
|
156
|
-
const
|
|
165
|
+
const service = new Service(mergeDefaults({
|
|
157
166
|
metadata: {
|
|
158
167
|
name,
|
|
159
168
|
...(namespace && { namespace }),
|
|
@@ -164,12 +173,12 @@ export function StatefulApp(props: StatefulAppProps): StatefulAppResult {
|
|
|
164
173
|
ports: [{ port, targetPort: port, protocol: "TCP", name: "app" }],
|
|
165
174
|
clusterIP: "None",
|
|
166
175
|
},
|
|
167
|
-
};
|
|
176
|
+
}, defs?.service));
|
|
168
177
|
|
|
169
|
-
const result:
|
|
178
|
+
const result: Record<string, any> = { statefulSet, service };
|
|
170
179
|
|
|
171
180
|
if (minAvailable !== undefined) {
|
|
172
|
-
result.pdb = {
|
|
181
|
+
result.pdb = new PodDisruptionBudget(mergeDefaults({
|
|
173
182
|
metadata: {
|
|
174
183
|
name,
|
|
175
184
|
...(namespace && { namespace }),
|
|
@@ -179,8 +188,8 @@ export function StatefulApp(props: StatefulAppProps): StatefulAppResult {
|
|
|
179
188
|
minAvailable,
|
|
180
189
|
selector: { matchLabels: { "app.kubernetes.io/name": name } },
|
|
181
190
|
},
|
|
182
|
-
};
|
|
191
|
+
}, defs?.pdb));
|
|
183
192
|
}
|
|
184
193
|
|
|
185
194
|
return result;
|
|
186
|
-
}
|
|
195
|
+
}, "StatefulApp");
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* with common defaults (health probes, resource limits, labels).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
9
|
+
import { Deployment, Service, Ingress, PodDisruptionBudget } from "../generated";
|
|
8
10
|
import type { ContainerSecurityContext } from "./security-context";
|
|
9
11
|
|
|
10
12
|
export interface WebAppProps {
|
|
@@ -56,13 +58,20 @@ export interface WebAppProps {
|
|
|
56
58
|
namespace?: string;
|
|
57
59
|
/** Environment variables for the container. */
|
|
58
60
|
env?: Array<{ name: string; value: string }>;
|
|
61
|
+
/** Per-member defaults for fine-grained overrides. */
|
|
62
|
+
defaults?: {
|
|
63
|
+
deployment?: Partial<Record<string, unknown>>;
|
|
64
|
+
service?: Partial<Record<string, unknown>>;
|
|
65
|
+
ingress?: Partial<Record<string, unknown>>;
|
|
66
|
+
pdb?: Partial<Record<string, unknown>>;
|
|
67
|
+
};
|
|
59
68
|
}
|
|
60
69
|
|
|
61
70
|
export interface WebAppResult {
|
|
62
|
-
deployment:
|
|
63
|
-
service:
|
|
64
|
-
ingress?:
|
|
65
|
-
pdb?:
|
|
71
|
+
deployment: InstanceType<typeof Deployment>;
|
|
72
|
+
service: InstanceType<typeof Service>;
|
|
73
|
+
ingress?: InstanceType<typeof Ingress>;
|
|
74
|
+
pdb?: InstanceType<typeof PodDisruptionBudget>;
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
/**
|
|
@@ -84,7 +93,7 @@ export interface WebAppResult {
|
|
|
84
93
|
* export { deployment, service, ingress };
|
|
85
94
|
* ```
|
|
86
95
|
*/
|
|
87
|
-
export
|
|
96
|
+
export const WebApp = Composite<WebAppProps>((props) => {
|
|
88
97
|
const {
|
|
89
98
|
name,
|
|
90
99
|
image,
|
|
@@ -102,6 +111,7 @@ export function WebApp(props: WebAppProps): WebAppResult {
|
|
|
102
111
|
terminationGracePeriodSeconds,
|
|
103
112
|
priorityClassName,
|
|
104
113
|
minAvailable,
|
|
114
|
+
defaults: defs,
|
|
105
115
|
} = props;
|
|
106
116
|
|
|
107
117
|
const commonLabels: Record<string, string> = {
|
|
@@ -146,9 +156,7 @@ export function WebApp(props: WebAppProps): WebAppResult {
|
|
|
146
156
|
...(priorityClassName && { priorityClassName }),
|
|
147
157
|
};
|
|
148
158
|
|
|
149
|
-
|
|
150
|
-
// The actual resource instantiation happens in user code with the generated classes.
|
|
151
|
-
const deploymentProps: Record<string, unknown> = {
|
|
159
|
+
const deployment = new Deployment(mergeDefaults({
|
|
152
160
|
metadata: {
|
|
153
161
|
name,
|
|
154
162
|
...(namespace && { namespace }),
|
|
@@ -162,9 +170,9 @@ export function WebApp(props: WebAppProps): WebAppResult {
|
|
|
162
170
|
spec: podSpec,
|
|
163
171
|
},
|
|
164
172
|
},
|
|
165
|
-
};
|
|
173
|
+
}, defs?.deployment));
|
|
166
174
|
|
|
167
|
-
const
|
|
175
|
+
const service = new Service(mergeDefaults({
|
|
168
176
|
metadata: {
|
|
169
177
|
name,
|
|
170
178
|
...(namespace && { namespace }),
|
|
@@ -175,12 +183,9 @@ export function WebApp(props: WebAppProps): WebAppResult {
|
|
|
175
183
|
ports: [{ port: 80, targetPort: port, protocol: "TCP", name: "http" }],
|
|
176
184
|
type: "ClusterIP",
|
|
177
185
|
},
|
|
178
|
-
};
|
|
186
|
+
}, defs?.service));
|
|
179
187
|
|
|
180
|
-
const result:
|
|
181
|
-
deployment: deploymentProps,
|
|
182
|
-
service: serviceProps,
|
|
183
|
-
};
|
|
188
|
+
const result: Record<string, any> = { deployment, service };
|
|
184
189
|
|
|
185
190
|
if (props.ingressHost) {
|
|
186
191
|
// Build paths — use ingressPaths if provided, otherwise default single "/"
|
|
@@ -205,7 +210,7 @@ export function WebApp(props: WebAppProps): WebAppResult {
|
|
|
205
210
|
},
|
|
206
211
|
];
|
|
207
212
|
|
|
208
|
-
|
|
213
|
+
result.ingress = new Ingress(mergeDefaults({
|
|
209
214
|
metadata: {
|
|
210
215
|
name,
|
|
211
216
|
...(namespace && { namespace }),
|
|
@@ -227,12 +232,11 @@ export function WebApp(props: WebAppProps): WebAppResult {
|
|
|
227
232
|
],
|
|
228
233
|
}),
|
|
229
234
|
},
|
|
230
|
-
};
|
|
231
|
-
result.ingress = ingressProps;
|
|
235
|
+
}, defs?.ingress));
|
|
232
236
|
}
|
|
233
237
|
|
|
234
238
|
if (minAvailable !== undefined) {
|
|
235
|
-
result.pdb = {
|
|
239
|
+
result.pdb = new PodDisruptionBudget(mergeDefaults({
|
|
236
240
|
metadata: {
|
|
237
241
|
name,
|
|
238
242
|
...(namespace && { namespace }),
|
|
@@ -242,8 +246,8 @@ export function WebApp(props: WebAppProps): WebAppResult {
|
|
|
242
246
|
minAvailable,
|
|
243
247
|
selector: { matchLabels: { "app.kubernetes.io/name": name } },
|
|
244
248
|
},
|
|
245
|
-
};
|
|
249
|
+
}, defs?.pdb));
|
|
246
250
|
}
|
|
247
251
|
|
|
248
252
|
return result;
|
|
249
|
-
}
|
|
253
|
+
}, "WebApp");
|
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
* that need RBAC for secrets/configmaps and optional autoscaling, but no Service.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
9
|
+
import {
|
|
10
|
+
Deployment, ServiceAccount, Role, RoleBinding,
|
|
11
|
+
ConfigMap, HorizontalPodAutoscaler, PodDisruptionBudget,
|
|
12
|
+
} from "../generated";
|
|
8
13
|
import type { ContainerSecurityContext } from "./security-context";
|
|
9
14
|
|
|
10
15
|
export interface WorkerPoolProps {
|
|
@@ -54,16 +59,26 @@ export interface WorkerPoolProps {
|
|
|
54
59
|
namespace?: string;
|
|
55
60
|
/** Environment variables for the container. */
|
|
56
61
|
env?: Array<{ name: string; value: string }>;
|
|
62
|
+
/** Per-member defaults for fine-grained overrides. */
|
|
63
|
+
defaults?: {
|
|
64
|
+
deployment?: Partial<Record<string, unknown>>;
|
|
65
|
+
serviceAccount?: Partial<Record<string, unknown>>;
|
|
66
|
+
role?: Partial<Record<string, unknown>>;
|
|
67
|
+
roleBinding?: Partial<Record<string, unknown>>;
|
|
68
|
+
configMap?: Partial<Record<string, unknown>>;
|
|
69
|
+
hpa?: Partial<Record<string, unknown>>;
|
|
70
|
+
pdb?: Partial<Record<string, unknown>>;
|
|
71
|
+
};
|
|
57
72
|
}
|
|
58
73
|
|
|
59
74
|
export interface WorkerPoolResult {
|
|
60
|
-
deployment:
|
|
61
|
-
serviceAccount?:
|
|
62
|
-
role?:
|
|
63
|
-
roleBinding?:
|
|
64
|
-
configMap?:
|
|
65
|
-
hpa?:
|
|
66
|
-
pdb?:
|
|
75
|
+
deployment: InstanceType<typeof Deployment>;
|
|
76
|
+
serviceAccount?: InstanceType<typeof ServiceAccount>;
|
|
77
|
+
role?: InstanceType<typeof Role>;
|
|
78
|
+
roleBinding?: InstanceType<typeof RoleBinding>;
|
|
79
|
+
configMap?: InstanceType<typeof ConfigMap>;
|
|
80
|
+
hpa?: InstanceType<typeof HorizontalPodAutoscaler>;
|
|
81
|
+
pdb?: InstanceType<typeof PodDisruptionBudget>;
|
|
67
82
|
}
|
|
68
83
|
|
|
69
84
|
/**
|
|
@@ -82,7 +97,7 @@ export interface WorkerPoolResult {
|
|
|
82
97
|
* });
|
|
83
98
|
* ```
|
|
84
99
|
*/
|
|
85
|
-
export
|
|
100
|
+
export const WorkerPool = Composite<WorkerPoolProps>((props) => {
|
|
86
101
|
const {
|
|
87
102
|
name,
|
|
88
103
|
image,
|
|
@@ -103,6 +118,7 @@ export function WorkerPool(props: WorkerPoolProps): WorkerPoolResult {
|
|
|
103
118
|
labels: extraLabels = {},
|
|
104
119
|
namespace,
|
|
105
120
|
env,
|
|
121
|
+
defaults: defs,
|
|
106
122
|
} = props;
|
|
107
123
|
|
|
108
124
|
const saName = `${name}-sa`;
|
|
@@ -147,7 +163,7 @@ export function WorkerPool(props: WorkerPoolProps): WorkerPoolResult {
|
|
|
147
163
|
...(priorityClassName && { priorityClassName }),
|
|
148
164
|
};
|
|
149
165
|
|
|
150
|
-
const
|
|
166
|
+
const deployment = new Deployment(mergeDefaults({
|
|
151
167
|
metadata: {
|
|
152
168
|
name,
|
|
153
169
|
...(namespace && { namespace }),
|
|
@@ -161,31 +177,29 @@ export function WorkerPool(props: WorkerPoolProps): WorkerPoolResult {
|
|
|
161
177
|
spec: podSpec,
|
|
162
178
|
},
|
|
163
179
|
},
|
|
164
|
-
};
|
|
180
|
+
}, defs?.deployment));
|
|
165
181
|
|
|
166
|
-
const result:
|
|
167
|
-
deployment: deploymentProps,
|
|
168
|
-
};
|
|
182
|
+
const result: Record<string, any> = { deployment };
|
|
169
183
|
|
|
170
184
|
if (createRbac) {
|
|
171
|
-
result.serviceAccount = {
|
|
185
|
+
result.serviceAccount = new ServiceAccount(mergeDefaults({
|
|
172
186
|
metadata: {
|
|
173
187
|
name: saName,
|
|
174
188
|
...(namespace && { namespace }),
|
|
175
189
|
labels: { ...commonLabels, "app.kubernetes.io/component": "worker" },
|
|
176
190
|
},
|
|
177
|
-
};
|
|
191
|
+
}, defs?.serviceAccount));
|
|
178
192
|
|
|
179
|
-
result.role = {
|
|
193
|
+
result.role = new Role(mergeDefaults({
|
|
180
194
|
metadata: {
|
|
181
195
|
name: roleName,
|
|
182
196
|
...(namespace && { namespace }),
|
|
183
197
|
labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
|
|
184
198
|
},
|
|
185
199
|
rules: effectiveRbacRules,
|
|
186
|
-
};
|
|
200
|
+
}, defs?.role));
|
|
187
201
|
|
|
188
|
-
result.roleBinding = {
|
|
202
|
+
result.roleBinding = new RoleBinding(mergeDefaults({
|
|
189
203
|
metadata: {
|
|
190
204
|
name: bindingName,
|
|
191
205
|
...(namespace && { namespace }),
|
|
@@ -203,22 +217,22 @@ export function WorkerPool(props: WorkerPoolProps): WorkerPoolResult {
|
|
|
203
217
|
...(namespace && { namespace }),
|
|
204
218
|
},
|
|
205
219
|
],
|
|
206
|
-
};
|
|
220
|
+
}, defs?.roleBinding));
|
|
207
221
|
}
|
|
208
222
|
|
|
209
223
|
if (config) {
|
|
210
|
-
result.configMap = {
|
|
224
|
+
result.configMap = new ConfigMap(mergeDefaults({
|
|
211
225
|
metadata: {
|
|
212
226
|
name: configMapName,
|
|
213
227
|
...(namespace && { namespace }),
|
|
214
228
|
labels: { ...commonLabels, "app.kubernetes.io/component": "config" },
|
|
215
229
|
},
|
|
216
230
|
data: config,
|
|
217
|
-
};
|
|
231
|
+
}, defs?.configMap));
|
|
218
232
|
}
|
|
219
233
|
|
|
220
234
|
if (minAvailable !== undefined) {
|
|
221
|
-
result.pdb = {
|
|
235
|
+
result.pdb = new PodDisruptionBudget(mergeDefaults({
|
|
222
236
|
metadata: {
|
|
223
237
|
name,
|
|
224
238
|
...(namespace && { namespace }),
|
|
@@ -228,12 +242,12 @@ export function WorkerPool(props: WorkerPoolProps): WorkerPoolResult {
|
|
|
228
242
|
minAvailable,
|
|
229
243
|
selector: { matchLabels: { "app.kubernetes.io/name": name } },
|
|
230
244
|
},
|
|
231
|
-
};
|
|
245
|
+
}, defs?.pdb));
|
|
232
246
|
}
|
|
233
247
|
|
|
234
248
|
if (autoscaling) {
|
|
235
249
|
const targetCPUPercent = autoscaling.targetCPUPercent ?? 70;
|
|
236
|
-
result.hpa = {
|
|
250
|
+
result.hpa = new HorizontalPodAutoscaler(mergeDefaults({
|
|
237
251
|
metadata: {
|
|
238
252
|
name,
|
|
239
253
|
...(namespace && { namespace }),
|
|
@@ -257,8 +271,8 @@ export function WorkerPool(props: WorkerPoolProps): WorkerPoolResult {
|
|
|
257
271
|
},
|
|
258
272
|
],
|
|
259
273
|
},
|
|
260
|
-
};
|
|
274
|
+
}, defs?.hpa));
|
|
261
275
|
}
|
|
262
276
|
|
|
263
277
|
return result;
|
|
264
|
-
}
|
|
278
|
+
}, "WorkerPool");
|