@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,371 @@
1
+ /**
2
+ * CockroachDbCluster composite — StatefulSet + Services + RBAC + PDB + Jobs.
3
+ *
4
+ * Deploys a CockroachDB cluster on Kubernetes with TLS support via self-signed
5
+ * certificates. Produces all K8s resources needed for a single cloud's slice of
6
+ * a CockroachDB cluster (typically 3 nodes). Multi-cloud deployments use one
7
+ * CockroachDbCluster per cloud, sharing joinAddresses across clouds.
8
+ */
9
+ import { Composite, mergeDefaults } from "@intentius/chant";
10
+ import { StatefulSet, Service, ServiceAccount, Role, RoleBinding, ClusterRole, ClusterRoleBinding, PodDisruptionBudget, Job } from "../generated/index.js";
11
+ /**
12
+ * Create a CockroachDbCluster composite — returns prop objects for a full
13
+ * CockroachDB StatefulSet deployment including RBAC, Services, PDB, and Jobs.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { CockroachDbCluster } from "@intentius/chant-lexicon-k8s";
18
+ *
19
+ * const crdb = CockroachDbCluster({
20
+ * name: "cockroachdb",
21
+ * namespace: "crdb",
22
+ * replicas: 3,
23
+ * locality: "cloud=aws,region=us-east-1",
24
+ * joinAddresses: [
25
+ * "cockroachdb-0.cockroachdb.crdb.svc.cluster.local",
26
+ * "cockroachdb-1.cockroachdb.crdb.svc.cluster.local",
27
+ * "cockroachdb-2.cockroachdb.crdb.svc.cluster.local",
28
+ * ],
29
+ * });
30
+ * ```
31
+ */
32
+ export const CockroachDbCluster = Composite((props) => {
33
+ const { name, namespace, replicas = 3, image = "cockroachdb/cockroach:v24.3.0", storageSize = "100Gi", storageClassName, cpuLimit = "2", memoryLimit = "8Gi", cachePercent = ".25", sqlMemoryPercent = ".25", locality, joinAddresses = [], secure = true, skipInit = false, skipCertGen = false, extraCertNodeAddresses = [], advertiseHostDomain, mountClientCerts = false, labels: extraLabels = {}, defaults: defs, } = props;
34
+ const saName = name;
35
+ const certsDir = "/cockroach/cockroach-certs";
36
+ const clientCertsDir = "/cockroach/cockroach-client-certs";
37
+ const dataDir = "/cockroach/cockroach-data";
38
+ const commonLabels = {
39
+ "app.kubernetes.io/name": name,
40
+ "app.kubernetes.io/managed-by": "chant",
41
+ ...extraLabels,
42
+ };
43
+ // -- RBAC --
44
+ const serviceAccount = new ServiceAccount(mergeDefaults({
45
+ metadata: {
46
+ name: saName,
47
+ ...(namespace && { namespace }),
48
+ labels: { ...commonLabels, "app.kubernetes.io/component": "database" },
49
+ },
50
+ }, defs?.serviceAccount));
51
+ const role = new Role(mergeDefaults({
52
+ metadata: {
53
+ name,
54
+ ...(namespace && { namespace }),
55
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
56
+ },
57
+ rules: [
58
+ { apiGroups: [""], resources: ["secrets"], verbs: ["get", "create", "update", "patch"] },
59
+ ],
60
+ }, defs?.role));
61
+ const roleBinding = new RoleBinding(mergeDefaults({
62
+ metadata: {
63
+ name,
64
+ ...(namespace && { namespace }),
65
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
66
+ },
67
+ roleRef: {
68
+ apiGroup: "rbac.authorization.k8s.io",
69
+ kind: "Role",
70
+ name,
71
+ },
72
+ subjects: [
73
+ { kind: "ServiceAccount", name: saName, ...(namespace && { namespace }) },
74
+ ],
75
+ }, defs?.roleBinding));
76
+ const clusterRole = new ClusterRole(mergeDefaults({
77
+ metadata: {
78
+ name,
79
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
80
+ },
81
+ rules: [
82
+ { apiGroups: ["certificates.k8s.io"], resources: ["certificatesigningrequests"], verbs: ["get", "create", "watch"] },
83
+ ],
84
+ }, defs?.clusterRole));
85
+ const clusterRoleBinding = new ClusterRoleBinding(mergeDefaults({
86
+ metadata: {
87
+ name,
88
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
89
+ },
90
+ roleRef: {
91
+ apiGroup: "rbac.authorization.k8s.io",
92
+ kind: "ClusterRole",
93
+ name,
94
+ },
95
+ subjects: [
96
+ { kind: "ServiceAccount", name: saName, ...(namespace && { namespace }) },
97
+ ],
98
+ }, defs?.clusterRoleBinding));
99
+ // -- Services --
100
+ const publicService = new Service(mergeDefaults({
101
+ metadata: {
102
+ name: `${name}-public`,
103
+ ...(namespace && { namespace }),
104
+ labels: { ...commonLabels, "app.kubernetes.io/component": "database" },
105
+ },
106
+ spec: {
107
+ selector: { "app.kubernetes.io/name": name },
108
+ ports: [
109
+ { port: 26257, targetPort: 26257, protocol: "TCP", name: "grpc" },
110
+ { port: 8080, targetPort: 8080, protocol: "TCP", name: "http" },
111
+ ],
112
+ type: "ClusterIP",
113
+ },
114
+ }, defs?.publicService));
115
+ const headlessService = new Service(mergeDefaults({
116
+ metadata: {
117
+ name,
118
+ ...(namespace && { namespace }),
119
+ labels: { ...commonLabels, "app.kubernetes.io/component": "database" },
120
+ annotations: {
121
+ "service.alpha.kubernetes.io/tolerate-unready-endpoints": "true",
122
+ },
123
+ },
124
+ spec: {
125
+ selector: { "app.kubernetes.io/name": name },
126
+ ports: [
127
+ { port: 26257, targetPort: 26257, protocol: "TCP", name: "grpc" },
128
+ { port: 8080, targetPort: 8080, protocol: "TCP", name: "http" },
129
+ ],
130
+ clusterIP: "None",
131
+ publishNotReadyAddresses: true,
132
+ },
133
+ }, defs?.headlessService));
134
+ // -- PodDisruptionBudget --
135
+ const pdb = new PodDisruptionBudget(mergeDefaults({
136
+ metadata: {
137
+ name,
138
+ ...(namespace && { namespace }),
139
+ labels: { ...commonLabels, "app.kubernetes.io/component": "disruption-budget" },
140
+ },
141
+ spec: {
142
+ maxUnavailable: 1,
143
+ selector: { matchLabels: { "app.kubernetes.io/name": name } },
144
+ },
145
+ }, defs?.pdb));
146
+ // -- StatefulSet --
147
+ // Build the cockroach start command as a shell string so that $(hostname -f)
148
+ // is expanded at runtime. K8s exec-form args do NOT invoke a shell, so
149
+ // $(...) substitutions are never evaluated unless we wrap with sh -c.
150
+ // When advertiseHostDomain is set, advertise the cross-cluster ExternalDNS name
151
+ // (e.g. "cockroachdb-0.east.crdb.internal") so gossip addresses are resolvable
152
+ // from other Kubernetes clusters. Otherwise fall back to the cluster-local FQDN.
153
+ const advertiseHostFlag = advertiseHostDomain
154
+ ? `--advertise-host=\${HOSTNAME}.${advertiseHostDomain}`
155
+ : `--advertise-host=$(hostname -f)`;
156
+ const cockroachFlags = [
157
+ `--logtostderr=WARNING`,
158
+ ...(secure ? [`--certs-dir=${certsDir}`] : ["--insecure"]),
159
+ advertiseHostFlag,
160
+ `--http-addr=0.0.0.0`,
161
+ `--cache=${cachePercent}`,
162
+ `--max-sql-memory=${sqlMemoryPercent}`,
163
+ ...(joinAddresses.length > 0 ? [`--join=${joinAddresses.join(",")}`] : []),
164
+ ...(locality ? [`--locality=${locality}`] : []),
165
+ ];
166
+ const cockroachStartCmd = `/cockroach/cockroach start ${cockroachFlags.join(" ")}`;
167
+ const volumes = [];
168
+ const volumeMounts = [
169
+ { name: "datadir", mountPath: dataDir },
170
+ ];
171
+ if (secure) {
172
+ volumes.push({ name: "certs", secret: { secretName: `${name}-node-certs`, defaultMode: 0o400 } });
173
+ volumeMounts.push({ name: "certs", mountPath: certsDir });
174
+ if (mountClientCerts) {
175
+ volumes.push({ name: "client-certs", secret: { secretName: `${name}-client-certs`, defaultMode: 0o400 } });
176
+ volumeMounts.push({ name: "client-certs", mountPath: clientCertsDir });
177
+ }
178
+ }
179
+ const container = {
180
+ name,
181
+ image,
182
+ ports: [
183
+ { containerPort: 26257, name: "grpc" },
184
+ { containerPort: 8080, name: "http" },
185
+ ],
186
+ command: ["/bin/sh", "-c"],
187
+ args: [cockroachStartCmd],
188
+ resources: {
189
+ limits: { cpu: cpuLimit, memory: memoryLimit },
190
+ requests: { cpu: cpuLimit, memory: memoryLimit },
191
+ },
192
+ volumeMounts,
193
+ env: [
194
+ { name: "COCKROACH_CHANNEL", value: "kubernetes-multiregion" },
195
+ ],
196
+ readinessProbe: {
197
+ httpGet: { path: "/health?ready=1", port: 8080, ...(secure && { scheme: "HTTPS" }) },
198
+ initialDelaySeconds: 10,
199
+ periodSeconds: 5,
200
+ failureThreshold: 2,
201
+ },
202
+ livenessProbe: {
203
+ httpGet: { path: "/health", port: 8080, ...(secure && { scheme: "HTTPS" }) },
204
+ initialDelaySeconds: 30,
205
+ periodSeconds: 5,
206
+ },
207
+ };
208
+ const statefulSet = new StatefulSet(mergeDefaults({
209
+ metadata: {
210
+ name,
211
+ ...(namespace && { namespace }),
212
+ labels: { ...commonLabels, "app.kubernetes.io/component": "database" },
213
+ },
214
+ spec: {
215
+ serviceName: name,
216
+ replicas,
217
+ podManagementPolicy: "Parallel",
218
+ selector: { matchLabels: { "app.kubernetes.io/name": name } },
219
+ template: {
220
+ metadata: { labels: { "app.kubernetes.io/name": name, ...extraLabels } },
221
+ spec: {
222
+ serviceAccountName: saName,
223
+ terminationGracePeriodSeconds: 60,
224
+ containers: [container],
225
+ ...(volumes.length > 0 && { volumes }),
226
+ affinity: {
227
+ podAntiAffinity: {
228
+ preferredDuringSchedulingIgnoredDuringExecution: [
229
+ {
230
+ weight: 100,
231
+ podAffinityTerm: {
232
+ labelSelector: { matchLabels: { "app.kubernetes.io/name": name } },
233
+ topologyKey: "kubernetes.io/hostname",
234
+ },
235
+ },
236
+ ],
237
+ },
238
+ },
239
+ },
240
+ },
241
+ volumeClaimTemplates: [
242
+ {
243
+ metadata: { name: "datadir" },
244
+ spec: {
245
+ accessModes: ["ReadWriteOnce"],
246
+ ...(storageClassName && { storageClassName }),
247
+ resources: { requests: { storage: storageSize } },
248
+ },
249
+ },
250
+ ],
251
+ },
252
+ }, defs?.statefulSet));
253
+ // -- cert-gen Job --
254
+ // Generates self-signed CA and node certs, stores them in K8s Secrets.
255
+ // Each node's cert includes the pod DNS names (pod-N.svc.namespace.svc.cluster.local).
256
+ // NOTE: The cert-gen Job uses `curl` to create K8s Secrets via the API server.
257
+ // CockroachDB UBI images (v24+) include curl. For multi-region deployments,
258
+ // use an external cert generation script instead (see generate-certs.sh).
259
+ const nodeNames = Array.from({ length: replicas }, (_, i) => `${name}-${i}.${name}`);
260
+ // Include both short names (for in-cluster init job) and FQDNs (for cross-namespace/init connections).
261
+ const nodeAddresses = namespace
262
+ ? [...nodeNames, ...nodeNames.map((n) => `${n}.${namespace}.svc.cluster.local`)]
263
+ : [...nodeNames, ...nodeNames.map((n) => `${n}.default.svc.cluster.local`)];
264
+ const ns = namespace ?? "default";
265
+ const nodeSecretName = `${name}-node-certs`;
266
+ const clientSecretName = `${name}-client-certs`;
267
+ const allCertNodeAddresses = [...nodeAddresses, ...extraCertNodeAddresses];
268
+ const certGenScript = [
269
+ "set -ex",
270
+ "cd /cockroach",
271
+ "cockroach cert create-ca --certs-dir=certs --ca-key=certs/ca.key",
272
+ `cockroach cert create-node ${allCertNodeAddresses.join(" ")} localhost 127.0.0.1 --certs-dir=certs --ca-key=certs/ca.key`,
273
+ "cockroach cert create-client root --certs-dir=certs --ca-key=certs/ca.key",
274
+ // Store certs in K8s Secrets via the API using the ServiceAccount token.
275
+ `TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)`,
276
+ `K8S_CA=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt`,
277
+ `API=https://kubernetes.default.svc`,
278
+ `NS=${ns}`,
279
+ `encode() { base64 | tr -d '\\n'; }`,
280
+ // Build JSON payloads for the two secrets.
281
+ `NODE_PAYLOAD=$(printf '{"apiVersion":"v1","kind":"Secret","metadata":{"name":"${nodeSecretName}","namespace":"%s"},"type":"Opaque","data":{"ca.crt":"%s","node.crt":"%s","node.key":"%s"}}' "$NS" "$(cat certs/ca.crt | encode)" "$(cat certs/node.crt | encode)" "$(cat certs/node.key | encode)")`,
282
+ `CLIENT_PAYLOAD=$(printf '{"apiVersion":"v1","kind":"Secret","metadata":{"name":"${clientSecretName}","namespace":"%s"},"type":"Opaque","data":{"ca.crt":"%s","client.root.crt":"%s","client.root.key":"%s"}}' "$NS" "$(cat certs/ca.crt | encode)" "$(cat certs/client.root.crt | encode)" "$(cat certs/client.root.key | encode)")`,
283
+ // Create or update each secret.
284
+ `for SECRET_INFO in "${nodeSecretName}:$NODE_PAYLOAD" "${clientSecretName}:$CLIENT_PAYLOAD"; do`,
285
+ ` SECRET_NAME=\${SECRET_INFO%%:*}`,
286
+ ` PAYLOAD=\${SECRET_INFO#*:}`,
287
+ ` STATUS=$(curl -s --cacert $K8S_CA -H "Authorization: Bearer $TOKEN" -o /dev/null -w '%{http_code}' $API/api/v1/namespaces/$NS/secrets/$SECRET_NAME)`,
288
+ ` if [ "$STATUS" = "200" ]; then`,
289
+ ` curl -sf --cacert $K8S_CA -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -X PUT $API/api/v1/namespaces/$NS/secrets/$SECRET_NAME -d "$PAYLOAD"`,
290
+ ` else`,
291
+ ` curl -sf --cacert $K8S_CA -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -X POST $API/api/v1/namespaces/$NS/secrets -d "$PAYLOAD"`,
292
+ ` fi`,
293
+ `done`,
294
+ ].join("\n");
295
+ const certGenJob = skipCertGen ? undefined : new Job(mergeDefaults({
296
+ metadata: {
297
+ name: `${name}-cert-gen`,
298
+ ...(namespace && { namespace }),
299
+ labels: { ...commonLabels, "app.kubernetes.io/component": "cert-gen" },
300
+ },
301
+ spec: {
302
+ backoffLimit: 3,
303
+ ttlSecondsAfterFinished: 3600,
304
+ template: {
305
+ metadata: { labels: { "app.kubernetes.io/name": name, ...extraLabels } },
306
+ spec: {
307
+ serviceAccountName: saName,
308
+ restartPolicy: "OnFailure",
309
+ containers: [
310
+ {
311
+ name: "cert-gen",
312
+ image,
313
+ command: ["bash", "-c", certGenScript],
314
+ },
315
+ ],
316
+ },
317
+ },
318
+ },
319
+ }, defs?.certGenJob));
320
+ // -- init Job (only when skipCertGen is false) --
321
+ const initArgs = secure
322
+ ? [`--certs-dir=${certsDir}`, `--host=${name}-0.${name}`]
323
+ : ["--insecure", `--host=${name}-0.${name}`];
324
+ const initVolumes = [];
325
+ const initVolumeMounts = [];
326
+ if (secure) {
327
+ initVolumes.push({ name: "client-certs", secret: { secretName: `${name}-client-certs`, defaultMode: 0o400 } });
328
+ initVolumeMounts.push({ name: "client-certs", mountPath: certsDir });
329
+ }
330
+ const initJob = skipInit ? undefined : new Job(mergeDefaults({
331
+ metadata: {
332
+ name: `${name}-init`,
333
+ ...(namespace && { namespace }),
334
+ labels: { ...commonLabels, "app.kubernetes.io/component": "init" },
335
+ },
336
+ spec: {
337
+ backoffLimit: 6,
338
+ ttlSecondsAfterFinished: 3600,
339
+ template: {
340
+ metadata: { labels: { "app.kubernetes.io/name": name, ...extraLabels } },
341
+ spec: {
342
+ serviceAccountName: saName,
343
+ restartPolicy: "OnFailure",
344
+ containers: [
345
+ {
346
+ name: "cluster-init",
347
+ image,
348
+ command: ["/cockroach/cockroach"],
349
+ args: ["init", ...initArgs],
350
+ ...(initVolumeMounts.length > 0 && { volumeMounts: initVolumeMounts }),
351
+ },
352
+ ],
353
+ ...(initVolumes.length > 0 && { volumes: initVolumes }),
354
+ },
355
+ },
356
+ },
357
+ }, defs?.initJob));
358
+ return {
359
+ serviceAccount,
360
+ role,
361
+ roleBinding,
362
+ clusterRole,
363
+ clusterRoleBinding,
364
+ publicService,
365
+ headlessService,
366
+ pdb,
367
+ statefulSet,
368
+ ...(initJob && { initJob }),
369
+ ...(certGenJob && { certGenJob }),
370
+ };
371
+ }, "CockroachDbCluster");