@intentius/chant-lexicon-k8s 0.124.30 → 0.124.32

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,156 @@
1
+ /**
2
+ * Flux CD composites — turn Chant build targets into Flux sources and
3
+ * `Kustomization`s.
4
+ *
5
+ * The k8s lexicon stays runtime-agnostic: it only emits manifests. These
6
+ * composites are the opt-in bridge to Flux's reconciliation layer, the
7
+ * `ArgoAppFor` analogue for the source-controller/kustomize-controller pair.
8
+ * Authoring a `GitRepository` + `Kustomization` by hand is ~40 lines of YAML
9
+ * per app; `FluxAppFor` collapses the pair to one call with defaults taken
10
+ * from real Flux estates.
11
+ *
12
+ * - FluxGitSource(name, opts) → a single K8s::Flux::GitRepository
13
+ * - FluxAppFor(target, opts) → a single K8s::Flux::Kustomization
14
+ *
15
+ * The two are split deliberately: the common estate shape is one source
16
+ * shared by many Kustomizations. A `GitRepository` per app is the mistake
17
+ * this split makes hard — declare the source once, hand its result to every
18
+ * `FluxAppFor` that reconciles a path out of it.
19
+ */
20
+ import { Composite, mergeDefaults } from "@intentius/chant";
21
+ import { GitRepository as GitRepositoryResource, Kustomization as KustomizationResource, } from "../generated/index.js";
22
+ // ── Shared types ─────────────────────────────────────────────────────────────
23
+ /** The namespace the Flux controllers run in and watch by default. */
24
+ const FLUX_NAMESPACE = "flux-system";
25
+ /** knr-ops's name for the bootstrap-injected age identity Secret, and the
26
+ * name `flux bootstrap` documentation uses. */
27
+ const SOPS_AGE_SECRET_NAME = "sops-age";
28
+ const FluxGitRepository = Composite((props) => {
29
+ const { name, url, branch = "main", tag, interval = "5m", secretRef, fluxNamespace = FLUX_NAMESPACE, labels = {}, defaults, } = props;
30
+ const gitRepository = new GitRepositoryResource(mergeDefaults({
31
+ metadata: {
32
+ name,
33
+ namespace: fluxNamespace,
34
+ labels: {
35
+ "app.kubernetes.io/name": name,
36
+ "app.kubernetes.io/managed-by": "chant",
37
+ ...labels,
38
+ },
39
+ },
40
+ spec: {
41
+ interval,
42
+ url,
43
+ // An unset spec.ref falls back to `master` — always pin (FLUX001).
44
+ ref: tag !== undefined ? { tag } : { branch },
45
+ ...(secretRef !== undefined && { secretRef: { name: secretRef } }),
46
+ },
47
+ }, defaults?.gitRepository));
48
+ return { gitRepository };
49
+ }, "FluxGitRepository");
50
+ /**
51
+ * Declare a Flux `GitRepository` source in one call.
52
+ *
53
+ * Declare it once and share it: every `FluxAppFor` that reconciles a path out
54
+ * of the same repo should take this result as its `source`.
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * import { FluxGitSource } from "@intentius/chant-lexicon-k8s";
59
+ *
60
+ * export const source = FluxGitSource("home-chant", {
61
+ * url: "https://github.com/jhgaylor/home-chant",
62
+ * branch: "main",
63
+ * });
64
+ * ```
65
+ */
66
+ export function FluxGitSource(name, options) {
67
+ return FluxGitRepository({ name, ...options });
68
+ }
69
+ /** Resolve the `source` option to a rendered sourceRef. */
70
+ function resolveSourceRef(target, source) {
71
+ if (typeof source === "string") {
72
+ return { kind: "GitRepository", name: source };
73
+ }
74
+ if ("gitRepository" in source && source.gitRepository !== undefined) {
75
+ const metadata = source.gitRepository
76
+ .props?.metadata;
77
+ const name = metadata?.name;
78
+ if (typeof name !== "string" || name === "") {
79
+ throw new Error(`FluxAppFor("${target}"): the supplied FluxGitSource result has no metadata.name to reference.`);
80
+ }
81
+ return {
82
+ kind: "GitRepository",
83
+ name,
84
+ ...(typeof metadata?.namespace === "string" && { namespace: metadata.namespace }),
85
+ };
86
+ }
87
+ const ref = source;
88
+ return {
89
+ kind: ref.kind ?? "GitRepository",
90
+ name: ref.name,
91
+ ...(ref.namespace !== undefined && { namespace: ref.namespace }),
92
+ };
93
+ }
94
+ const FluxKustomization = Composite((props) => {
95
+ const { target, source, path, targetNamespace, interval = "10m", prune = true, wait = true, dependsOn = [], timeout, suspend, serviceAccountName, decryption, fluxNamespace = FLUX_NAMESPACE, labels = {}, defaults, } = props;
96
+ const sourceRef = resolveSourceRef(target, source);
97
+ const decryptionSpec = decryption === undefined
98
+ ? undefined
99
+ : {
100
+ provider: "sops",
101
+ secretRef: {
102
+ name: typeof decryption === "string" ? SOPS_AGE_SECRET_NAME : decryption.secretRef ?? SOPS_AGE_SECRET_NAME,
103
+ },
104
+ };
105
+ // The Kustomization's namespace also scopes the sourceRef: an in-spec
106
+ // sourceRef without a namespace resolves in the Kustomization's own.
107
+ const kustomization = new KustomizationResource(mergeDefaults({
108
+ metadata: {
109
+ name: target,
110
+ namespace: fluxNamespace,
111
+ labels: {
112
+ "app.kubernetes.io/name": target,
113
+ "app.kubernetes.io/managed-by": "chant",
114
+ ...labels,
115
+ },
116
+ },
117
+ spec: {
118
+ interval,
119
+ path,
120
+ prune,
121
+ wait,
122
+ sourceRef,
123
+ ...(targetNamespace !== undefined && { targetNamespace }),
124
+ ...(dependsOn.length > 0 && { dependsOn: dependsOn.map((name) => ({ name })) }),
125
+ ...(timeout !== undefined && { timeout }),
126
+ ...(suspend !== undefined && { suspend }),
127
+ ...(serviceAccountName !== undefined && { serviceAccountName }),
128
+ ...(decryptionSpec !== undefined && { decryption: decryptionSpec }),
129
+ },
130
+ }, defaults?.kustomization));
131
+ return { kustomization };
132
+ }, "FluxKustomization");
133
+ /**
134
+ * Reconcile a Chant build target with Flux in one call — the `Kustomization`
135
+ * half of the GitRepository + Kustomization pair. The source is passed in,
136
+ * not created here, so many apps share one repo declaration.
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * import { FluxGitSource, FluxAppFor } from "@intentius/chant-lexicon-k8s";
141
+ *
142
+ * export const source = FluxGitSource("home-chant", {
143
+ * url: "https://github.com/jhgaylor/home-chant",
144
+ * });
145
+ *
146
+ * export const hello = FluxAppFor("hello-chant", {
147
+ * source,
148
+ * path: "./apps/hello-chant/k8s",
149
+ * targetNamespace: "default",
150
+ * dependsOn: ["cert-manager", "traefik"],
151
+ * });
152
+ * ```
153
+ */
154
+ export function FluxAppFor(target, options) {
155
+ return FluxKustomization({ target, ...options });
156
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * GceIngress composite — Ingress with GCE Ingress Controller annotations.
3
+ *
4
+ * @gke Full `kubernetes.io/ingress.*` and `networking.gke.io/*` annotation set
5
+ * including static IP, managed certificates, and FrontendConfig.
6
+ */
7
+ import { Composite, mergeDefaults } from "@intentius/chant";
8
+ import { Ingress } from "../generated/index.js";
9
+ /**
10
+ * Create a GceIngress composite — returns prop objects for
11
+ * an Ingress with GCE Ingress Controller annotations.
12
+ *
13
+ * @gke
14
+ * @example
15
+ * ```ts
16
+ * import { GceIngress } from "@intentius/chant-lexicon-k8s";
17
+ *
18
+ * const { ingress } = GceIngress({
19
+ * name: "api-ingress",
20
+ * hosts: [
21
+ * {
22
+ * hostname: "api.example.com",
23
+ * paths: [{ path: "/", serviceName: "api", servicePort: 80 }],
24
+ * },
25
+ * ],
26
+ * staticIpName: "microservice-ip",
27
+ * managedCertificate: "api-cert",
28
+ * });
29
+ * ```
30
+ */
31
+ export const GceIngress = Composite((props) => {
32
+ const { name, hosts, staticIpName, managedCertificate, frontendConfig, healthCheckPath, sslRedirect, annotations: extraAnnotations = {}, labels: extraLabels = {}, namespace, defaults: defs, } = props;
33
+ const commonLabels = {
34
+ "app.kubernetes.io/name": name,
35
+ "app.kubernetes.io/managed-by": "chant",
36
+ ...extraLabels,
37
+ };
38
+ // Build GCE annotations
39
+ const annotations = {
40
+ "kubernetes.io/ingress.class": "gce",
41
+ ...extraAnnotations,
42
+ };
43
+ if (staticIpName) {
44
+ annotations["kubernetes.io/ingress.global-static-ip-name"] = staticIpName;
45
+ }
46
+ if (managedCertificate) {
47
+ annotations["networking.gke.io/managed-certificates"] = managedCertificate;
48
+ }
49
+ if (frontendConfig) {
50
+ annotations["networking.gke.io/v1beta1.FrontendConfig"] = frontendConfig;
51
+ }
52
+ if (sslRedirect ?? !!managedCertificate) {
53
+ annotations["networking.gke.io/v1beta1.FrontendConfig"] =
54
+ annotations["networking.gke.io/v1beta1.FrontendConfig"] ?? `${name}-frontend-config`;
55
+ }
56
+ if (healthCheckPath) {
57
+ annotations["cloud.google.com/neg"] = '{"ingress": true}';
58
+ }
59
+ const ingressRules = hosts.map((host) => ({
60
+ host: host.hostname,
61
+ http: {
62
+ paths: host.paths.map((p) => ({
63
+ path: p.path,
64
+ pathType: p.pathType ?? "Prefix",
65
+ backend: {
66
+ service: { name: p.serviceName, port: { number: p.servicePort } },
67
+ },
68
+ })),
69
+ },
70
+ }));
71
+ const ingress = new Ingress(mergeDefaults({
72
+ metadata: {
73
+ name,
74
+ ...(namespace && { namespace }),
75
+ labels: { ...commonLabels, "app.kubernetes.io/component": "ingress" },
76
+ annotations,
77
+ },
78
+ spec: {
79
+ rules: ingressRules,
80
+ },
81
+ }, defs?.ingress));
82
+ return { ingress };
83
+ }, "GceIngress");
@@ -0,0 +1,49 @@
1
+ /**
2
+ * GcePdStorageClass composite — StorageClass for GCE Persistent Disk CSI driver.
3
+ *
4
+ * @gke Creates a StorageClass with the `pd.csi.storage.gke.io` provisioner.
5
+ */
6
+ import { Composite, mergeDefaults } from "@intentius/chant";
7
+ import { StorageClass } from "../generated/index.js";
8
+ /**
9
+ * Create a GcePdStorageClass composite — returns prop objects for
10
+ * a StorageClass with the GCE Persistent Disk CSI provisioner.
11
+ *
12
+ * @gke
13
+ * @example
14
+ * ```ts
15
+ * import { GcePdStorageClass } from "@intentius/chant-lexicon-k8s";
16
+ *
17
+ * const { storageClass } = GcePdStorageClass({
18
+ * name: "pd-ssd",
19
+ * type: "pd-ssd",
20
+ * });
21
+ * ```
22
+ */
23
+ export const GcePdStorageClass = Composite((props) => {
24
+ const { name, type = "pd-balanced", replicationType = "none", fsType = "ext4", 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
+ type,
32
+ "csi.storage.k8s.io/fstype": fsType,
33
+ };
34
+ if (replicationType !== "none") {
35
+ parameters["replication-type"] = replicationType;
36
+ }
37
+ const storageClass = new StorageClass(mergeDefaults({
38
+ metadata: {
39
+ name,
40
+ labels: { ...commonLabels, "app.kubernetes.io/component": "storage" },
41
+ },
42
+ provisioner: "pd.csi.storage.gke.io",
43
+ parameters,
44
+ reclaimPolicy,
45
+ volumeBindingMode,
46
+ allowVolumeExpansion,
47
+ }, defs?.storageClass));
48
+ return { storageClass };
49
+ }, "GcePdStorageClass");
@@ -0,0 +1,129 @@
1
+ /**
2
+ * GkeExternalDnsAgent composite — Deployment + ServiceAccount + ClusterRole + ClusterRoleBinding.
3
+ *
4
+ * @gke Like ExternalDnsAgent but uses --provider=google and GKE Workload Identity
5
+ * instead of IRSA for Cloud DNS management.
6
+ */
7
+ import { Composite, mergeDefaults } from "@intentius/chant";
8
+ import { Deployment, ServiceAccount, ClusterRole, ClusterRoleBinding } from "../generated/index.js";
9
+ /**
10
+ * Create a GkeExternalDnsAgent composite — returns prop objects for
11
+ * a Deployment, ServiceAccount (with Workload Identity), ClusterRole, and ClusterRoleBinding.
12
+ *
13
+ * @gke
14
+ * @example
15
+ * ```ts
16
+ * import { GkeExternalDnsAgent } from "@intentius/chant-lexicon-k8s";
17
+ *
18
+ * const { deployment, serviceAccount, clusterRole, clusterRoleBinding } = GkeExternalDnsAgent({
19
+ * gcpServiceAccountEmail: "external-dns@my-project.iam.gserviceaccount.com",
20
+ * gcpProjectId: "my-project",
21
+ * domainFilters: ["example.com"],
22
+ * txtOwnerId: "my-cluster",
23
+ * });
24
+ * ```
25
+ */
26
+ export const GkeExternalDnsAgent = Composite((props) => {
27
+ const { gcpServiceAccountEmail, gcpProjectId, domainFilters, txtOwnerId, source = "ingress", name = "external-dns", image = "registry.k8s.io/external-dns/external-dns:v0.14.0", namespace = "kube-system", labels: extraLabels = {}, defaults: defs, } = props;
28
+ const saName = `${name}-sa`;
29
+ const clusterRoleName = `${name}-role`;
30
+ const bindingName = `${name}-binding`;
31
+ const commonLabels = {
32
+ "app.kubernetes.io/name": name,
33
+ "app.kubernetes.io/managed-by": "chant",
34
+ ...extraLabels,
35
+ };
36
+ const sources = Array.isArray(source) ? source : [source];
37
+ const args = [
38
+ ...sources.map((s) => `--source=${s}`),
39
+ "--provider=google",
40
+ `--google-project=${gcpProjectId}`,
41
+ "--policy=upsert-only",
42
+ "--registry=txt",
43
+ ];
44
+ for (const domain of domainFilters) {
45
+ args.push(`--domain-filter=${domain}`);
46
+ }
47
+ if (txtOwnerId) {
48
+ args.push(`--txt-owner-id=${txtOwnerId}`);
49
+ }
50
+ const deployment = new Deployment(mergeDefaults({
51
+ metadata: {
52
+ name,
53
+ namespace,
54
+ labels: { ...commonLabels, "app.kubernetes.io/component": "dns" },
55
+ },
56
+ spec: {
57
+ replicas: 1,
58
+ selector: { matchLabels: { "app.kubernetes.io/name": name } },
59
+ template: {
60
+ metadata: { labels: { "app.kubernetes.io/name": name, ...extraLabels } },
61
+ spec: {
62
+ serviceAccountName: saName,
63
+ containers: [
64
+ {
65
+ name,
66
+ image,
67
+ args,
68
+ resources: {
69
+ requests: { cpu: "50m", memory: "64Mi" },
70
+ limits: { cpu: "100m", memory: "128Mi" },
71
+ },
72
+ securityContext: {
73
+ runAsNonRoot: true,
74
+ runAsUser: 65534,
75
+ readOnlyRootFilesystem: true,
76
+ allowPrivilegeEscalation: false,
77
+ },
78
+ },
79
+ ],
80
+ },
81
+ },
82
+ },
83
+ }, defs?.deployment));
84
+ const serviceAccount = new ServiceAccount(mergeDefaults({
85
+ metadata: {
86
+ name: saName,
87
+ namespace,
88
+ labels: { ...commonLabels, "app.kubernetes.io/component": "dns" },
89
+ annotations: {
90
+ "iam.gke.io/gcp-service-account": gcpServiceAccountEmail,
91
+ },
92
+ },
93
+ }, defs?.serviceAccount));
94
+ const clusterRole = new ClusterRole(mergeDefaults({
95
+ metadata: {
96
+ name: clusterRoleName,
97
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
98
+ },
99
+ rules: [
100
+ { apiGroups: [""], resources: ["services", "endpoints", "pods"], verbs: ["get", "watch", "list"] },
101
+ { apiGroups: ["extensions", "networking.k8s.io"], resources: ["ingresses"], verbs: ["get", "watch", "list"] },
102
+ { apiGroups: [""], resources: ["nodes"], verbs: ["list", "watch"] },
103
+ ],
104
+ }, defs?.clusterRole));
105
+ const clusterRoleBinding = new ClusterRoleBinding(mergeDefaults({
106
+ metadata: {
107
+ name: bindingName,
108
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
109
+ },
110
+ roleRef: {
111
+ apiGroup: "rbac.authorization.k8s.io",
112
+ kind: "ClusterRole",
113
+ name: clusterRoleName,
114
+ },
115
+ subjects: [
116
+ {
117
+ kind: "ServiceAccount",
118
+ name: saName,
119
+ namespace,
120
+ },
121
+ ],
122
+ }, defs?.clusterRoleBinding));
123
+ return {
124
+ deployment,
125
+ serviceAccount,
126
+ clusterRole,
127
+ clusterRoleBinding,
128
+ };
129
+ }, "GkeExternalDnsAgent");
@@ -0,0 +1,165 @@
1
+ /**
2
+ * GkeFluentBitAgent composite — DaemonSet + RBAC + ConfigMap for Fluent Bit on GKE.
3
+ *
4
+ * @gke Like FluentBitAgent but targets Cloud Logging via the stackdriver
5
+ * output plugin and uses GKE Workload Identity instead of IRSA.
6
+ */
7
+ import { Composite, mergeDefaults } from "@intentius/chant";
8
+ import { DaemonSet, ServiceAccount, ClusterRole, ClusterRoleBinding, ConfigMap } from "../generated/index.js";
9
+ /**
10
+ * Create a GkeFluentBitAgent composite — returns prop objects for
11
+ * a DaemonSet, ServiceAccount, ClusterRole, ClusterRoleBinding, and ConfigMap.
12
+ *
13
+ * @gke
14
+ * @example
15
+ * ```ts
16
+ * import { GkeFluentBitAgent } from "@intentius/chant-lexicon-k8s";
17
+ *
18
+ * const { daemonSet, serviceAccount, clusterRole, clusterRoleBinding, configMap } = GkeFluentBitAgent({
19
+ * clusterName: "my-cluster",
20
+ * projectId: "my-project",
21
+ * gcpServiceAccountEmail: "fluent-bit@my-project.iam.gserviceaccount.com",
22
+ * });
23
+ * ```
24
+ */
25
+ export const GkeFluentBitAgent = Composite((props) => {
26
+ const { clusterName, projectId, gcpServiceAccountEmail, name = "fluent-bit", image = "fluent/fluent-bit:latest", namespace = "gke-logging", labels: extraLabels = {}, cpuRequest = "50m", memoryRequest = "64Mi", cpuLimit = "200m", memoryLimit = "128Mi", defaults: defs, } = props;
27
+ const saName = `${name}-sa`;
28
+ const clusterRoleName = `${name}-role`;
29
+ const bindingName = `${name}-binding`;
30
+ const configMapName = `${name}-config`;
31
+ const commonLabels = {
32
+ "app.kubernetes.io/name": name,
33
+ "app.kubernetes.io/managed-by": "chant",
34
+ ...extraLabels,
35
+ };
36
+ const fluentBitConfig = `[SERVICE]
37
+ Flush 5
38
+ Log_Level info
39
+ Daemon off
40
+ Parsers_File parsers.conf
41
+
42
+ [INPUT]
43
+ Name tail
44
+ Tag kube.*
45
+ Path /var/log/containers/*.log
46
+ Parser docker
47
+ DB /var/fluent-bit/state/flb_container.db
48
+ Mem_Buf_Limit 5MB
49
+ Skip_Long_Lines On
50
+ Refresh_Interval 10
51
+
52
+ [FILTER]
53
+ Name kubernetes
54
+ Match kube.*
55
+ Kube_URL https://kubernetes.default.svc:443
56
+ Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
57
+ Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
58
+ Merge_Log On
59
+ K8S-Logging.Parser On
60
+ K8S-Logging.Exclude Off
61
+
62
+ [OUTPUT]
63
+ Name stackdriver
64
+ Match *
65
+ google_service_credentials /var/run/secrets/kubernetes.io/serviceaccount/token
66
+ resource k8s_container
67
+ k8s_cluster_name ${clusterName}
68
+ k8s_cluster_location ${projectId}
69
+ `;
70
+ const container = {
71
+ name,
72
+ image,
73
+ resources: {
74
+ requests: { cpu: cpuRequest, memory: memoryRequest },
75
+ limits: { cpu: cpuLimit, memory: memoryLimit },
76
+ },
77
+ volumeMounts: [
78
+ { name: "varlog", mountPath: "/var/log", readOnly: true },
79
+ { name: "config", mountPath: `/etc/${name}`, readOnly: true },
80
+ { name: "state", mountPath: "/var/fluent-bit/state" },
81
+ ],
82
+ securityContext: {
83
+ runAsUser: 0,
84
+ readOnlyRootFilesystem: true,
85
+ allowPrivilegeEscalation: false,
86
+ },
87
+ };
88
+ const daemonSet = new DaemonSet(mergeDefaults({
89
+ metadata: {
90
+ name,
91
+ namespace,
92
+ labels: { ...commonLabels, "app.kubernetes.io/component": "agent" },
93
+ },
94
+ spec: {
95
+ selector: { matchLabels: { "app.kubernetes.io/name": name } },
96
+ template: {
97
+ metadata: { labels: { "app.kubernetes.io/name": name, ...extraLabels } },
98
+ spec: {
99
+ serviceAccountName: saName,
100
+ containers: [container],
101
+ volumes: [
102
+ { name: "varlog", hostPath: { path: "/var/log" } },
103
+ { name: "config", configMap: { name: configMapName } },
104
+ { name: "state", hostPath: { path: `/var/fluent-bit/state/${name}` } },
105
+ ],
106
+ tolerations: [{ operator: "Exists" }],
107
+ },
108
+ },
109
+ },
110
+ }, defs?.daemonSet));
111
+ const serviceAccount = new ServiceAccount(mergeDefaults({
112
+ metadata: {
113
+ name: saName,
114
+ namespace,
115
+ labels: { ...commonLabels, "app.kubernetes.io/component": "agent" },
116
+ ...(gcpServiceAccountEmail
117
+ ? { annotations: { "iam.gke.io/gcp-service-account": gcpServiceAccountEmail } }
118
+ : {}),
119
+ },
120
+ }, defs?.serviceAccount));
121
+ const clusterRole = new ClusterRole(mergeDefaults({
122
+ metadata: {
123
+ name: clusterRoleName,
124
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
125
+ },
126
+ rules: [
127
+ { apiGroups: [""], resources: ["namespaces", "pods"], verbs: ["get", "list", "watch"] },
128
+ ],
129
+ }, defs?.clusterRole));
130
+ const clusterRoleBinding = new ClusterRoleBinding(mergeDefaults({
131
+ metadata: {
132
+ name: bindingName,
133
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
134
+ },
135
+ roleRef: {
136
+ apiGroup: "rbac.authorization.k8s.io",
137
+ kind: "ClusterRole",
138
+ name: clusterRoleName,
139
+ },
140
+ subjects: [
141
+ {
142
+ kind: "ServiceAccount",
143
+ name: saName,
144
+ namespace,
145
+ },
146
+ ],
147
+ }, defs?.clusterRoleBinding));
148
+ const configMap = new ConfigMap(mergeDefaults({
149
+ metadata: {
150
+ name: configMapName,
151
+ namespace,
152
+ labels: { ...commonLabels, "app.kubernetes.io/component": "config" },
153
+ },
154
+ data: {
155
+ "fluent-bit.conf": fluentBitConfig,
156
+ },
157
+ }, defs?.configMap));
158
+ return {
159
+ daemonSet,
160
+ serviceAccount,
161
+ clusterRole,
162
+ clusterRoleBinding,
163
+ configMap,
164
+ };
165
+ }, "GkeFluentBitAgent");
@@ -0,0 +1,91 @@
1
+ /**
2
+ * GkeGateway composite — Gateway + HTTPRoute for GKE Gateway API.
3
+ *
4
+ * @gke Creates a Gateway with a GKE-specific `gatewayClassName` and
5
+ * HTTPRoute resources for traffic routing.
6
+ */
7
+ import { Composite, mergeDefaults } from "@intentius/chant";
8
+ import { Deployment } from "../generated/index.js";
9
+ /**
10
+ * Create a GkeGateway composite — returns prop objects for
11
+ * a Gateway and HTTPRoute with GKE-specific gateway class.
12
+ *
13
+ * @gke
14
+ * @example
15
+ * ```ts
16
+ * import { GkeGateway } from "@intentius/chant-lexicon-k8s";
17
+ *
18
+ * const { gateway, httpRoute } = GkeGateway({
19
+ * name: "api-gateway",
20
+ * hosts: [
21
+ * {
22
+ * hostname: "api.example.com",
23
+ * paths: [{ path: "/", serviceName: "api", servicePort: 80 }],
24
+ * },
25
+ * ],
26
+ * certificateName: "api-cert",
27
+ * });
28
+ * ```
29
+ */
30
+ export const GkeGateway = Composite((props) => {
31
+ const { name, gatewayClassName = "gke-l7-global-external-managed", hosts, certificateName, labels: extraLabels = {}, namespace, defaults: defs, } = props;
32
+ const routeName = `${name}-route`;
33
+ const commonLabels = {
34
+ "app.kubernetes.io/name": name,
35
+ "app.kubernetes.io/managed-by": "chant",
36
+ ...extraLabels,
37
+ };
38
+ // Build Gateway listeners
39
+ const listeners = [];
40
+ if (certificateName) {
41
+ listeners.push({
42
+ name: "https",
43
+ protocol: "HTTPS",
44
+ port: 443,
45
+ tls: {
46
+ mode: "Terminate",
47
+ certificateRefs: [{ kind: "ManagedCertificate", name: certificateName }],
48
+ },
49
+ });
50
+ }
51
+ else {
52
+ listeners.push({
53
+ name: "http",
54
+ protocol: "HTTP",
55
+ port: 80,
56
+ });
57
+ }
58
+ // Gateway and HTTPRoute are CRDs — use Deployment constructor as a generic Declarable wrapper
59
+ const gateway = new Deployment(mergeDefaults({
60
+ metadata: {
61
+ name,
62
+ ...(namespace && { namespace }),
63
+ labels: { ...commonLabels, "app.kubernetes.io/component": "gateway" },
64
+ },
65
+ spec: {
66
+ gatewayClassName,
67
+ listeners,
68
+ },
69
+ }, defs?.gateway));
70
+ // Build HTTPRoute rules
71
+ const hostnames = hosts.map((h) => h.hostname);
72
+ const rules = hosts.flatMap((host) => host.paths.map((p) => ({
73
+ matches: [{ path: { type: "PathPrefix", value: p.path } }],
74
+ backendRefs: [
75
+ { name: p.serviceName, port: p.servicePort },
76
+ ],
77
+ })));
78
+ const httpRoute = new Deployment(mergeDefaults({
79
+ metadata: {
80
+ name: routeName,
81
+ ...(namespace && { namespace }),
82
+ labels: { ...commonLabels, "app.kubernetes.io/component": "route" },
83
+ },
84
+ spec: {
85
+ parentRefs: [{ name }],
86
+ hostnames,
87
+ rules,
88
+ },
89
+ }, defs?.httpRoute));
90
+ return { gateway, httpRoute };
91
+ }, "GkeGateway");