@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.
- package/dist/integrity.json +20 -15
- 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/dist/skills/chant-k8s-eks.md +156 -0
- package/dist/skills/chant-k8s-patterns.md +245 -0
- package/dist/skills/chant-k8s.md +36 -227
- package/package.json +27 -24
- package/src/codegen/docs.ts +5 -5
- package/src/composites/adot-collector.ts +245 -0
- package/src/composites/agic-ingress.ts +149 -0
- package/src/composites/alb-ingress.ts +152 -0
- package/src/composites/autoscaled-service.ts +51 -0
- 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 +221 -0
- package/src/composites/composites.test.ts +1584 -0
- package/src/composites/config-connector-context.ts +62 -0
- package/src/composites/configured-app.ts +224 -0
- package/src/composites/cron-workload.ts +6 -0
- package/src/composites/ebs-storage-class.ts +96 -0
- package/src/composites/efs-storage-class.ts +77 -0
- package/src/composites/external-dns-agent.ts +174 -0
- package/src/composites/filestore-storage-class.ts +79 -0
- package/src/composites/fluent-bit-agent.ts +220 -0
- package/src/composites/gce-pd-storage-class.ts +85 -0
- package/src/composites/gke-gateway.ts +143 -0
- package/src/composites/index.ts +47 -0
- package/src/composites/irsa-service-account.ts +114 -0
- package/src/composites/metrics-server.ts +224 -0
- package/src/composites/monitored-service.ts +221 -0
- package/src/composites/network-isolated-app.ts +202 -0
- package/src/composites/node-agent.ts +6 -0
- package/src/composites/secure-ingress.ts +149 -0
- package/src/composites/security-context.ts +10 -0
- package/src/composites/sidecar-app.ts +207 -0
- package/src/composites/stateful-app.ts +67 -15
- package/src/composites/web-app.ts +104 -35
- package/src/composites/worker-pool.ts +38 -4
- package/src/composites/workload-identity-sa.ts +118 -0
- package/src/composites/workload-identity-service-account.ts +116 -0
- package/src/index.ts +24 -2
- 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 +556 -242
- package/src/serializer.test.ts +120 -0
- package/src/serializer.ts +16 -4
package/src/serializer.test.ts
CHANGED
|
@@ -143,6 +143,76 @@ describe("k8sSerializer", () => {
|
|
|
143
143
|
expect(result).not.toContain("spec:");
|
|
144
144
|
});
|
|
145
145
|
|
|
146
|
+
test("ClusterRole is specless type", () => {
|
|
147
|
+
const entities = new Map<string, any>();
|
|
148
|
+
entities.set(
|
|
149
|
+
"viewRole",
|
|
150
|
+
mockResource("K8s::Rbac::ClusterRole", {
|
|
151
|
+
metadata: { name: "view-role" },
|
|
152
|
+
rules: [{ apiGroups: [""], resources: ["pods"], verbs: ["get", "list"] }],
|
|
153
|
+
}),
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
const result = k8sSerializer.serialize(entities);
|
|
157
|
+
expect(result).toContain("kind: ClusterRole");
|
|
158
|
+
expect(result).toContain("name: view-role");
|
|
159
|
+
expect(result).not.toContain("spec:");
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("ClusterRoleBinding is specless type", () => {
|
|
163
|
+
const entities = new Map<string, any>();
|
|
164
|
+
entities.set(
|
|
165
|
+
"viewBinding",
|
|
166
|
+
mockResource("K8s::Rbac::ClusterRoleBinding", {
|
|
167
|
+
metadata: { name: "view-binding" },
|
|
168
|
+
roleRef: { apiGroup: "rbac.authorization.k8s.io", kind: "ClusterRole", name: "view-role" },
|
|
169
|
+
subjects: [{ kind: "ServiceAccount", name: "default", namespace: "default" }],
|
|
170
|
+
}),
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const result = k8sSerializer.serialize(entities);
|
|
174
|
+
expect(result).toContain("kind: ClusterRoleBinding");
|
|
175
|
+
expect(result).not.toContain("spec:");
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("StorageClass is specless type", () => {
|
|
179
|
+
const entities = new Map<string, any>();
|
|
180
|
+
entities.set(
|
|
181
|
+
"gp3",
|
|
182
|
+
mockResource("K8s::Storage::StorageClass", {
|
|
183
|
+
metadata: { name: "gp3-encrypted" },
|
|
184
|
+
provisioner: "ebs.csi.aws.com",
|
|
185
|
+
parameters: { type: "gp3", encrypted: "true" },
|
|
186
|
+
reclaimPolicy: "Delete",
|
|
187
|
+
volumeBindingMode: "WaitForFirstConsumer",
|
|
188
|
+
}),
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const result = k8sSerializer.serialize(entities);
|
|
192
|
+
expect(result).toContain("kind: StorageClass");
|
|
193
|
+
expect(result).toContain("provisioner: ebs.csi.aws.com");
|
|
194
|
+
expect(result).not.toContain("spec:");
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test("APIService is specless type", () => {
|
|
198
|
+
const entities = new Map<string, any>();
|
|
199
|
+
entities.set(
|
|
200
|
+
"metricsApi",
|
|
201
|
+
mockResource("K8s::Admissionregistration::APIService", {
|
|
202
|
+
metadata: { name: "v1beta1.metrics.k8s.io" },
|
|
203
|
+
group: "metrics.k8s.io",
|
|
204
|
+
version: "v1beta1",
|
|
205
|
+
service: { name: "metrics-server", namespace: "kube-system" },
|
|
206
|
+
groupPriorityMinimum: 100,
|
|
207
|
+
versionPriority: 100,
|
|
208
|
+
}),
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
const result = k8sSerializer.serialize(entities);
|
|
212
|
+
expect(result).toContain("kind: APIService");
|
|
213
|
+
expect(result).not.toContain("spec:");
|
|
214
|
+
});
|
|
215
|
+
|
|
146
216
|
test("multi-resource entities joined by ---", () => {
|
|
147
217
|
const entities = new Map<string, any>();
|
|
148
218
|
entities.set(
|
|
@@ -248,6 +318,56 @@ describe("k8sSerializer", () => {
|
|
|
248
318
|
expect(result).toBe("");
|
|
249
319
|
});
|
|
250
320
|
|
|
321
|
+
test("Namespaces appear before other resources regardless of insertion order", () => {
|
|
322
|
+
const entities = new Map<string, any>();
|
|
323
|
+
// Insert Deployment first, then Namespace — Namespace should still come first in output
|
|
324
|
+
entities.set(
|
|
325
|
+
"deploy",
|
|
326
|
+
mockResource("K8s::Apps::Deployment", {
|
|
327
|
+
metadata: { name: "app", namespace: "my-ns" },
|
|
328
|
+
spec: { replicas: 1 },
|
|
329
|
+
}),
|
|
330
|
+
);
|
|
331
|
+
entities.set(
|
|
332
|
+
"ns",
|
|
333
|
+
mockResource("K8s::Core::Namespace", {
|
|
334
|
+
metadata: { name: "my-ns" },
|
|
335
|
+
}),
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
const result = k8sSerializer.serialize(entities);
|
|
339
|
+
const docs = result.split("---");
|
|
340
|
+
// First document should be the Namespace
|
|
341
|
+
expect(docs[0]).toContain("kind: Namespace");
|
|
342
|
+
expect(docs[0]).toContain("name: my-ns");
|
|
343
|
+
// Second document should be the Deployment
|
|
344
|
+
expect(docs[1]).toContain("kind: Deployment");
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
test("ConfigMap multiline data emits as | block scalar", () => {
|
|
348
|
+
const entities = new Map<string, any>();
|
|
349
|
+
const multilineConfig = "[SERVICE]\n Flush 5\n Log_Level info\n\n[INPUT]\n Name tail\n";
|
|
350
|
+
entities.set(
|
|
351
|
+
"config",
|
|
352
|
+
mockResource("K8s::Core::ConfigMap", {
|
|
353
|
+
metadata: { name: "app-config" },
|
|
354
|
+
data: { "fluent-bit.conf": multilineConfig },
|
|
355
|
+
}),
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
const result = k8sSerializer.serialize(entities);
|
|
359
|
+
expect(result).toContain("kind: ConfigMap");
|
|
360
|
+
// Must use | block scalar, not flatten to single line
|
|
361
|
+
expect(result).toContain("fluent-bit.conf: |");
|
|
362
|
+
// Content lines should be preserved (indented under the key)
|
|
363
|
+
expect(result).toContain("[SERVICE]");
|
|
364
|
+
expect(result).toContain("Flush 5");
|
|
365
|
+
expect(result).toContain("[INPUT]");
|
|
366
|
+
expect(result).toContain("Name tail");
|
|
367
|
+
// Should NOT contain literal \n in the output
|
|
368
|
+
expect(result).not.toContain("\\n");
|
|
369
|
+
});
|
|
370
|
+
|
|
251
371
|
test("key ordering: apiVersion, kind, metadata, spec, then rest", () => {
|
|
252
372
|
const entities = new Map<string, any>();
|
|
253
373
|
entities.set(
|
package/src/serializer.ts
CHANGED
|
@@ -26,6 +26,13 @@ const SPECLESS_TYPES = new Set([
|
|
|
26
26
|
"Secret",
|
|
27
27
|
"Namespace",
|
|
28
28
|
"ServiceAccount",
|
|
29
|
+
"ClusterRole",
|
|
30
|
+
"ClusterRoleBinding",
|
|
31
|
+
"Role",
|
|
32
|
+
"RoleBinding",
|
|
33
|
+
"StorageClass",
|
|
34
|
+
"PersistentVolume",
|
|
35
|
+
"APIService",
|
|
29
36
|
]);
|
|
30
37
|
|
|
31
38
|
/**
|
|
@@ -157,7 +164,8 @@ export const k8sSerializer: Serializer = {
|
|
|
157
164
|
}
|
|
158
165
|
}
|
|
159
166
|
|
|
160
|
-
const
|
|
167
|
+
const namespaceDocs: string[] = [];
|
|
168
|
+
const otherDocs: string[] = [];
|
|
161
169
|
|
|
162
170
|
for (const [name, entity] of entities) {
|
|
163
171
|
if (isPropertyDeclarable(entity)) continue;
|
|
@@ -230,12 +238,16 @@ export const k8sSerializer: Serializer = {
|
|
|
230
238
|
}
|
|
231
239
|
}
|
|
232
240
|
|
|
233
|
-
// Emit as YAML
|
|
241
|
+
// Emit as YAML — sort Namespaces first so kubectl apply succeeds
|
|
234
242
|
const yamlDoc = emitK8sManifest(manifest);
|
|
235
|
-
|
|
243
|
+
if (gvk.kind === "Namespace") {
|
|
244
|
+
namespaceDocs.push(yamlDoc);
|
|
245
|
+
} else {
|
|
246
|
+
otherDocs.push(yamlDoc);
|
|
247
|
+
}
|
|
236
248
|
}
|
|
237
249
|
|
|
238
|
-
return
|
|
250
|
+
return [...namespaceDocs, ...otherDocs].join("\n---\n");
|
|
239
251
|
},
|
|
240
252
|
};
|
|
241
253
|
|