@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,152 @@
1
+ /**
2
+ * MonitoredService composite — Deployment + Service + ServiceMonitor + optional PrometheusRule.
3
+ *
4
+ * Observability pattern. ServiceMonitor and PrometheusRule are CRDs
5
+ * from the Prometheus Operator (monitoring.coreos.com/v1), returned
6
+ * as raw objects that can be serialized alongside native K8s resources.
7
+ *
8
+ * Rules come in two forms. `ruleGroups` takes `RuleGroup`s from the
9
+ * prometheus lexicon (`@intentius/chant-lexicon-prometheus`), typed and
10
+ * checked there, and rendered here exactly as they would be in a rule file.
11
+ * `alertRules` is the older shorthand for one group of alerts and still works.
12
+ */
13
+ import { Composite, mergeDefaults } from "@intentius/chant";
14
+ import { ruleGroupConfig } from "@intentius/chant-lexicon-prometheus";
15
+ import { Deployment, Service, ServiceMonitor, PrometheusRule } from "../generated/index.js";
16
+ /**
17
+ * Create a MonitoredService composite — returns prop objects for
18
+ * a Deployment, Service, ServiceMonitor, and optional PrometheusRule.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * import { MonitoredService } from "@intentius/chant-lexicon-k8s";
23
+ *
24
+ * const { deployment, service, serviceMonitor, prometheusRule } = MonitoredService({
25
+ * name: "api",
26
+ * image: "api:1.0",
27
+ * port: 8080,
28
+ * metricsPort: 9090,
29
+ * alertRules: [
30
+ * { name: "HighErrorRate", expr: 'rate(http_errors_total[5m]) > 0.1', for: "5m", severity: "critical" },
31
+ * ],
32
+ * });
33
+ *
34
+ * // Or with typed rule groups from the prometheus lexicon:
35
+ * import { RuleGroup } from "@intentius/chant-lexicon-prometheus";
36
+ * const apiRules = new RuleGroup({
37
+ * name: "api",
38
+ * rules: [{ alert: "ApiDown", expr: 'up{job="api"} == 0', for: "5m", labels: { severity: "page" } }],
39
+ * });
40
+ * MonitoredService({ name: "api", image: "api:1.0", ruleGroups: [apiRules] });
41
+ * ```
42
+ */
43
+ export const MonitoredService = Composite((props) => {
44
+ const { name, image, port = 80, metricsPort = 9090, metricsPath = "/metrics", scrapeInterval = "30s", alertRules, ruleGroups, replicas = 2, labels: extraLabels = {}, cpuLimit = "500m", memoryLimit = "256Mi", cpuRequest = "100m", memoryRequest = "128Mi", namespace, env, securityContext, defaults: defs, } = props;
45
+ const commonLabels = {
46
+ "app.kubernetes.io/name": name,
47
+ "app.kubernetes.io/managed-by": "chant",
48
+ ...extraLabels,
49
+ };
50
+ const ports = [
51
+ { containerPort: port, name: "http" },
52
+ ];
53
+ if (metricsPort !== port) {
54
+ ports.push({ containerPort: metricsPort, name: "metrics" });
55
+ }
56
+ const deployment = new Deployment(mergeDefaults({
57
+ metadata: {
58
+ name,
59
+ ...(namespace && { namespace }),
60
+ labels: { ...commonLabels, "app.kubernetes.io/component": "server" },
61
+ },
62
+ spec: {
63
+ replicas,
64
+ selector: { matchLabels: { "app.kubernetes.io/name": name } },
65
+ template: {
66
+ metadata: { labels: { "app.kubernetes.io/name": name, ...extraLabels } },
67
+ spec: {
68
+ containers: [
69
+ {
70
+ name,
71
+ image,
72
+ ports,
73
+ resources: {
74
+ limits: { cpu: cpuLimit, memory: memoryLimit },
75
+ requests: { cpu: cpuRequest, memory: memoryRequest },
76
+ },
77
+ ...(env && { env }),
78
+ ...(securityContext && { securityContext }),
79
+ },
80
+ ],
81
+ },
82
+ },
83
+ },
84
+ }, defs?.deployment));
85
+ const servicePorts = [
86
+ { port: 80, targetPort: port, protocol: "TCP", name: "http" },
87
+ ];
88
+ if (metricsPort !== port) {
89
+ servicePorts.push({ port: metricsPort, targetPort: metricsPort, protocol: "TCP", name: "metrics" });
90
+ }
91
+ const service = new Service(mergeDefaults({
92
+ metadata: {
93
+ name,
94
+ ...(namespace && { namespace }),
95
+ labels: { ...commonLabels, "app.kubernetes.io/component": "server" },
96
+ },
97
+ spec: {
98
+ selector: { "app.kubernetes.io/name": name },
99
+ ports: servicePorts,
100
+ type: "ClusterIP",
101
+ },
102
+ }, defs?.service));
103
+ const serviceMonitor = new ServiceMonitor(mergeDefaults({
104
+ metadata: {
105
+ name,
106
+ ...(namespace && { namespace }),
107
+ labels: { ...commonLabels, "app.kubernetes.io/component": "monitoring" },
108
+ },
109
+ spec: {
110
+ selector: {
111
+ matchLabels: { "app.kubernetes.io/name": name },
112
+ },
113
+ endpoints: [
114
+ {
115
+ port: "metrics",
116
+ path: metricsPath,
117
+ interval: scrapeInterval,
118
+ },
119
+ ],
120
+ },
121
+ }, defs?.serviceMonitor));
122
+ const result = { deployment, service, serviceMonitor };
123
+ const groups = [];
124
+ if (alertRules && alertRules.length > 0) {
125
+ groups.push({
126
+ name: `${name}.rules`,
127
+ rules: alertRules.map((rule) => ({
128
+ alert: rule.name,
129
+ expr: rule.expr,
130
+ ...(rule.for && { for: rule.for }),
131
+ labels: {
132
+ ...(rule.severity && { severity: rule.severity }),
133
+ },
134
+ ...(rule.annotations && { annotations: rule.annotations }),
135
+ })),
136
+ });
137
+ }
138
+ for (const group of ruleGroups ?? []) {
139
+ groups.push(ruleGroupConfig(group));
140
+ }
141
+ if (groups.length > 0) {
142
+ result.prometheusRule = new PrometheusRule(mergeDefaults({
143
+ metadata: {
144
+ name: `${name}-alerts`,
145
+ ...(namespace && { namespace }),
146
+ labels: { ...commonLabels, "app.kubernetes.io/component": "monitoring" },
147
+ },
148
+ spec: { groups },
149
+ }, defs?.prometheusRule));
150
+ }
151
+ return result;
152
+ }, "MonitoredService");
@@ -0,0 +1,114 @@
1
+ /**
2
+ * NamespaceEnv composite — Namespace + optional ResourceQuota + LimitRange + NetworkPolicy.
3
+ *
4
+ * A higher-level construct for multi-tenant namespace provisioning with
5
+ * resource guardrails and network isolation.
6
+ */
7
+ import { Composite, mergeDefaults } from "@intentius/chant";
8
+ import { Namespace, ResourceQuota, LimitRange, NetworkPolicy } from "../generated/index.js";
9
+ /**
10
+ * Create a NamespaceEnv composite — returns prop objects for
11
+ * a Namespace, optional ResourceQuota, LimitRange, and NetworkPolicy.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { NamespaceEnv } from "@intentius/chant-lexicon-k8s";
16
+ *
17
+ * const { namespace, resourceQuota, limitRange, networkPolicy } = NamespaceEnv({
18
+ * name: "team-alpha",
19
+ * cpuQuota: "8",
20
+ * memoryQuota: "16Gi",
21
+ * defaultCpuRequest: "100m",
22
+ * defaultMemoryRequest: "128Mi",
23
+ * defaultDenyIngress: true,
24
+ * });
25
+ * ```
26
+ */
27
+ export const NamespaceEnv = Composite((props) => {
28
+ const { name, cpuQuota, memoryQuota, maxPods, defaultCpuRequest, defaultMemoryRequest, defaultCpuLimit, defaultMemoryLimit, defaultDenyIngress = true, defaultDenyEgress = false, labels: extraLabels = {}, defaults: defs, } = props;
29
+ const commonLabels = {
30
+ "app.kubernetes.io/name": name,
31
+ "app.kubernetes.io/managed-by": "chant",
32
+ ...extraLabels,
33
+ };
34
+ const namespace = new Namespace(mergeDefaults({
35
+ metadata: {
36
+ name,
37
+ labels: { ...commonLabels, "app.kubernetes.io/component": "namespace" },
38
+ },
39
+ }, defs?.namespace));
40
+ const result = { namespace };
41
+ // ResourceQuota — only if at least one quota prop is set
42
+ const hasQuota = cpuQuota || memoryQuota || maxPods !== undefined;
43
+ if (hasQuota) {
44
+ const hard = {};
45
+ if (cpuQuota)
46
+ hard["limits.cpu"] = cpuQuota;
47
+ if (memoryQuota)
48
+ hard["limits.memory"] = memoryQuota;
49
+ if (maxPods !== undefined)
50
+ hard.pods = String(maxPods);
51
+ result.resourceQuota = new ResourceQuota(mergeDefaults({
52
+ metadata: {
53
+ name: `${name}-quota`,
54
+ namespace: name,
55
+ labels: { ...commonLabels, "app.kubernetes.io/component": "quota" },
56
+ },
57
+ spec: { hard },
58
+ }, defs?.resourceQuota));
59
+ }
60
+ // LimitRange — only if at least one default limit prop is set
61
+ const hasLimits = defaultCpuRequest || defaultMemoryRequest || defaultCpuLimit || defaultMemoryLimit;
62
+ if (hasQuota && !hasLimits) {
63
+ console.warn(`[NamespaceEnv] "${name}": ResourceQuota set but no LimitRange defaults. ` +
64
+ `Pods without explicit resource requests will fail to schedule.`);
65
+ }
66
+ if (hasLimits) {
67
+ const defaultLimits = {};
68
+ const defaultRequests = {};
69
+ if (defaultCpuLimit)
70
+ defaultLimits.cpu = defaultCpuLimit;
71
+ if (defaultMemoryLimit)
72
+ defaultLimits.memory = defaultMemoryLimit;
73
+ if (defaultCpuRequest)
74
+ defaultRequests.cpu = defaultCpuRequest;
75
+ if (defaultMemoryRequest)
76
+ defaultRequests.memory = defaultMemoryRequest;
77
+ const limit = { type: "Container" };
78
+ if (Object.keys(defaultLimits).length > 0)
79
+ limit.default = defaultLimits;
80
+ if (Object.keys(defaultRequests).length > 0)
81
+ limit.defaultRequest = defaultRequests;
82
+ result.limitRange = new LimitRange(mergeDefaults({
83
+ metadata: {
84
+ name: `${name}-limits`,
85
+ namespace: name,
86
+ labels: { ...commonLabels, "app.kubernetes.io/component": "limits" },
87
+ },
88
+ spec: {
89
+ limits: [limit],
90
+ },
91
+ }, defs?.limitRange));
92
+ }
93
+ // NetworkPolicy — default-deny ingress and/or egress
94
+ const hasNetworkPolicy = defaultDenyIngress || defaultDenyEgress;
95
+ if (hasNetworkPolicy) {
96
+ const policyTypes = [];
97
+ if (defaultDenyIngress)
98
+ policyTypes.push("Ingress");
99
+ if (defaultDenyEgress)
100
+ policyTypes.push("Egress");
101
+ result.networkPolicy = new NetworkPolicy(mergeDefaults({
102
+ metadata: {
103
+ name: `${name}-default-deny`,
104
+ namespace: name,
105
+ labels: { ...commonLabels, "app.kubernetes.io/component": "network-policy" },
106
+ },
107
+ spec: {
108
+ podSelector: {},
109
+ policyTypes,
110
+ },
111
+ }, defs?.networkPolicy));
112
+ }
113
+ return result;
114
+ }, "NamespaceEnv");
@@ -0,0 +1,124 @@
1
+ /**
2
+ * NetworkIsolatedApp composite — Deployment + Service + NetworkPolicy.
3
+ *
4
+ * Per-app allow rules beyond NamespaceEnv's default-deny.
5
+ * Creates fine-grained ingress/egress policies for a single application.
6
+ */
7
+ import { Composite, mergeDefaults } from "@intentius/chant";
8
+ import { Deployment, Service, NetworkPolicy } from "../generated/index.js";
9
+ /**
10
+ * Create a NetworkIsolatedApp composite — returns prop objects for
11
+ * a Deployment, Service, and NetworkPolicy.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { NetworkIsolatedApp } from "@intentius/chant-lexicon-k8s";
16
+ *
17
+ * const { deployment, service, networkPolicy } = NetworkIsolatedApp({
18
+ * name: "api",
19
+ * image: "api:1.0",
20
+ * port: 8080,
21
+ * allowIngressFrom: [
22
+ * { podSelector: { "app.kubernetes.io/name": "frontend" } },
23
+ * ],
24
+ * allowEgressTo: [
25
+ * { podSelector: { "app.kubernetes.io/name": "postgres" }, ports: [{ port: 5432 }] },
26
+ * ],
27
+ * });
28
+ * ```
29
+ */
30
+ export const NetworkIsolatedApp = Composite((props) => {
31
+ const { name, image, port = 80, replicas = 2, allowIngressFrom, allowEgressTo, labels: extraLabels = {}, cpuLimit = "500m", memoryLimit = "256Mi", cpuRequest = "100m", memoryRequest = "128Mi", namespace, env, securityContext, defaults: defs, } = props;
32
+ const commonLabels = {
33
+ "app.kubernetes.io/name": name,
34
+ "app.kubernetes.io/managed-by": "chant",
35
+ ...extraLabels,
36
+ };
37
+ const deployment = new Deployment(mergeDefaults({
38
+ metadata: {
39
+ name,
40
+ ...(namespace && { namespace }),
41
+ labels: { ...commonLabels, "app.kubernetes.io/component": "server" },
42
+ },
43
+ spec: {
44
+ replicas,
45
+ selector: { matchLabels: { "app.kubernetes.io/name": name } },
46
+ template: {
47
+ metadata: { labels: { "app.kubernetes.io/name": name, ...extraLabels } },
48
+ spec: {
49
+ containers: [
50
+ {
51
+ name,
52
+ image,
53
+ ports: [{ containerPort: port, name: "http" }],
54
+ resources: {
55
+ limits: { cpu: cpuLimit, memory: memoryLimit },
56
+ requests: { cpu: cpuRequest, memory: memoryRequest },
57
+ },
58
+ ...(env && { env }),
59
+ ...(securityContext && { securityContext }),
60
+ },
61
+ ],
62
+ },
63
+ },
64
+ },
65
+ }, defs?.deployment));
66
+ const service = new Service(mergeDefaults({
67
+ metadata: {
68
+ name,
69
+ ...(namespace && { namespace }),
70
+ labels: { ...commonLabels, "app.kubernetes.io/component": "server" },
71
+ },
72
+ spec: {
73
+ selector: { "app.kubernetes.io/name": name },
74
+ ports: [{ port: 80, targetPort: port, protocol: "TCP", name: "http" }],
75
+ type: "ClusterIP",
76
+ },
77
+ }, defs?.service));
78
+ // Build network policy
79
+ const policyTypes = [];
80
+ const policySpec = {
81
+ podSelector: { matchLabels: { "app.kubernetes.io/name": name } },
82
+ };
83
+ if (allowIngressFrom) {
84
+ policyTypes.push("Ingress");
85
+ policySpec.ingress = [
86
+ {
87
+ from: allowIngressFrom.map((peer) => ({
88
+ ...(peer.podSelector && { podSelector: { matchLabels: peer.podSelector } }),
89
+ ...(peer.namespaceSelector && { namespaceSelector: { matchLabels: peer.namespaceSelector } }),
90
+ })),
91
+ ports: [{ port, protocol: "TCP" }],
92
+ },
93
+ ];
94
+ }
95
+ if (allowEgressTo) {
96
+ policyTypes.push("Egress");
97
+ policySpec.egress = allowEgressTo.map((peer) => ({
98
+ to: [
99
+ {
100
+ ...(peer.podSelector && { podSelector: { matchLabels: peer.podSelector } }),
101
+ ...(peer.namespaceSelector && { namespaceSelector: { matchLabels: peer.namespaceSelector } }),
102
+ },
103
+ ],
104
+ ...(peer.ports && {
105
+ ports: peer.ports.map((p) => ({
106
+ port: p.port,
107
+ protocol: p.protocol ?? "TCP",
108
+ })),
109
+ }),
110
+ }));
111
+ }
112
+ if (policyTypes.length > 0) {
113
+ policySpec.policyTypes = policyTypes;
114
+ }
115
+ const networkPolicy = new NetworkPolicy(mergeDefaults({
116
+ metadata: {
117
+ name: `${name}-policy`,
118
+ ...(namespace && { namespace }),
119
+ labels: { ...commonLabels, "app.kubernetes.io/component": "network-policy" },
120
+ },
121
+ spec: policySpec,
122
+ }, defs?.networkPolicy));
123
+ return { deployment, service, networkPolicy };
124
+ }, "NetworkIsolatedApp");
@@ -0,0 +1,149 @@
1
+ /**
2
+ * NodeAgent composite — DaemonSet + ServiceAccount + ClusterRole + ClusterRoleBinding + optional ConfigMap.
3
+ *
4
+ * A higher-level construct for per-node agents (Fluentd, Prometheus Node Exporter,
5
+ * security scanners) that need cluster-wide RBAC and tolerations.
6
+ */
7
+ import { Composite, mergeDefaults } from "@intentius/chant";
8
+ import { DaemonSet, ServiceAccount, ClusterRole, ClusterRoleBinding, ConfigMap } from "../generated/index.js";
9
+ /**
10
+ * Create a NodeAgent composite — returns prop objects for
11
+ * a DaemonSet, ServiceAccount, ClusterRole, ClusterRoleBinding, and optional ConfigMap.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { NodeAgent } from "@intentius/chant-lexicon-k8s";
16
+ *
17
+ * const { daemonSet, serviceAccount, clusterRole, clusterRoleBinding } = NodeAgent({
18
+ * name: "log-collector",
19
+ * image: "fluentd:v1.16",
20
+ * hostPaths: [{ name: "varlog", hostPath: "/var/log", mountPath: "/var/log" }],
21
+ * rbacRules: [
22
+ * { apiGroups: [""], resources: ["pods", "namespaces"], verbs: ["get", "list", "watch"] },
23
+ * ],
24
+ * });
25
+ * ```
26
+ */
27
+ export const NodeAgent = Composite((props) => {
28
+ const { name, image, port, hostPaths = [], config, rbacRules, tolerateAllTaints = true, namespace, cpuRequest = "50m", memoryRequest = "64Mi", cpuLimit = "200m", memoryLimit = "128Mi", labels: extraLabels = {}, env, securityContext, defaults: defs, } = props;
29
+ const saName = `${name}-sa`;
30
+ const clusterRoleName = `${name}-role`;
31
+ const bindingName = `${name}-binding`;
32
+ const configMapName = `${name}-config`;
33
+ const commonLabels = {
34
+ "app.kubernetes.io/name": name,
35
+ "app.kubernetes.io/managed-by": "chant",
36
+ ...extraLabels,
37
+ };
38
+ // Build volumes and volumeMounts from hostPaths
39
+ const volumes = [];
40
+ const volumeMounts = [];
41
+ for (const hp of hostPaths) {
42
+ volumes.push({
43
+ name: hp.name,
44
+ hostPath: { path: hp.hostPath },
45
+ });
46
+ volumeMounts.push({
47
+ name: hp.name,
48
+ mountPath: hp.mountPath,
49
+ readOnly: hp.readOnly !== false,
50
+ });
51
+ }
52
+ // ConfigMap volume
53
+ if (config) {
54
+ volumes.push({
55
+ name: "config",
56
+ configMap: { name: configMapName },
57
+ });
58
+ volumeMounts.push({
59
+ name: "config",
60
+ mountPath: `/etc/${name}`,
61
+ readOnly: true,
62
+ });
63
+ }
64
+ const container = {
65
+ name,
66
+ image,
67
+ ...(port && { ports: [{ containerPort: port, name: "metrics" }] }),
68
+ resources: {
69
+ requests: { cpu: cpuRequest, memory: memoryRequest },
70
+ limits: { cpu: cpuLimit, memory: memoryLimit },
71
+ },
72
+ ...(env && { env }),
73
+ ...(volumeMounts.length > 0 && { volumeMounts }),
74
+ ...(securityContext && { securityContext }),
75
+ };
76
+ const podSpec = {
77
+ serviceAccountName: saName,
78
+ containers: [container],
79
+ ...(volumes.length > 0 && { volumes }),
80
+ ...(tolerateAllTaints && {
81
+ tolerations: [{ operator: "Exists" }],
82
+ }),
83
+ };
84
+ const daemonSet = new DaemonSet(mergeDefaults({
85
+ metadata: {
86
+ name,
87
+ ...(namespace && { namespace }),
88
+ labels: { ...commonLabels, "app.kubernetes.io/component": "agent" },
89
+ },
90
+ spec: {
91
+ selector: { matchLabels: { "app.kubernetes.io/name": name } },
92
+ template: {
93
+ metadata: { labels: { "app.kubernetes.io/name": name, ...extraLabels } },
94
+ spec: podSpec,
95
+ },
96
+ },
97
+ }, defs?.daemonSet));
98
+ const serviceAccount = new ServiceAccount(mergeDefaults({
99
+ metadata: {
100
+ name: saName,
101
+ ...(namespace && { namespace }),
102
+ labels: { ...commonLabels, "app.kubernetes.io/component": "agent" },
103
+ },
104
+ }, defs?.serviceAccount));
105
+ // ClusterRole — cluster-scoped, no namespace
106
+ const clusterRole = new ClusterRole(mergeDefaults({
107
+ metadata: {
108
+ name: clusterRoleName,
109
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
110
+ },
111
+ rules: rbacRules,
112
+ }, defs?.clusterRole));
113
+ // ClusterRoleBinding — cluster-scoped, no namespace
114
+ const clusterRoleBinding = new ClusterRoleBinding(mergeDefaults({
115
+ metadata: {
116
+ name: bindingName,
117
+ labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
118
+ },
119
+ roleRef: {
120
+ apiGroup: "rbac.authorization.k8s.io",
121
+ kind: "ClusterRole",
122
+ name: clusterRoleName,
123
+ },
124
+ subjects: [
125
+ {
126
+ kind: "ServiceAccount",
127
+ name: saName,
128
+ ...(namespace && { namespace }),
129
+ },
130
+ ],
131
+ }, defs?.clusterRoleBinding));
132
+ const result = {
133
+ daemonSet,
134
+ serviceAccount,
135
+ clusterRole,
136
+ clusterRoleBinding,
137
+ };
138
+ if (config) {
139
+ result.configMap = new ConfigMap(mergeDefaults({
140
+ metadata: {
141
+ name: configMapName,
142
+ ...(namespace && { namespace }),
143
+ labels: { ...commonLabels, "app.kubernetes.io/component": "config" },
144
+ },
145
+ data: config,
146
+ }, defs?.configMap));
147
+ }
148
+ return result;
149
+ }, "NodeAgent");