@intentius/chant-lexicon-k8s 0.124.31 → 0.124.33

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 (270) hide show
  1. package/dist/actions/apps.js +18 -0
  2. package/dist/actions/batch.js +6 -0
  3. package/dist/actions/core.js +48 -0
  4. package/dist/actions/index.js +13 -0
  5. package/dist/actions/networking.js +11 -0
  6. package/dist/actions/rbac.js +8 -0
  7. package/dist/api/classify.js +123 -0
  8. package/dist/api/connect.js +62 -0
  9. package/dist/api/fake-cluster.js +175 -0
  10. package/dist/api/operation-surface.d.ts.map +1 -1
  11. package/dist/api/operation-surface.js +109 -0
  12. package/dist/api/owner-chain.js +100 -0
  13. package/dist/api/sweep-types.js +35 -0
  14. package/dist/behaviour-kinds.js +82 -0
  15. package/dist/codegen/docs-cli.js +2 -0
  16. package/dist/codegen/docs.js +146 -0
  17. package/dist/codegen/generate-cli.js +30 -0
  18. package/dist/codegen/generate-lexicon.js +74 -0
  19. package/dist/codegen/generate-list-map-keys.js +88 -0
  20. package/dist/codegen/generate-operations.js +53 -0
  21. package/dist/codegen/generate-typescript.js +124 -0
  22. package/dist/codegen/generate.js +173 -0
  23. package/dist/codegen/naming.js +174 -0
  24. package/dist/codegen/package.js +36 -0
  25. package/dist/codegen/patches.js +88 -0
  26. package/dist/codegen/typecheck.js +4 -0
  27. package/dist/codegen/versions.js +41 -0
  28. package/dist/components/argo-app.js +51 -0
  29. package/dist/components/builders.js +22 -0
  30. package/dist/components/capability-plugin.js +31 -0
  31. package/dist/components/flux-reconcile.js +61 -0
  32. package/dist/components/index.d.ts +1 -1
  33. package/dist/components/index.d.ts.map +1 -1
  34. package/dist/components/index.js +18 -0
  35. package/dist/components/kubectl-apply.d.ts +83 -1
  36. package/dist/components/kubectl-apply.d.ts.map +1 -1
  37. package/dist/components/kubectl-apply.js +274 -0
  38. package/dist/components/kustomize-apply.js +25 -0
  39. package/dist/composites/adot-collector.js +184 -0
  40. package/dist/composites/agic-ingress.js +85 -0
  41. package/dist/composites/aks-external-dns-agent.js +146 -0
  42. package/dist/composites/alb-ingress.js +86 -0
  43. package/dist/composites/argo-app.js +199 -0
  44. package/dist/composites/autoscaled-service.js +174 -0
  45. package/dist/composites/azure-disk-storage-class.js +47 -0
  46. package/dist/composites/azure-file-storage-class.js +48 -0
  47. package/dist/composites/azure-monitor-collector.js +176 -0
  48. package/dist/composites/batch-job.js +139 -0
  49. package/dist/composites/catalog.js +4110 -0
  50. package/dist/composites/cockroachdb-cluster.js +371 -0
  51. package/dist/composites/cockroachdb-region-stack.js +369 -0
  52. package/dist/composites/config-connector-context.js +40 -0
  53. package/dist/composites/configured-app.js +135 -0
  54. package/dist/composites/cron-schedule.js +38 -0
  55. package/dist/composites/cron-workload.js +109 -0
  56. package/dist/composites/ebs-storage-class.js +54 -0
  57. package/dist/composites/efs-storage-class.js +46 -0
  58. package/dist/composites/external-dns-agent.js +122 -0
  59. package/dist/composites/filestore-storage-class.js +49 -0
  60. package/dist/composites/fluent-bit-agent.js +157 -0
  61. package/dist/composites/flux-app.js +156 -0
  62. package/dist/composites/gce-ingress.js +83 -0
  63. package/dist/composites/gce-pd-storage-class.js +49 -0
  64. package/dist/composites/gke-external-dns-agent.js +129 -0
  65. package/dist/composites/gke-fluent-bit-agent.js +165 -0
  66. package/dist/composites/gke-gateway.js +91 -0
  67. package/dist/composites/gke-otel-collector.js +94 -0
  68. package/dist/composites/index.js +51 -0
  69. package/dist/composites/inference-service.js +76 -0
  70. package/dist/composites/irsa-service-account.js +77 -0
  71. package/dist/composites/member-defaults.js +14 -0
  72. package/dist/composites/metrics-server.js +181 -0
  73. package/dist/composites/model.js +92 -0
  74. package/dist/composites/monitored-service.js +152 -0
  75. package/dist/composites/namespace-env.js +114 -0
  76. package/dist/composites/network-isolated-app.js +124 -0
  77. package/dist/composites/node-agent.js +149 -0
  78. package/dist/composites/operator-stack.js +268 -0
  79. package/dist/composites/otel-collector-agent.js +142 -0
  80. package/dist/composites/otel-collector-gateway.js +216 -0
  81. package/dist/composites/otel-collector-node.js +176 -0
  82. package/dist/composites/otel-collector-rbac.js +115 -0
  83. package/dist/composites/otel-collector-shape.js +128 -0
  84. package/dist/composites/otel-collector.js +115 -0
  85. package/dist/composites/otel-operator-collector.js +123 -0
  86. package/dist/composites/ray-cluster.js +378 -0
  87. package/dist/composites/ray-job.js +136 -0
  88. package/dist/composites/ray-service.js +178 -0
  89. package/dist/composites/secure-ingress.js +100 -0
  90. package/dist/composites/security-context.js +1 -0
  91. package/dist/composites/sidecar-app.js +105 -0
  92. package/dist/composites/stateful-app.js +111 -0
  93. package/dist/composites/vllm-serving-runtime.js +114 -0
  94. package/dist/composites/web-app.js +157 -0
  95. package/dist/composites/worker-pool.js +167 -0
  96. package/dist/composites/workload-identity-sa.js +81 -0
  97. package/dist/composites/workload-identity-service-account.js +77 -0
  98. package/dist/config-schema.js +72 -0
  99. package/dist/config.js +59 -0
  100. package/dist/coverage.js +27 -0
  101. package/dist/crd/crd-sources.js +615 -0
  102. package/dist/crd/loader.js +181 -0
  103. package/dist/crd/oci-chart.js +144 -0
  104. package/dist/crd/parser.js +382 -0
  105. package/dist/crd/project-codegen.js +273 -0
  106. package/dist/crd/types.js +7 -0
  107. package/dist/deep-observe-hooks.js +306 -0
  108. package/dist/deep-observe.js +234 -0
  109. package/dist/default-labels.js +87 -0
  110. package/dist/describe-resources.js +699 -0
  111. package/dist/describe-stack-status.js +99 -0
  112. package/dist/detect.js +11 -0
  113. package/dist/effect-receipt-row.js +205 -0
  114. package/dist/export-resources.js +39 -0
  115. package/dist/generated/index.js +1092 -0
  116. package/dist/generated/runtime.js +4 -0
  117. package/dist/group-namespace.js +96 -0
  118. package/dist/import/embedded.js +197 -0
  119. package/dist/import/generator.js +288 -0
  120. package/dist/import/live-export.js +85 -0
  121. package/dist/import/parser.js +204 -0
  122. package/dist/import/testdata/embedded/fixtures.js +60 -0
  123. package/dist/include/entity.js +78 -0
  124. package/dist/include/resolve.js +170 -0
  125. package/dist/index.js +59 -0
  126. package/dist/integrity.json +3 -3
  127. package/dist/kube/apply.js +90 -0
  128. package/dist/kube/connect.js +46 -0
  129. package/dist/kube/delete.js +138 -0
  130. package/dist/kube/describe.js +169 -0
  131. package/dist/kube/events.js +132 -0
  132. package/dist/kube/flags.js +91 -0
  133. package/dist/kube/get.js +159 -0
  134. package/dist/kube/group.js +123 -0
  135. package/dist/kube/logs.js +82 -0
  136. package/dist/kube/project.js +94 -0
  137. package/dist/kube/render.js +227 -0
  138. package/dist/kube/source.js +122 -0
  139. package/dist/kube/target.js +63 -0
  140. package/dist/kube/testing.js +28 -0
  141. package/dist/kube/top.js +99 -0
  142. package/dist/kube/verdict.js +72 -0
  143. package/dist/kube/wait.js +129 -0
  144. package/dist/kustomize/render.js +73 -0
  145. package/dist/kustomize/rendered-entity.js +67 -0
  146. package/dist/kustomize/root.js +68 -0
  147. package/dist/lint/audit-catalog.js +61 -0
  148. package/dist/lint/audit-lineage.js +118 -0
  149. package/dist/lint/post-synth/argo-helpers.js +36 -0
  150. package/dist/lint/post-synth/argo002.js +31 -0
  151. package/dist/lint/post-synth/argo003.js +53 -0
  152. package/dist/lint/post-synth/argo005.js +54 -0
  153. package/dist/lint/post-synth/crd-schema-helpers.d.ts.map +1 -1
  154. package/dist/lint/post-synth/crd-schema-helpers.js +214 -0
  155. package/dist/lint/post-synth/flux002.js +56 -0
  156. package/dist/lint/post-synth/flux003.js +50 -0
  157. package/dist/lint/post-synth/index.js +104 -0
  158. package/dist/lint/post-synth/k8s-helpers.js +186 -0
  159. package/dist/lint/post-synth/monitoring-selection-helpers.js +163 -0
  160. package/dist/lint/post-synth/otel-placement-helpers.js +293 -0
  161. package/dist/lint/post-synth/sops-helpers.js +43 -0
  162. package/dist/lint/post-synth/wk8005.js +44 -0
  163. package/dist/lint/post-synth/wk8006.js +56 -0
  164. package/dist/lint/post-synth/wk8041.js +60 -0
  165. package/dist/lint/post-synth/wk8042.js +36 -0
  166. package/dist/lint/post-synth/wk8101.js +52 -0
  167. package/dist/lint/post-synth/wk8102.js +30 -0
  168. package/dist/lint/post-synth/wk8103.js +33 -0
  169. package/dist/lint/post-synth/wk8104.js +58 -0
  170. package/dist/lint/post-synth/wk8105.js +33 -0
  171. package/dist/lint/post-synth/wk8201.js +44 -0
  172. package/dist/lint/post-synth/wk8202.js +34 -0
  173. package/dist/lint/post-synth/wk8203.js +34 -0
  174. package/dist/lint/post-synth/wk8204.js +71 -0
  175. package/dist/lint/post-synth/wk8205.js +38 -0
  176. package/dist/lint/post-synth/wk8207.js +33 -0
  177. package/dist/lint/post-synth/wk8208.js +33 -0
  178. package/dist/lint/post-synth/wk8209.js +33 -0
  179. package/dist/lint/post-synth/wk8301.js +49 -0
  180. package/dist/lint/post-synth/wk8302.js +34 -0
  181. package/dist/lint/post-synth/wk8303.js +68 -0
  182. package/dist/lint/post-synth/wk8304.js +58 -0
  183. package/dist/lint/post-synth/wk8305.js +96 -0
  184. package/dist/lint/post-synth/wk8306.js +38 -0
  185. package/dist/lint/post-synth/wk8401.js +86 -0
  186. package/dist/lint/post-synth/wk8402.js +31 -0
  187. package/dist/lint/post-synth/wk8403.js +49 -0
  188. package/dist/lint/post-synth/wk8404.js +36 -0
  189. package/dist/lint/post-synth/wk8405.js +65 -0
  190. package/dist/lint/post-synth/wk8406.js +50 -0
  191. package/dist/lint/post-synth/wk8407.js +58 -0
  192. package/dist/lint/post-synth/wk8501.js +36 -0
  193. package/dist/lint/post-synth/wk8502.js +35 -0
  194. package/dist/lint/post-synth/wk8503.js +164 -0
  195. package/dist/lint/post-synth/wk8504.js +20 -0
  196. package/dist/lint/post-synth/wk8505.js +31 -0
  197. package/dist/lint/post-synth/wk8601.js +40 -0
  198. package/dist/lint/post-synth/wk8602.js +120 -0
  199. package/dist/lint/post-synth/wk8603.js +63 -0
  200. package/dist/lint/post-synth/wk8604.js +31 -0
  201. package/dist/lint/post-synth/wk8605.js +124 -0
  202. package/dist/lint/post-synth/wk8606.js +22 -0
  203. package/dist/lint/post-synth/wk8701.js +31 -0
  204. package/dist/lint/post-synth/wk8702.js +37 -0
  205. package/dist/lint/post-synth/wk8703.js +31 -0
  206. package/dist/lint/post-synth/wk8704.js +135 -0
  207. package/dist/lint/post-synth/wk8705.js +38 -0
  208. package/dist/lint/rules/argo-appset-single-project.js +56 -0
  209. package/dist/lint/rules/argo-ast.js +94 -0
  210. package/dist/lint/rules/argo-automated-prune.js +59 -0
  211. package/dist/lint/rules/flux-source-ref-pin.js +44 -0
  212. package/dist/lint/rules/hardcoded-namespace.js +57 -0
  213. package/dist/lint/rules/latest-image-tag.js +103 -0
  214. package/dist/lint/rules/missing-resource-limits.js +85 -0
  215. package/dist/lsp/completions.d.ts.map +1 -1
  216. package/dist/lsp/completions.js +18 -0
  217. package/dist/lsp/hover.d.ts.map +1 -1
  218. package/dist/lsp/hover.js +57 -0
  219. package/dist/manifest-entity.js +71 -0
  220. package/dist/manifest.json +1 -1
  221. package/dist/micro-time.js +49 -0
  222. package/dist/op/activities/apply-diff.d.ts +31 -0
  223. package/dist/op/activities/apply-diff.d.ts.map +1 -0
  224. package/dist/op/activities/apply-diff.js +79 -0
  225. package/dist/op/activities/argo.js +98 -0
  226. package/dist/op/activities/ensure-secret.js +38 -0
  227. package/dist/op/activities/index.js +51 -0
  228. package/dist/op/activities/kubectl.d.ts +64 -0
  229. package/dist/op/activities/kubectl.d.ts.map +1 -1
  230. package/dist/op/activities/kubectl.js +517 -0
  231. package/dist/op/activities/wait-for-ready.js +229 -0
  232. package/dist/op/builders.js +68 -0
  233. package/dist/package-cli.js +21 -0
  234. package/dist/patch/json-patch.js +187 -0
  235. package/dist/patch/rendered-patch.js +94 -0
  236. package/dist/plugin.js +741 -0
  237. package/dist/project-kinds.js +56 -0
  238. package/dist/receipt-store.js +216 -0
  239. package/dist/rules/crd-schema-helpers.ts +2 -1
  240. package/dist/secret-labels.js +33 -0
  241. package/dist/secret-store.js +116 -0
  242. package/dist/serializer.d.ts.map +1 -1
  243. package/dist/serializer.js +578 -0
  244. package/dist/sops/encrypted-secret-file.js +194 -0
  245. package/dist/sops/entity.js +32 -0
  246. package/dist/spec/fetch.js +58 -0
  247. package/dist/spec/parse.js +622 -0
  248. package/dist/subscribe-changes.js +168 -0
  249. package/dist/teardown.js +197 -0
  250. package/dist/telemetry-release.js +86 -0
  251. package/dist/validate-cli.js +17 -0
  252. package/dist/validate.js +47 -0
  253. package/dist/variables.js +34 -0
  254. package/dist/whoami.js +109 -0
  255. package/package.json +12 -12
  256. package/src/api/operation-surface.ts +2 -1
  257. package/src/codegen/package.ts +2 -2
  258. package/src/components/index.ts +3 -0
  259. package/src/components/kubectl-apply-plan.k3d.e2e.test.ts +127 -0
  260. package/src/components/kubectl-apply.test.ts +262 -0
  261. package/src/components/kubectl-apply.ts +341 -12
  262. package/src/deep-observe-hooks.ts +2 -2
  263. package/src/import/roundtrip-build.test.ts +46 -0
  264. package/src/lint/post-synth/crd-schema-helpers.ts +2 -1
  265. package/src/lsp/completions.ts +2 -1
  266. package/src/lsp/hover.ts +2 -1
  267. package/src/op/activities/apply-diff.ts +87 -0
  268. package/src/op/activities/kubectl-plan.test.ts +224 -0
  269. package/src/op/activities/kubectl.ts +204 -16
  270. package/src/serializer.ts +2 -1
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Argo CD composites — turn Chant build targets into Argo `Application`s.
3
+ *
4
+ * The k8s lexicon stays runtime-agnostic: it only emits manifests. These
5
+ * composites are the opt-in bridge to Argo CD's reconciliation layer. Authoring
6
+ * an `Application` by hand is ~30 lines of nested YAML; `ArgoAppFor` collapses
7
+ * it to one call with production-friendly defaults.
8
+ *
9
+ * - ArgoAppFor(target, opts) → a single K8s::Argo::Application
10
+ * - ArgoAppSetForRegions(regions, …) → one ApplicationSet, fanned out per region
11
+ * - registerArgoCluster(opts) → the cluster-registration Secret
12
+ */
13
+ import { Composite, mergeDefaults } from "@intentius/chant";
14
+ import { Application as ApplicationResource, ApplicationSet as ApplicationSetResource, Secret as SecretResource, } from "../generated/index.js";
15
+ const IN_CLUSTER_SERVER = "https://kubernetes.default.svc";
16
+ /** The default, safe sync policy: automated, non-pruning, self-healing. */
17
+ function defaultSyncPolicy() {
18
+ return {
19
+ automated: { prune: false, selfHeal: true },
20
+ syncOptions: ["CreateNamespace=true"],
21
+ };
22
+ }
23
+ function renderSyncPolicy(policy) {
24
+ const out = {};
25
+ if (policy.automated) {
26
+ out.automated = {
27
+ ...(policy.automated.prune !== undefined && { prune: policy.automated.prune }),
28
+ ...(policy.automated.selfHeal !== undefined && { selfHeal: policy.automated.selfHeal }),
29
+ };
30
+ }
31
+ if (policy.syncOptions && policy.syncOptions.length > 0) {
32
+ out.syncOptions = policy.syncOptions;
33
+ }
34
+ return out;
35
+ }
36
+ function renderDestination(dest) {
37
+ return {
38
+ ...(dest.server !== undefined && { server: dest.server }),
39
+ ...(dest.name !== undefined && { name: dest.name }),
40
+ namespace: dest.namespace,
41
+ };
42
+ }
43
+ const ArgoApplication = Composite((props) => {
44
+ const { target, repo, path, destination = { server: IN_CLUSTER_SERVER, namespace: target }, targetRevision = "HEAD", project = "default", argoNamespace = "argocd", syncPolicy, labels = {}, defaults, } = props;
45
+ const resolvedSyncPolicy = syncPolicy ?? defaultSyncPolicy();
46
+ const renderedSync = renderSyncPolicy(resolvedSyncPolicy);
47
+ const application = new ApplicationResource(mergeDefaults({
48
+ metadata: {
49
+ name: target,
50
+ namespace: argoNamespace,
51
+ labels: {
52
+ "app.kubernetes.io/name": target,
53
+ "app.kubernetes.io/managed-by": "chant",
54
+ ...labels,
55
+ },
56
+ },
57
+ spec: {
58
+ project,
59
+ source: { repoURL: repo, path, targetRevision },
60
+ destination: renderDestination(destination),
61
+ ...(Object.keys(renderedSync).length > 0 && { syncPolicy: renderedSync }),
62
+ },
63
+ }, defaults?.application));
64
+ return { application };
65
+ }, "ArgoApplication");
66
+ /**
67
+ * Turn a Chant build target into an Argo CD `Application` in one call.
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * import { ArgoAppFor } from "@intentius/chant-lexicon-k8s";
72
+ *
73
+ * export const api = ArgoAppFor("api", {
74
+ * repo: "https://github.com/acme/infra",
75
+ * path: "dist/api",
76
+ * destination: { server: "https://kubernetes.default.svc", namespace: "api" },
77
+ * });
78
+ * ```
79
+ */
80
+ export function ArgoAppFor(target, options) {
81
+ return ArgoApplication({ target, ...options });
82
+ }
83
+ /**
84
+ * Emit one `ApplicationSet` that fans out across regions via a list generator —
85
+ * one synced Application per region, all scoped to a single AppProject.
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * import { ArgoAppSetForRegions } from "@intentius/chant-lexicon-k8s";
90
+ *
91
+ * export const crdb = ArgoAppSetForRegions(
92
+ * ["east", "central", "west"],
93
+ * (region) => ({
94
+ * server: clusterServers[region],
95
+ * namespace: `crdb-${region}`,
96
+ * path: `dist/${region}`,
97
+ * }),
98
+ * { name: "crdb", repo: "https://github.com/acme/infra", project: "crdb" },
99
+ * );
100
+ * ```
101
+ */
102
+ export function ArgoAppSetForRegions(regions, fn, options) {
103
+ return ArgoApplicationSet({ regions, fn, options });
104
+ }
105
+ const ArgoApplicationSet = Composite((props) => {
106
+ const { regions, fn, options } = props;
107
+ const { name, repo, path: setPath, project = "default", argoNamespace = "argocd", targetRevision: setRevision = "HEAD", syncPolicy, labels = {}, defaults, } = options;
108
+ // One list-generator element per region, carrying the resolved per-region
109
+ // values the template interpolates.
110
+ const elements = regions.map((region) => {
111
+ const t = fn(region);
112
+ const path = t.path ?? setPath;
113
+ if (path === undefined) {
114
+ throw new Error(`ArgoAppSetForRegions("${name}"): region "${region}" has no path — set options.path or return a path from the mapper.`);
115
+ }
116
+ return {
117
+ region,
118
+ ...(t.server !== undefined && { server: t.server }),
119
+ ...(t.name !== undefined && { clusterName: t.name }),
120
+ namespace: t.namespace,
121
+ path,
122
+ targetRevision: t.targetRevision ?? setRevision,
123
+ };
124
+ });
125
+ // Destination interpolates server or name depending on what the mapper gave.
126
+ const usesServer = elements.every((e) => "server" in e);
127
+ const destination = usesServer
128
+ ? { server: "{{server}}", namespace: "{{namespace}}" }
129
+ : { name: "{{clusterName}}", namespace: "{{namespace}}" };
130
+ const resolvedSyncPolicy = syncPolicy ?? defaultSyncPolicy();
131
+ const renderedSync = renderSyncPolicy(resolvedSyncPolicy);
132
+ const applicationSet = new ApplicationSetResource(mergeDefaults({
133
+ metadata: {
134
+ name,
135
+ namespace: argoNamespace,
136
+ labels: {
137
+ "app.kubernetes.io/name": name,
138
+ "app.kubernetes.io/managed-by": "chant",
139
+ ...labels,
140
+ },
141
+ },
142
+ spec: {
143
+ generators: [{ list: { elements } }],
144
+ template: {
145
+ metadata: { name: `{{region}}-${name}` },
146
+ spec: {
147
+ // Single static AppProject for the whole set (ARGO004).
148
+ project,
149
+ source: { repoURL: repo, path: "{{path}}", targetRevision: "{{targetRevision}}" },
150
+ destination,
151
+ ...(Object.keys(renderedSync).length > 0 && { syncPolicy: renderedSync }),
152
+ },
153
+ },
154
+ },
155
+ }, defaults?.applicationSet));
156
+ return { applicationSet };
157
+ }, "ArgoApplicationSet");
158
+ /**
159
+ * Register an external cluster with Argo CD — emits the cluster Secret labelled
160
+ * `argocd.argoproj.io/secret-type: cluster` that ARGO003 looks for.
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * import { registerArgoCluster } from "@intentius/chant-lexicon-k8s";
165
+ *
166
+ * export const east = registerArgoCluster({
167
+ * name: "east",
168
+ * server: "https://east.example.com",
169
+ * config: { tlsClientConfig: { insecure: false } },
170
+ * });
171
+ * ```
172
+ */
173
+ export function registerArgoCluster(options) {
174
+ return ArgoClusterSecret(options);
175
+ }
176
+ const ArgoClusterSecret = Composite((options) => {
177
+ const { name, server, config, argoNamespace = "argocd", labels = {}, defaults } = options;
178
+ const configString = config === undefined ? undefined : typeof config === "string" ? config : JSON.stringify(config);
179
+ const secret = new SecretResource(mergeDefaults({
180
+ metadata: {
181
+ // Secret names can't contain characters from the server URL; use the
182
+ // cluster name as the object name.
183
+ name: `cluster-${name}`,
184
+ namespace: argoNamespace,
185
+ labels: {
186
+ "argocd.argoproj.io/secret-type": "cluster",
187
+ "app.kubernetes.io/managed-by": "chant",
188
+ ...labels,
189
+ },
190
+ },
191
+ type: "Opaque",
192
+ stringData: {
193
+ name,
194
+ server,
195
+ ...(configString !== undefined && { config: configString }),
196
+ },
197
+ }, defaults?.secret));
198
+ return { secret };
199
+ }, "ArgoClusterSecret");
@@ -0,0 +1,174 @@
1
+ /**
2
+ * AutoscaledService composite — Deployment + Service + HPA + PDB.
3
+ *
4
+ * A higher-level construct for production HTTP services with autoscaling
5
+ * and disruption budget. Enforces that HPA targets match the Deployment,
6
+ * PDB selectors match pod labels, and resource requests are set.
7
+ */
8
+ import { Composite, mergeDefaults } from "@intentius/chant";
9
+ import { Deployment, Service, HorizontalPodAutoscaler, PodDisruptionBudget } from "../generated/index.js";
10
+ /**
11
+ * Create an AutoscaledService composite — returns prop objects for
12
+ * a Deployment, Service, HorizontalPodAutoscaler, and PodDisruptionBudget.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { AutoscaledService } from "@intentius/chant-lexicon-k8s";
17
+ *
18
+ * const { deployment, service, hpa, pdb } = AutoscaledService({
19
+ * name: "api",
20
+ * image: "api:1.0",
21
+ * maxReplicas: 10,
22
+ * cpuRequest: "100m",
23
+ * memoryRequest: "128Mi",
24
+ * });
25
+ * ```
26
+ */
27
+ export const AutoscaledService = Composite((props) => {
28
+ const { name, image, port = 80, minReplicas = 2, maxReplicas, targetCPUPercent = 70, targetMemoryPercent, minAvailable = 1, cpuRequest, memoryRequest, cpuLimit, memoryLimit, topologySpread = false, livenessPath = "/healthz", readinessPath = "/readyz", initContainers, securityContext, terminationGracePeriodSeconds, priorityClassName, labels: extraLabels = {}, namespace, env, serviceAccountName, volumes: explicitVolumes = [], volumeMounts: explicitMounts = [], tmpDirs = [], defaults: defs, } = props;
29
+ const commonLabels = {
30
+ "app.kubernetes.io/name": name,
31
+ "app.kubernetes.io/managed-by": "chant",
32
+ ...extraLabels,
33
+ };
34
+ // Build topologySpreadConstraints if enabled
35
+ const topologyConstraints = (() => {
36
+ if (!topologySpread)
37
+ return undefined;
38
+ const maxSkew = typeof topologySpread === "object" ? (topologySpread.maxSkew ?? 1) : 1;
39
+ const topologyKey = typeof topologySpread === "object"
40
+ ? (topologySpread.topologyKey ?? "topology.kubernetes.io/zone")
41
+ : "topology.kubernetes.io/zone";
42
+ return [{
43
+ maxSkew,
44
+ topologyKey,
45
+ whenUnsatisfiable: "DoNotSchedule",
46
+ labelSelector: { matchLabels: { "app.kubernetes.io/name": name } },
47
+ }];
48
+ })();
49
+ // Generate emptyDir volumes/mounts from tmpDirs, then merge with explicit
50
+ const tmpVolumes = tmpDirs.map((_, i) => ({ name: `tmp-${i}`, emptyDir: {} }));
51
+ const tmpMounts = tmpDirs.map((dir, i) => ({ name: `tmp-${i}`, mountPath: dir }));
52
+ const allVolumes = [...explicitVolumes, ...tmpVolumes];
53
+ const allMounts = [...explicitMounts, ...tmpMounts];
54
+ const resources = {
55
+ requests: { cpu: cpuRequest, memory: memoryRequest },
56
+ ...(cpuLimit || memoryLimit
57
+ ? {
58
+ limits: {
59
+ ...(cpuLimit && { cpu: cpuLimit }),
60
+ ...(memoryLimit && { memory: memoryLimit }),
61
+ },
62
+ }
63
+ : {}),
64
+ };
65
+ const deployment = new Deployment(mergeDefaults({
66
+ metadata: {
67
+ name,
68
+ ...(namespace && { namespace }),
69
+ labels: { ...commonLabels, "app.kubernetes.io/component": "server" },
70
+ },
71
+ spec: {
72
+ replicas: minReplicas,
73
+ selector: { matchLabels: { "app.kubernetes.io/name": name } },
74
+ template: {
75
+ metadata: { labels: { "app.kubernetes.io/name": name, ...extraLabels } },
76
+ spec: {
77
+ containers: [
78
+ {
79
+ name,
80
+ image,
81
+ ports: [{ containerPort: port, name: "http" }],
82
+ resources,
83
+ livenessProbe: {
84
+ httpGet: { path: livenessPath, port },
85
+ initialDelaySeconds: 10,
86
+ periodSeconds: 10,
87
+ },
88
+ readinessProbe: {
89
+ httpGet: { path: readinessPath, port },
90
+ initialDelaySeconds: 5,
91
+ periodSeconds: 5,
92
+ },
93
+ ...(env && { env }),
94
+ ...(securityContext && { securityContext }),
95
+ ...(allMounts.length > 0 && { volumeMounts: allMounts }),
96
+ },
97
+ ],
98
+ ...(initContainers && {
99
+ initContainers: initContainers.map((ic) => ({
100
+ name: ic.name,
101
+ image: ic.image,
102
+ ...(ic.command && { command: ic.command }),
103
+ ...(ic.args && { args: ic.args }),
104
+ })),
105
+ }),
106
+ ...(topologyConstraints && { topologySpreadConstraints: topologyConstraints }),
107
+ ...(terminationGracePeriodSeconds !== undefined && { terminationGracePeriodSeconds }),
108
+ ...(priorityClassName && { priorityClassName }),
109
+ ...(serviceAccountName && { serviceAccountName }),
110
+ ...(allVolumes.length > 0 && { volumes: allVolumes }),
111
+ },
112
+ },
113
+ },
114
+ }, defs?.deployment));
115
+ const service = new Service(mergeDefaults({
116
+ metadata: {
117
+ name,
118
+ ...(namespace && { namespace }),
119
+ labels: { ...commonLabels, "app.kubernetes.io/component": "server" },
120
+ },
121
+ spec: {
122
+ selector: { "app.kubernetes.io/name": name },
123
+ ports: [{ port: 80, targetPort: port, protocol: "TCP", name: "http" }],
124
+ type: "ClusterIP",
125
+ },
126
+ }, defs?.service));
127
+ const metrics = [
128
+ {
129
+ type: "Resource",
130
+ resource: {
131
+ name: "cpu",
132
+ target: { type: "Utilization", averageUtilization: targetCPUPercent },
133
+ },
134
+ },
135
+ ];
136
+ if (targetMemoryPercent !== undefined) {
137
+ metrics.push({
138
+ type: "Resource",
139
+ resource: {
140
+ name: "memory",
141
+ target: { type: "Utilization", averageUtilization: targetMemoryPercent },
142
+ },
143
+ });
144
+ }
145
+ const hpa = new HorizontalPodAutoscaler(mergeDefaults({
146
+ metadata: {
147
+ name,
148
+ ...(namespace && { namespace }),
149
+ labels: { ...commonLabels, "app.kubernetes.io/component": "autoscaler" },
150
+ },
151
+ spec: {
152
+ scaleTargetRef: {
153
+ apiVersion: "apps/v1",
154
+ kind: "Deployment",
155
+ name,
156
+ },
157
+ minReplicas,
158
+ maxReplicas,
159
+ metrics,
160
+ },
161
+ }, defs?.hpa));
162
+ const pdb = new PodDisruptionBudget(mergeDefaults({
163
+ metadata: {
164
+ name,
165
+ ...(namespace && { namespace }),
166
+ labels: { ...commonLabels, "app.kubernetes.io/component": "disruption-budget" },
167
+ },
168
+ spec: {
169
+ minAvailable,
170
+ selector: { matchLabels: { "app.kubernetes.io/name": name } },
171
+ },
172
+ }, defs?.pdb));
173
+ return { deployment, service, hpa, pdb };
174
+ }, "AutoscaledService");
@@ -0,0 +1,47 @@
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
+ import { Composite, mergeDefaults } from "@intentius/chant";
7
+ import { StorageClass } from "../generated/index.js";
8
+ /**
9
+ * Create an AzureDiskStorageClass composite — returns prop objects for
10
+ * a StorageClass with the Azure Disk CSI provisioner.
11
+ *
12
+ * @aks
13
+ * @example
14
+ * ```ts
15
+ * import { AzureDiskStorageClass } from "@intentius/chant-lexicon-k8s";
16
+ *
17
+ * const { storageClass } = AzureDiskStorageClass({
18
+ * name: "premium-disk",
19
+ * skuName: "Premium_LRS",
20
+ * });
21
+ * ```
22
+ */
23
+ export const AzureDiskStorageClass = Composite((props) => {
24
+ const { name, skuName = "Premium_LRS", cachingMode = "ReadOnly", networkAccessPolicy = "AllowAll", reclaimPolicy = "Delete", volumeBindingMode = "WaitForFirstConsumer", allowVolumeExpansion = true, labels: extraLabels = {}, defaults: defs, } = props;
25
+ const commonLabels = {
26
+ "app.kubernetes.io/name": name,
27
+ "app.kubernetes.io/managed-by": "chant",
28
+ ...extraLabels,
29
+ };
30
+ const parameters = {
31
+ skuName,
32
+ cachingMode,
33
+ networkAccessPolicy,
34
+ };
35
+ const storageClass = new StorageClass(mergeDefaults({
36
+ metadata: {
37
+ name,
38
+ labels: { ...commonLabels, "app.kubernetes.io/component": "storage" },
39
+ },
40
+ provisioner: "disk.csi.azure.com",
41
+ parameters,
42
+ reclaimPolicy,
43
+ volumeBindingMode,
44
+ allowVolumeExpansion,
45
+ }, defs?.storageClass));
46
+ return { storageClass };
47
+ }, "AzureDiskStorageClass");
@@ -0,0 +1,48 @@
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
+ import { Composite, mergeDefaults } from "@intentius/chant";
8
+ import { StorageClass } from "../generated/index.js";
9
+ /**
10
+ * Create an AzureFileStorageClass composite — returns prop objects for
11
+ * a StorageClass with the Azure Files CSI provisioner.
12
+ *
13
+ * @aks
14
+ * @example
15
+ * ```ts
16
+ * import { AzureFileStorageClass } from "@intentius/chant-lexicon-k8s";
17
+ *
18
+ * const { storageClass } = AzureFileStorageClass({
19
+ * name: "azure-files-shared",
20
+ * skuName: "Premium_LRS",
21
+ * protocol: "nfs",
22
+ * });
23
+ * ```
24
+ */
25
+ export const AzureFileStorageClass = Composite((props) => {
26
+ const { name, skuName = "Premium_LRS", protocol = "smb", shareName, reclaimPolicy = "Delete", labels: extraLabels = {}, defaults: defs, } = props;
27
+ const commonLabels = {
28
+ "app.kubernetes.io/name": name,
29
+ "app.kubernetes.io/managed-by": "chant",
30
+ ...extraLabels,
31
+ };
32
+ const parameters = {
33
+ skuName,
34
+ protocol,
35
+ };
36
+ if (shareName)
37
+ parameters.shareName = shareName;
38
+ const storageClass = new StorageClass(mergeDefaults({
39
+ metadata: {
40
+ name,
41
+ labels: { ...commonLabels, "app.kubernetes.io/component": "storage" },
42
+ },
43
+ provisioner: "file.csi.azure.com",
44
+ parameters,
45
+ reclaimPolicy,
46
+ }, defs?.storageClass));
47
+ return { storageClass };
48
+ }, "AzureFileStorageClass");
@@ -0,0 +1,176 @@
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
+ import { Composite, mergeDefaults } from "@intentius/chant";
8
+ import { DaemonSet, ServiceAccount, ClusterRole, ClusterRoleBinding, ConfigMap } from "../generated/index.js";
9
+ /**
10
+ * Create an AzureMonitorCollector composite — returns prop objects for
11
+ * a DaemonSet, ServiceAccount, ClusterRole, ClusterRoleBinding, and ConfigMap.
12
+ *
13
+ * @aks
14
+ * @example
15
+ * ```ts
16
+ * import { AzureMonitorCollector } from "@intentius/chant-lexicon-k8s";
17
+ *
18
+ * const { daemonSet, serviceAccount, clusterRole, clusterRoleBinding, configMap } = AzureMonitorCollector({
19
+ * workspaceId: "00000000-0000-0000-0000-000000000000",
20
+ * clusterName: "my-aks-cluster",
21
+ * });
22
+ * ```
23
+ */
24
+ export const AzureMonitorCollector = Composite((props) => {
25
+ const { workspaceId, clusterName, name = "azure-monitor-collector", image = "mcr.microsoft.com/azuremonitor/containerinsights/ciprod:3.1.35", namespace = "azure-monitor", labels: extraLabels = {}, cpuRequest = "100m", memoryRequest = "256Mi", cpuLimit = "500m", memoryLimit = "512Mi", clientId, defaults: defs, } = props;
26
+ const saName = `${name}-sa`;
27
+ const clusterRoleName = `${name}-role`;
28
+ const bindingName = `${name}-binding`;
29
+ const configMapName = `${name}-config`;
30
+ const commonLabels = {
31
+ "app.kubernetes.io/name": name,
32
+ "app.kubernetes.io/managed-by": "chant",
33
+ ...extraLabels,
34
+ };
35
+ // Build OTel collector config YAML for Azure Monitor
36
+ const collectorConfig = `receivers:
37
+ otlp:
38
+ protocols:
39
+ grpc:
40
+ endpoint: 0.0.0.0:4317
41
+ http:
42
+ endpoint: 0.0.0.0:4318
43
+
44
+ processors:
45
+ batch:
46
+ timeout: 30s
47
+ send_batch_size: 8192
48
+
49
+ exporters:
50
+ azuremonitor:
51
+ connection_string: InstrumentationKey=\${APPINSIGHTS_INSTRUMENTATIONKEY}
52
+ endpoint: https://dc.services.visualstudio.com/v2/track
53
+ azuremonitor/logs:
54
+ workspace_id: ${workspaceId}
55
+ cluster_name: ${clusterName}
56
+
57
+ service:
58
+ pipelines:
59
+ metrics:
60
+ receivers: [otlp]
61
+ processors: [batch]
62
+ exporters: [azuremonitor]
63
+ traces:
64
+ receivers: [otlp]
65
+ processors: [batch]
66
+ exporters: [azuremonitor]
67
+ logs:
68
+ receivers: [otlp]
69
+ processors: [batch]
70
+ exporters: [azuremonitor/logs]
71
+ `;
72
+ const container = {
73
+ name,
74
+ image,
75
+ ports: [
76
+ { containerPort: 4317, name: "otlp-grpc" },
77
+ { containerPort: 4318, name: "otlp-http" },
78
+ ],
79
+ env: [
80
+ { name: "AKS_CLUSTER_NAME", value: clusterName },
81
+ { name: "WORKSPACE_ID", value: workspaceId },
82
+ ],
83
+ resources: {
84
+ requests: { cpu: cpuRequest, memory: memoryRequest },
85
+ limits: { cpu: cpuLimit, memory: memoryLimit },
86
+ },
87
+ volumeMounts: [
88
+ { name: "config", mountPath: "/etc/otel", readOnly: true },
89
+ ],
90
+ };
91
+ const daemonSet = new DaemonSet(mergeDefaults({
92
+ metadata: {
93
+ name,
94
+ namespace,
95
+ labels: { ...commonLabels, "app.kubernetes.io/component": "agent" },
96
+ },
97
+ spec: {
98
+ selector: { matchLabels: { "app.kubernetes.io/name": name } },
99
+ template: {
100
+ metadata: { labels: { "app.kubernetes.io/name": name, ...extraLabels } },
101
+ spec: {
102
+ serviceAccountName: saName,
103
+ containers: [container],
104
+ volumes: [
105
+ { name: "config", configMap: { name: configMapName } },
106
+ ],
107
+ tolerations: [{ operator: "Exists" }],
108
+ },
109
+ },
110
+ },
111
+ }, defs?.daemonSet));
112
+ const saLabels = {
113
+ ...commonLabels,
114
+ "app.kubernetes.io/component": "agent",
115
+ };
116
+ if (clientId) {
117
+ saLabels["azure.workload.identity/use"] = "true";
118
+ }
119
+ const serviceAccount = new ServiceAccount(mergeDefaults({
120
+ metadata: {
121
+ name: saName,
122
+ namespace,
123
+ labels: saLabels,
124
+ ...(clientId ? { annotations: { "azure.workload.identity/client-id": clientId } } : {}),
125
+ },
126
+ }, defs?.serviceAccount));
127
+ const clusterRole = new ClusterRole(mergeDefaults({
128
+ metadata: {
129
+ name: clusterRoleName,
130
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
131
+ },
132
+ rules: [
133
+ { apiGroups: [""], resources: ["pods", "nodes", "endpoints"], verbs: ["get", "list", "watch"] },
134
+ { apiGroups: ["apps"], resources: ["replicasets"], verbs: ["get", "list", "watch"] },
135
+ { apiGroups: ["batch"], resources: ["jobs"], verbs: ["get", "list", "watch"] },
136
+ { apiGroups: [""], resources: ["nodes/proxy"], verbs: ["get"] },
137
+ { apiGroups: [""], resources: ["nodes/stats", "configmaps", "events"], verbs: ["create", "get"] },
138
+ { apiGroups: [""], resources: ["configmaps"], verbs: ["get", "update", "create"], resourceNames: ["otel-container-insight-clusterleader"] },
139
+ ],
140
+ }, defs?.clusterRole));
141
+ const clusterRoleBinding = new ClusterRoleBinding(mergeDefaults({
142
+ metadata: {
143
+ name: bindingName,
144
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
145
+ },
146
+ roleRef: {
147
+ apiGroup: "rbac.authorization.k8s.io",
148
+ kind: "ClusterRole",
149
+ name: clusterRoleName,
150
+ },
151
+ subjects: [
152
+ {
153
+ kind: "ServiceAccount",
154
+ name: saName,
155
+ namespace,
156
+ },
157
+ ],
158
+ }, defs?.clusterRoleBinding));
159
+ const configMap = new ConfigMap(mergeDefaults({
160
+ metadata: {
161
+ name: configMapName,
162
+ namespace,
163
+ labels: { ...commonLabels, "app.kubernetes.io/component": "config" },
164
+ },
165
+ data: {
166
+ "config.yaml": collectorConfig,
167
+ },
168
+ }, defs?.configMap));
169
+ return {
170
+ daemonSet,
171
+ serviceAccount,
172
+ clusterRole,
173
+ clusterRoleBinding,
174
+ configMap,
175
+ };
176
+ }, "AzureMonitorCollector");