@intentius/chant-lexicon-helm 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.
- package/dist/archive-render.js +76 -0
- package/dist/codegen/docs-cli.js +3 -0
- package/dist/codegen/docs.js +113 -0
- package/dist/codegen/generate-cli.js +19 -0
- package/dist/codegen/generate.js +210 -0
- package/dist/codegen/naming.js +29 -0
- package/dist/codegen/package.js +44 -0
- package/dist/codegen/values-type.js +87 -0
- package/dist/commands.js +413 -0
- package/dist/components/builders.js +9 -0
- package/dist/components/capability-plugin.js +17 -0
- package/dist/components/helm-upgrade.js +109 -0
- package/dist/components/index.js +11 -0
- package/dist/composites/catalog.js +1119 -0
- package/dist/composites/helm-batch-job.js +148 -0
- package/dist/composites/helm-crd-lifecycle.js +145 -0
- package/dist/composites/helm-cron-job.js +130 -0
- package/dist/composites/helm-daemon-set.js +125 -0
- package/dist/composites/helm-external-secret.js +63 -0
- package/dist/composites/helm-library.js +24 -0
- package/dist/composites/helm-microservice.js +260 -0
- package/dist/composites/helm-monitored-service.js +188 -0
- package/dist/composites/helm-namespace-env.js +116 -0
- package/dist/composites/helm-secure-ingress.js +86 -0
- package/dist/composites/helm-stateful-service.js +160 -0
- package/dist/composites/helm-web-app.js +201 -0
- package/dist/composites/helm-worker.js +164 -0
- package/dist/composites/index.js +13 -0
- package/dist/config.js +161 -0
- package/dist/coverage.js +37 -0
- package/dist/deep-observe-hooks.js +19 -0
- package/dist/deep-observe.js +55 -0
- package/dist/describe-resources.js +119 -0
- package/dist/describe-stack-status.js +66 -0
- package/dist/detect.js +11 -0
- package/dist/generated/index.js +11 -0
- package/dist/helpers.js +84 -0
- package/dist/import/generator.js +292 -0
- package/dist/import/parser.js +141 -0
- package/dist/import/template-stripper.js +86 -0
- package/dist/index.js +55 -0
- package/dist/integrity.json +2 -2
- package/dist/intrinsics.js +482 -0
- package/dist/lint/audit-catalog.js +33 -0
- package/dist/lint/audit-lineage.js +53 -0
- package/dist/lint/post-synth/helm-helpers.js +60 -0
- package/dist/lint/post-synth/index.js +48 -0
- package/dist/lint/post-synth/whm005-no-empty-wrapper.js +47 -0
- package/dist/lint/post-synth/whm101.js +38 -0
- package/dist/lint/post-synth/whm102.js +26 -0
- package/dist/lint/post-synth/whm103.js +51 -0
- package/dist/lint/post-synth/whm104.js +29 -0
- package/dist/lint/post-synth/whm105.js +23 -0
- package/dist/lint/post-synth/whm201.js +29 -0
- package/dist/lint/post-synth/whm202.js +42 -0
- package/dist/lint/post-synth/whm203.js +32 -0
- package/dist/lint/post-synth/whm204.js +51 -0
- package/dist/lint/post-synth/whm301.js +31 -0
- package/dist/lint/post-synth/whm302.js +33 -0
- package/dist/lint/post-synth/whm401.js +52 -0
- package/dist/lint/post-synth/whm402.js +38 -0
- package/dist/lint/post-synth/whm403.js +38 -0
- package/dist/lint/post-synth/whm404.js +30 -0
- package/dist/lint/post-synth/whm405.js +47 -0
- package/dist/lint/post-synth/whm406.js +27 -0
- package/dist/lint/post-synth/whm407.js +72 -0
- package/dist/lint/post-synth/whm501.js +89 -0
- package/dist/lint/post-synth/whm502.js +85 -0
- package/dist/lint/post-synth/whm503.js +82 -0
- package/dist/lint/post-synth/whm504.js +47 -0
- package/dist/lint/rules/chart-metadata.js +53 -0
- package/dist/lint/rules/no-hardcoded-image.js +50 -0
- package/dist/lint/rules/values-no-helm-tpl.js +78 -0
- package/dist/lint/rules/values-no-secrets.js +65 -0
- package/dist/list-artifacts.js +134 -0
- package/dist/lsp/completions.d.ts.map +1 -1
- package/dist/lsp/completions.js +18 -0
- package/dist/lsp/hover.d.ts.map +1 -1
- package/dist/lsp/hover.js +40 -0
- package/dist/manifest.json +1 -1
- package/dist/op/activities/cluster-probe.js +116 -0
- package/dist/op/activities/helm.js +449 -0
- package/dist/op/activities/index.js +10 -0
- package/dist/op/builders.js +45 -0
- package/dist/package-cli.js +21 -0
- package/dist/pinnability/actions.js +207 -0
- package/dist/pinnability/classify.js +416 -0
- package/dist/pinnability/conditions.js +0 -0
- package/dist/pinnability/index.js +16 -0
- package/dist/pinnability/localize.js +518 -0
- package/dist/pinnability/render-stream.js +53 -0
- package/dist/pinnability/values.js +151 -0
- package/dist/plugin.js +458 -0
- package/dist/project-codegen.js +215 -0
- package/dist/release-observe.js +287 -0
- package/dist/render-diff.js +279 -0
- package/dist/render-digest.js +0 -0
- package/dist/render-records.js +29 -0
- package/dist/render-store.js +401 -0
- package/dist/render-wrapper.js +164 -0
- package/dist/render.js +394 -0
- package/dist/resources.js +109 -0
- package/dist/serializer.js +903 -0
- package/dist/validate-cli.js +17 -0
- package/dist/validate.js +30 -0
- package/dist/values-probe.js +504 -0
- package/dist/wrapper-chart.js +95 -0
- package/package.json +11 -11
- package/src/codegen/package.ts +2 -2
- package/src/lsp/completions.ts +2 -1
- package/src/lsp/hover.ts +2 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HelmBatchJob composite — Job + optional ServiceAccount + RBAC.
|
|
3
|
+
*
|
|
4
|
+
* One-shot batch job pattern with optional RBAC for jobs that need
|
|
5
|
+
* Kubernetes API access (e.g., data migrations, cluster operations).
|
|
6
|
+
*/
|
|
7
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
8
|
+
import { Chart, Values, Job, ServiceAccount, Role, RoleBinding } from "../resources.js";
|
|
9
|
+
import { values, include, printf, toYaml, With } from "../intrinsics.js";
|
|
10
|
+
export const HelmBatchJob = Composite((props) => {
|
|
11
|
+
const { name, imageRepository = "busybox", imageTag = "latest", backoffLimit = 6, completions = 1, parallelism = 1, restartPolicy = "OnFailure", serviceAccount = true, rbac = false, appVersion = "1.0.0", defaults: defs, } = props;
|
|
12
|
+
const chart = new Chart(mergeDefaults({
|
|
13
|
+
apiVersion: "v2",
|
|
14
|
+
name,
|
|
15
|
+
version: "0.1.0",
|
|
16
|
+
appVersion,
|
|
17
|
+
type: "application",
|
|
18
|
+
description: `A Helm chart for ${name} batch job`,
|
|
19
|
+
}, defs?.chart));
|
|
20
|
+
const valuesObj = {
|
|
21
|
+
image: {
|
|
22
|
+
repository: imageRepository,
|
|
23
|
+
tag: imageTag,
|
|
24
|
+
pullPolicy: "IfNotPresent",
|
|
25
|
+
},
|
|
26
|
+
job: {
|
|
27
|
+
backoffLimit,
|
|
28
|
+
completions,
|
|
29
|
+
parallelism,
|
|
30
|
+
},
|
|
31
|
+
restartPolicy,
|
|
32
|
+
command: [],
|
|
33
|
+
args: [],
|
|
34
|
+
resources: {},
|
|
35
|
+
};
|
|
36
|
+
if (props.ttlSecondsAfterFinished !== undefined) {
|
|
37
|
+
valuesObj.job.ttlSecondsAfterFinished = props.ttlSecondsAfterFinished;
|
|
38
|
+
}
|
|
39
|
+
if (props.podSecurityContext)
|
|
40
|
+
valuesObj.podSecurityContext = props.podSecurityContext;
|
|
41
|
+
if (props.securityContext)
|
|
42
|
+
valuesObj.securityContext = props.securityContext;
|
|
43
|
+
if (props.nodeSelector)
|
|
44
|
+
valuesObj.nodeSelector = props.nodeSelector;
|
|
45
|
+
if (props.tolerations)
|
|
46
|
+
valuesObj.tolerations = props.tolerations;
|
|
47
|
+
if (serviceAccount) {
|
|
48
|
+
valuesObj.serviceAccount = {
|
|
49
|
+
create: true,
|
|
50
|
+
name: "",
|
|
51
|
+
annotations: {},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (rbac) {
|
|
55
|
+
valuesObj.rbac = {
|
|
56
|
+
create: true,
|
|
57
|
+
rules: [],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const valuesRes = new Values(mergeDefaults(valuesObj, defs?.values));
|
|
61
|
+
const containerSpec = {
|
|
62
|
+
name,
|
|
63
|
+
image: printf("%s:%s", values.image.repository, values.image.tag),
|
|
64
|
+
imagePullPolicy: values.image.pullPolicy,
|
|
65
|
+
command: values.command,
|
|
66
|
+
args: values.args,
|
|
67
|
+
resources: toYaml(values.resources),
|
|
68
|
+
};
|
|
69
|
+
if (props.securityContext)
|
|
70
|
+
containerSpec.securityContext = toYaml(values.securityContext);
|
|
71
|
+
const podSpec = {
|
|
72
|
+
restartPolicy: values.restartPolicy,
|
|
73
|
+
containers: [containerSpec],
|
|
74
|
+
};
|
|
75
|
+
if (props.podSecurityContext)
|
|
76
|
+
podSpec.securityContext = toYaml(values.podSecurityContext);
|
|
77
|
+
if (props.nodeSelector)
|
|
78
|
+
podSpec.nodeSelector = With(values.nodeSelector, toYaml(values.nodeSelector));
|
|
79
|
+
if (props.tolerations)
|
|
80
|
+
podSpec.tolerations = With(values.tolerations, toYaml(values.tolerations));
|
|
81
|
+
if (serviceAccount)
|
|
82
|
+
podSpec.serviceAccountName = include(`${name}.serviceAccountName`);
|
|
83
|
+
const jobSpec = {
|
|
84
|
+
backoffLimit: values.job.backoffLimit,
|
|
85
|
+
completions: values.job.completions,
|
|
86
|
+
parallelism: values.job.parallelism,
|
|
87
|
+
template: {
|
|
88
|
+
metadata: {
|
|
89
|
+
labels: include(`${name}.selectorLabels`),
|
|
90
|
+
},
|
|
91
|
+
spec: podSpec,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
if (props.ttlSecondsAfterFinished !== undefined) {
|
|
95
|
+
jobSpec.ttlSecondsAfterFinished = values.job.ttlSecondsAfterFinished;
|
|
96
|
+
}
|
|
97
|
+
const job = new Job(mergeDefaults({
|
|
98
|
+
apiVersion: "batch/v1",
|
|
99
|
+
kind: "Job",
|
|
100
|
+
metadata: {
|
|
101
|
+
name: include(`${name}.fullname`),
|
|
102
|
+
labels: include(`${name}.labels`),
|
|
103
|
+
},
|
|
104
|
+
spec: jobSpec,
|
|
105
|
+
}, defs?.job));
|
|
106
|
+
const result = { chart, values: valuesRes, job };
|
|
107
|
+
if (serviceAccount) {
|
|
108
|
+
result.serviceAccount = new ServiceAccount(mergeDefaults({
|
|
109
|
+
apiVersion: "v1",
|
|
110
|
+
kind: "ServiceAccount",
|
|
111
|
+
metadata: {
|
|
112
|
+
name: include(`${name}.serviceAccountName`),
|
|
113
|
+
labels: include(`${name}.labels`),
|
|
114
|
+
annotations: toYaml(values.serviceAccount.annotations),
|
|
115
|
+
},
|
|
116
|
+
}, defs?.serviceAccount));
|
|
117
|
+
}
|
|
118
|
+
if (rbac) {
|
|
119
|
+
result.role = new Role(mergeDefaults({
|
|
120
|
+
apiVersion: "rbac.authorization.k8s.io/v1",
|
|
121
|
+
kind: "Role",
|
|
122
|
+
metadata: {
|
|
123
|
+
name: include(`${name}.fullname`),
|
|
124
|
+
labels: include(`${name}.labels`),
|
|
125
|
+
},
|
|
126
|
+
rules: toYaml(values.rbac.rules),
|
|
127
|
+
}, defs?.role));
|
|
128
|
+
result.roleBinding = new RoleBinding(mergeDefaults({
|
|
129
|
+
apiVersion: "rbac.authorization.k8s.io/v1",
|
|
130
|
+
kind: "RoleBinding",
|
|
131
|
+
metadata: {
|
|
132
|
+
name: include(`${name}.fullname`),
|
|
133
|
+
labels: include(`${name}.labels`),
|
|
134
|
+
},
|
|
135
|
+
roleRef: {
|
|
136
|
+
apiGroup: "rbac.authorization.k8s.io",
|
|
137
|
+
kind: "Role",
|
|
138
|
+
name: include(`${name}.fullname`),
|
|
139
|
+
},
|
|
140
|
+
subjects: [{
|
|
141
|
+
kind: "ServiceAccount",
|
|
142
|
+
name: include(`${name}.serviceAccountName`),
|
|
143
|
+
namespace: values.namespace ?? undefined,
|
|
144
|
+
}],
|
|
145
|
+
}, defs?.roleBinding));
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
}, "HelmBatchJob");
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HelmCRDLifecycle composite — managed CRD lifecycle via Helm hooks.
|
|
3
|
+
*
|
|
4
|
+
* Produces a Job-based CRD installer that runs as a pre-install/pre-upgrade
|
|
5
|
+
* hook, solving the Helm limitation that CRDs in crds/ are never upgraded
|
|
6
|
+
* or deleted.
|
|
7
|
+
*/
|
|
8
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
9
|
+
import { Chart, Values, Job, ConfigMap, ServiceAccount, ClusterRole, ClusterRoleBinding } from "../resources.js";
|
|
10
|
+
import { values, include, printf } from "../intrinsics.js";
|
|
11
|
+
export const HelmCRDLifecycle = Composite((props) => {
|
|
12
|
+
const { name, crdContent, kubectlImage = "bitnami/kubectl", kubectlTag = "latest", serviceAccountName, defaults: defs, } = props;
|
|
13
|
+
const saName = serviceAccountName ?? `${name}-crd-installer`;
|
|
14
|
+
const chart = new Chart(mergeDefaults({
|
|
15
|
+
apiVersion: "v2",
|
|
16
|
+
name,
|
|
17
|
+
version: "0.1.0",
|
|
18
|
+
type: "application",
|
|
19
|
+
description: `CRD lifecycle management for ${name}`,
|
|
20
|
+
}, defs?.chart));
|
|
21
|
+
const valuesRes = new Values(mergeDefaults({
|
|
22
|
+
crdLifecycle: {
|
|
23
|
+
enabled: true,
|
|
24
|
+
kubectl: {
|
|
25
|
+
image: kubectlImage,
|
|
26
|
+
tag: kubectlTag,
|
|
27
|
+
},
|
|
28
|
+
serviceAccount: {
|
|
29
|
+
name: saName,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
}, defs?.values));
|
|
33
|
+
const hookAnnotations = {
|
|
34
|
+
"helm.sh/hook": "pre-install,pre-upgrade",
|
|
35
|
+
"helm.sh/hook-weight": "-5",
|
|
36
|
+
"helm.sh/hook-delete-policy": "before-hook-creation",
|
|
37
|
+
};
|
|
38
|
+
const crdConfigMap = new ConfigMap(mergeDefaults({
|
|
39
|
+
apiVersion: "v1",
|
|
40
|
+
kind: "ConfigMap",
|
|
41
|
+
metadata: {
|
|
42
|
+
name: printf("%s-crd-content", include(`${name}.fullname`)),
|
|
43
|
+
labels: include(`${name}.labels`),
|
|
44
|
+
annotations: hookAnnotations,
|
|
45
|
+
},
|
|
46
|
+
data: {
|
|
47
|
+
"crds.yaml": crdContent,
|
|
48
|
+
},
|
|
49
|
+
}, defs?.crdConfigMap));
|
|
50
|
+
const serviceAccount = new ServiceAccount(mergeDefaults({
|
|
51
|
+
apiVersion: "v1",
|
|
52
|
+
kind: "ServiceAccount",
|
|
53
|
+
metadata: {
|
|
54
|
+
name: values.crdLifecycle.serviceAccount.name,
|
|
55
|
+
labels: include(`${name}.labels`),
|
|
56
|
+
annotations: hookAnnotations,
|
|
57
|
+
},
|
|
58
|
+
}, defs?.serviceAccount));
|
|
59
|
+
const clusterRole = new ClusterRole(mergeDefaults({
|
|
60
|
+
apiVersion: "rbac.authorization.k8s.io/v1",
|
|
61
|
+
kind: "ClusterRole",
|
|
62
|
+
metadata: {
|
|
63
|
+
name: printf("%s-crd-installer", include(`${name}.fullname`)),
|
|
64
|
+
labels: include(`${name}.labels`),
|
|
65
|
+
annotations: hookAnnotations,
|
|
66
|
+
},
|
|
67
|
+
rules: [{
|
|
68
|
+
apiGroups: ["apiextensions.k8s.io"],
|
|
69
|
+
resources: ["customresourcedefinitions"],
|
|
70
|
+
verbs: ["get", "list", "create", "update", "patch"],
|
|
71
|
+
}],
|
|
72
|
+
}, defs?.clusterRole));
|
|
73
|
+
const clusterRoleBinding = new ClusterRoleBinding(mergeDefaults({
|
|
74
|
+
apiVersion: "rbac.authorization.k8s.io/v1",
|
|
75
|
+
kind: "ClusterRoleBinding",
|
|
76
|
+
metadata: {
|
|
77
|
+
name: printf("%s-crd-installer", include(`${name}.fullname`)),
|
|
78
|
+
labels: include(`${name}.labels`),
|
|
79
|
+
annotations: hookAnnotations,
|
|
80
|
+
},
|
|
81
|
+
roleRef: {
|
|
82
|
+
apiGroup: "rbac.authorization.k8s.io",
|
|
83
|
+
kind: "ClusterRole",
|
|
84
|
+
name: printf("%s-crd-installer", include(`${name}.fullname`)),
|
|
85
|
+
},
|
|
86
|
+
subjects: [{
|
|
87
|
+
kind: "ServiceAccount",
|
|
88
|
+
name: values.crdLifecycle.serviceAccount.name,
|
|
89
|
+
namespace: "{{ .Release.Namespace }}",
|
|
90
|
+
}],
|
|
91
|
+
}, defs?.clusterRoleBinding));
|
|
92
|
+
const crdInstallJob = new Job(mergeDefaults({
|
|
93
|
+
apiVersion: "batch/v1",
|
|
94
|
+
kind: "Job",
|
|
95
|
+
metadata: {
|
|
96
|
+
name: printf("%s-crd-install", include(`${name}.fullname`)),
|
|
97
|
+
labels: include(`${name}.labels`),
|
|
98
|
+
annotations: hookAnnotations,
|
|
99
|
+
},
|
|
100
|
+
spec: {
|
|
101
|
+
template: {
|
|
102
|
+
metadata: {
|
|
103
|
+
labels: include(`${name}.selectorLabels`),
|
|
104
|
+
},
|
|
105
|
+
spec: {
|
|
106
|
+
serviceAccountName: values.crdLifecycle.serviceAccount.name,
|
|
107
|
+
restartPolicy: "Never",
|
|
108
|
+
securityContext: {
|
|
109
|
+
runAsNonRoot: true,
|
|
110
|
+
runAsUser: 1000,
|
|
111
|
+
},
|
|
112
|
+
containers: [{
|
|
113
|
+
name: "crd-installer",
|
|
114
|
+
image: printf("%s:%s", values.crdLifecycle.kubectl.image, values.crdLifecycle.kubectl.tag),
|
|
115
|
+
command: ["kubectl", "apply", "-f", "/crds/"],
|
|
116
|
+
securityContext: {
|
|
117
|
+
readOnlyRootFilesystem: true,
|
|
118
|
+
allowPrivilegeEscalation: false,
|
|
119
|
+
},
|
|
120
|
+
volumeMounts: [{
|
|
121
|
+
name: "crd-content",
|
|
122
|
+
mountPath: "/crds",
|
|
123
|
+
readOnly: true,
|
|
124
|
+
}],
|
|
125
|
+
}],
|
|
126
|
+
volumes: [{
|
|
127
|
+
name: "crd-content",
|
|
128
|
+
configMap: {
|
|
129
|
+
name: printf("%s-crd-content", include(`${name}.fullname`)),
|
|
130
|
+
},
|
|
131
|
+
}],
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
}, defs?.crdInstallJob));
|
|
136
|
+
return {
|
|
137
|
+
chart,
|
|
138
|
+
values: valuesRes,
|
|
139
|
+
crdInstallJob,
|
|
140
|
+
crdConfigMap,
|
|
141
|
+
serviceAccount,
|
|
142
|
+
clusterRole,
|
|
143
|
+
clusterRoleBinding,
|
|
144
|
+
};
|
|
145
|
+
}, "HelmCRDLifecycle");
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HelmCronJob composite — CronJob chart.
|
|
3
|
+
*
|
|
4
|
+
* Produces a Helm chart for scheduled batch workloads.
|
|
5
|
+
*/
|
|
6
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
7
|
+
import { Chart, Values, CronJob, ServiceAccount } from "../resources.js";
|
|
8
|
+
import { values, include, printf, toYaml, With } from "../intrinsics.js";
|
|
9
|
+
export const HelmCronJob = Composite((props) => {
|
|
10
|
+
const { name, imageRepository = "busybox", imageTag = "latest", schedule = "0 * * * *", restartPolicy = "OnFailure", appVersion = "1.0.0", serviceAccount = false, defaults: defs, } = props;
|
|
11
|
+
const chart = new Chart(mergeDefaults({
|
|
12
|
+
apiVersion: "v2",
|
|
13
|
+
name,
|
|
14
|
+
version: "0.1.0",
|
|
15
|
+
appVersion,
|
|
16
|
+
type: "application",
|
|
17
|
+
description: `A Helm chart for ${name} (cron job)`,
|
|
18
|
+
}, defs?.chart));
|
|
19
|
+
const valuesObj = {
|
|
20
|
+
image: {
|
|
21
|
+
repository: imageRepository,
|
|
22
|
+
tag: imageTag,
|
|
23
|
+
pullPolicy: "IfNotPresent",
|
|
24
|
+
},
|
|
25
|
+
schedule,
|
|
26
|
+
restartPolicy,
|
|
27
|
+
command: [],
|
|
28
|
+
args: [],
|
|
29
|
+
resources: {},
|
|
30
|
+
};
|
|
31
|
+
if (props.podSecurityContext)
|
|
32
|
+
valuesObj.podSecurityContext = props.podSecurityContext;
|
|
33
|
+
if (props.securityContext)
|
|
34
|
+
valuesObj.securityContext = props.securityContext;
|
|
35
|
+
if (props.nodeSelector)
|
|
36
|
+
valuesObj.nodeSelector = props.nodeSelector;
|
|
37
|
+
if (props.tolerations)
|
|
38
|
+
valuesObj.tolerations = props.tolerations;
|
|
39
|
+
if (props.affinity)
|
|
40
|
+
valuesObj.affinity = props.affinity;
|
|
41
|
+
if (props.podAnnotations)
|
|
42
|
+
valuesObj.podAnnotations = props.podAnnotations;
|
|
43
|
+
if (props.concurrencyPolicy)
|
|
44
|
+
valuesObj.concurrencyPolicy = props.concurrencyPolicy;
|
|
45
|
+
if (props.successfulJobsHistoryLimit !== undefined)
|
|
46
|
+
valuesObj.successfulJobsHistoryLimit = props.successfulJobsHistoryLimit;
|
|
47
|
+
if (props.failedJobsHistoryLimit !== undefined)
|
|
48
|
+
valuesObj.failedJobsHistoryLimit = props.failedJobsHistoryLimit;
|
|
49
|
+
if (props.backoffLimit !== undefined)
|
|
50
|
+
valuesObj.backoffLimit = props.backoffLimit;
|
|
51
|
+
if (serviceAccount) {
|
|
52
|
+
valuesObj.serviceAccount = {
|
|
53
|
+
create: true,
|
|
54
|
+
name: "",
|
|
55
|
+
annotations: {},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const valuesRes = new Values(mergeDefaults(valuesObj, defs?.values));
|
|
59
|
+
const containerSpec = {
|
|
60
|
+
name,
|
|
61
|
+
image: printf("%s:%s", values.image.repository, values.image.tag),
|
|
62
|
+
imagePullPolicy: values.image.pullPolicy,
|
|
63
|
+
command: values.command,
|
|
64
|
+
args: values.args,
|
|
65
|
+
resources: toYaml(values.resources),
|
|
66
|
+
};
|
|
67
|
+
if (props.securityContext)
|
|
68
|
+
containerSpec.securityContext = toYaml(values.securityContext);
|
|
69
|
+
const podSpec = {
|
|
70
|
+
restartPolicy: values.restartPolicy,
|
|
71
|
+
containers: [containerSpec],
|
|
72
|
+
};
|
|
73
|
+
if (props.podSecurityContext)
|
|
74
|
+
podSpec.securityContext = toYaml(values.podSecurityContext);
|
|
75
|
+
if (props.nodeSelector)
|
|
76
|
+
podSpec.nodeSelector = With(values.nodeSelector, toYaml(values.nodeSelector));
|
|
77
|
+
if (props.tolerations)
|
|
78
|
+
podSpec.tolerations = With(values.tolerations, toYaml(values.tolerations));
|
|
79
|
+
if (props.affinity)
|
|
80
|
+
podSpec.affinity = With(values.affinity, toYaml(values.affinity));
|
|
81
|
+
if (serviceAccount)
|
|
82
|
+
podSpec.serviceAccountName = include(`${name}.serviceAccountName`);
|
|
83
|
+
const templateMetadata = {
|
|
84
|
+
labels: include(`${name}.selectorLabels`),
|
|
85
|
+
};
|
|
86
|
+
if (props.podAnnotations)
|
|
87
|
+
templateMetadata.annotations = toYaml(values.podAnnotations);
|
|
88
|
+
const jobSpec = {
|
|
89
|
+
template: {
|
|
90
|
+
metadata: templateMetadata,
|
|
91
|
+
spec: podSpec,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
if (props.backoffLimit !== undefined)
|
|
95
|
+
jobSpec.backoffLimit = values.backoffLimit;
|
|
96
|
+
const cronJobSpec = {
|
|
97
|
+
schedule: values.schedule,
|
|
98
|
+
jobTemplate: {
|
|
99
|
+
spec: jobSpec,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
if (props.concurrencyPolicy)
|
|
103
|
+
cronJobSpec.concurrencyPolicy = values.concurrencyPolicy;
|
|
104
|
+
if (props.successfulJobsHistoryLimit !== undefined)
|
|
105
|
+
cronJobSpec.successfulJobsHistoryLimit = values.successfulJobsHistoryLimit;
|
|
106
|
+
if (props.failedJobsHistoryLimit !== undefined)
|
|
107
|
+
cronJobSpec.failedJobsHistoryLimit = values.failedJobsHistoryLimit;
|
|
108
|
+
const cronJob = new CronJob(mergeDefaults({
|
|
109
|
+
apiVersion: "batch/v1",
|
|
110
|
+
kind: "CronJob",
|
|
111
|
+
metadata: {
|
|
112
|
+
name: include(`${name}.fullname`),
|
|
113
|
+
labels: include(`${name}.labels`),
|
|
114
|
+
},
|
|
115
|
+
spec: cronJobSpec,
|
|
116
|
+
}, defs?.cronJob));
|
|
117
|
+
const result = { chart, values: valuesRes, cronJob };
|
|
118
|
+
if (serviceAccount) {
|
|
119
|
+
result.serviceAccount = new ServiceAccount(mergeDefaults({
|
|
120
|
+
apiVersion: "v1",
|
|
121
|
+
kind: "ServiceAccount",
|
|
122
|
+
metadata: {
|
|
123
|
+
name: include(`${name}.serviceAccountName`),
|
|
124
|
+
labels: include(`${name}.labels`),
|
|
125
|
+
annotations: toYaml(values.serviceAccount.annotations),
|
|
126
|
+
},
|
|
127
|
+
}, defs?.serviceAccount));
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
130
|
+
}, "HelmCronJob");
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HelmDaemonSet composite — DaemonSet + optional ServiceAccount.
|
|
3
|
+
*
|
|
4
|
+
* Common pattern for logging agents, monitoring sidecars, and node-level
|
|
5
|
+
* infrastructure that needs to run on every node.
|
|
6
|
+
*/
|
|
7
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
8
|
+
import { Chart, Values, DaemonSet, ServiceAccount } from "../resources.js";
|
|
9
|
+
import { values, include, printf, toYaml, With } from "../intrinsics.js";
|
|
10
|
+
export const HelmDaemonSet = Composite((props) => {
|
|
11
|
+
const { name, imageRepository = "fluent/fluent-bit", imageTag = "latest", port, hostPaths = [], serviceAccount = true, appVersion = "1.0.0", defaults: defs, } = props;
|
|
12
|
+
const chart = new Chart(mergeDefaults({
|
|
13
|
+
apiVersion: "v2",
|
|
14
|
+
name,
|
|
15
|
+
version: "0.1.0",
|
|
16
|
+
appVersion,
|
|
17
|
+
type: "application",
|
|
18
|
+
description: `A Helm chart for ${name} DaemonSet`,
|
|
19
|
+
}, defs?.chart));
|
|
20
|
+
const valuesObj = {
|
|
21
|
+
image: {
|
|
22
|
+
repository: imageRepository,
|
|
23
|
+
tag: imageTag,
|
|
24
|
+
pullPolicy: "IfNotPresent",
|
|
25
|
+
},
|
|
26
|
+
resources: {
|
|
27
|
+
limits: { cpu: "200m", memory: "256Mi" },
|
|
28
|
+
requests: { cpu: "100m", memory: "128Mi" },
|
|
29
|
+
},
|
|
30
|
+
nodeSelector: {},
|
|
31
|
+
tolerations: [],
|
|
32
|
+
updateStrategy: {
|
|
33
|
+
type: "RollingUpdate",
|
|
34
|
+
rollingUpdate: {
|
|
35
|
+
maxUnavailable: 1,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
if (serviceAccount) {
|
|
40
|
+
valuesObj.serviceAccount = {
|
|
41
|
+
create: true,
|
|
42
|
+
name: "",
|
|
43
|
+
annotations: {},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const valuesRes = new Values(mergeDefaults(valuesObj, defs?.values));
|
|
47
|
+
const containerSpec = {
|
|
48
|
+
name,
|
|
49
|
+
image: printf("%s:%s", values.image.repository, values.image.tag),
|
|
50
|
+
imagePullPolicy: values.image.pullPolicy,
|
|
51
|
+
resources: toYaml(values.resources),
|
|
52
|
+
securityContext: {
|
|
53
|
+
runAsNonRoot: true,
|
|
54
|
+
readOnlyRootFilesystem: true,
|
|
55
|
+
allowPrivilegeEscalation: false,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
if (port !== undefined) {
|
|
59
|
+
containerSpec.ports = [{ containerPort: port, name: "http" }];
|
|
60
|
+
}
|
|
61
|
+
if (hostPaths.length > 0) {
|
|
62
|
+
containerSpec.volumeMounts = hostPaths.map((hp) => ({
|
|
63
|
+
name: hp.name,
|
|
64
|
+
mountPath: hp.mountPath,
|
|
65
|
+
readOnly: hp.readOnly ?? true,
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
const podSpec = {
|
|
69
|
+
containers: [containerSpec],
|
|
70
|
+
securityContext: {
|
|
71
|
+
runAsNonRoot: true,
|
|
72
|
+
},
|
|
73
|
+
nodeSelector: With(values.nodeSelector, toYaml(values.nodeSelector)),
|
|
74
|
+
tolerations: With(values.tolerations, toYaml(values.tolerations)),
|
|
75
|
+
};
|
|
76
|
+
if (serviceAccount) {
|
|
77
|
+
podSpec.serviceAccountName = include(`${name}.serviceAccountName`);
|
|
78
|
+
}
|
|
79
|
+
if (hostPaths.length > 0) {
|
|
80
|
+
podSpec.volumes = hostPaths.map((hp) => ({
|
|
81
|
+
name: hp.name,
|
|
82
|
+
hostPath: {
|
|
83
|
+
path: hp.hostPath,
|
|
84
|
+
type: "Directory",
|
|
85
|
+
},
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
const daemonSet = new DaemonSet(mergeDefaults({
|
|
89
|
+
apiVersion: "apps/v1",
|
|
90
|
+
kind: "DaemonSet",
|
|
91
|
+
metadata: {
|
|
92
|
+
name: include(`${name}.fullname`),
|
|
93
|
+
labels: include(`${name}.labels`),
|
|
94
|
+
},
|
|
95
|
+
spec: {
|
|
96
|
+
selector: {
|
|
97
|
+
matchLabels: include(`${name}.selectorLabels`),
|
|
98
|
+
},
|
|
99
|
+
updateStrategy: toYaml(values.updateStrategy),
|
|
100
|
+
template: {
|
|
101
|
+
metadata: {
|
|
102
|
+
labels: include(`${name}.selectorLabels`),
|
|
103
|
+
},
|
|
104
|
+
spec: podSpec,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
}, defs?.daemonSet));
|
|
108
|
+
const result = {
|
|
109
|
+
chart,
|
|
110
|
+
values: valuesRes,
|
|
111
|
+
daemonSet,
|
|
112
|
+
};
|
|
113
|
+
if (serviceAccount) {
|
|
114
|
+
result.serviceAccount = new ServiceAccount(mergeDefaults({
|
|
115
|
+
apiVersion: "v1",
|
|
116
|
+
kind: "ServiceAccount",
|
|
117
|
+
metadata: {
|
|
118
|
+
name: include(`${name}.serviceAccountName`),
|
|
119
|
+
labels: include(`${name}.labels`),
|
|
120
|
+
annotations: toYaml(values.serviceAccount.annotations),
|
|
121
|
+
},
|
|
122
|
+
}, defs?.serviceAccount));
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
}, "HelmDaemonSet");
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HelmExternalSecret composite — ExternalSecret CR for secret management.
|
|
3
|
+
*
|
|
4
|
+
* Uses the external-secrets.io operator to sync secrets from external
|
|
5
|
+
* providers (AWS Secrets Manager, Vault, etc.) into Kubernetes Secrets.
|
|
6
|
+
*
|
|
7
|
+
* Thanks to the serializer's fallback GVK resolution, this composite
|
|
8
|
+
* returns a plain object with apiVersion/kind and the serializer handles
|
|
9
|
+
* it like any other K8s resource.
|
|
10
|
+
*/
|
|
11
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
12
|
+
import { Chart, Values, ExternalSecret } from "../resources.js";
|
|
13
|
+
import { values, include } from "../intrinsics.js";
|
|
14
|
+
export const HelmExternalSecret = Composite((props) => {
|
|
15
|
+
const { name, secretStoreName, secretStoreKind = "ClusterSecretStore", data, refreshInterval = "1h", defaults: defs, } = props;
|
|
16
|
+
const chart = new Chart(mergeDefaults({
|
|
17
|
+
apiVersion: "v2",
|
|
18
|
+
name,
|
|
19
|
+
version: "0.1.0",
|
|
20
|
+
type: "application",
|
|
21
|
+
description: `External secret management for ${name}`,
|
|
22
|
+
}, defs?.chart));
|
|
23
|
+
const secretDataEntries = Object.entries(data).map(([key, remotePath]) => ({
|
|
24
|
+
secretKey: key,
|
|
25
|
+
remoteRef: {
|
|
26
|
+
key: remotePath,
|
|
27
|
+
},
|
|
28
|
+
}));
|
|
29
|
+
const valuesRes = new Values(mergeDefaults({
|
|
30
|
+
externalSecret: {
|
|
31
|
+
refreshInterval,
|
|
32
|
+
secretStore: {
|
|
33
|
+
name: secretStoreName,
|
|
34
|
+
kind: secretStoreKind,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
}, defs?.values));
|
|
38
|
+
const externalSecret = new ExternalSecret(mergeDefaults({
|
|
39
|
+
apiVersion: "external-secrets.io/v1beta1",
|
|
40
|
+
kind: "ExternalSecret",
|
|
41
|
+
metadata: {
|
|
42
|
+
name: include(`${name}.fullname`),
|
|
43
|
+
labels: include(`${name}.labels`),
|
|
44
|
+
},
|
|
45
|
+
spec: {
|
|
46
|
+
refreshInterval: values.externalSecret.refreshInterval,
|
|
47
|
+
secretStoreRef: {
|
|
48
|
+
name: values.externalSecret.secretStore.name,
|
|
49
|
+
kind: values.externalSecret.secretStore.kind,
|
|
50
|
+
},
|
|
51
|
+
target: {
|
|
52
|
+
name: include(`${name}.fullname`),
|
|
53
|
+
creationPolicy: "Owner",
|
|
54
|
+
},
|
|
55
|
+
data: secretDataEntries,
|
|
56
|
+
},
|
|
57
|
+
}, defs?.externalSecret));
|
|
58
|
+
return {
|
|
59
|
+
chart,
|
|
60
|
+
values: valuesRes,
|
|
61
|
+
externalSecret,
|
|
62
|
+
};
|
|
63
|
+
}, "HelmExternalSecret");
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HelmLibrary composite — Library chart (type: library, no templates).
|
|
3
|
+
*
|
|
4
|
+
* Produces a Helm library chart with only Chart.yaml and _helpers.tpl.
|
|
5
|
+
*/
|
|
6
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
7
|
+
import { Chart, Values } from "../resources.js";
|
|
8
|
+
export const HelmLibrary = Composite((props) => {
|
|
9
|
+
const { name, version = "0.1.0", description = `A Helm library chart for ${name}`, dependencies = [], helpers = ["name", "fullname", "chart", "labels", "selectorLabels"], defaults: defs, } = props;
|
|
10
|
+
const chartProps = {
|
|
11
|
+
apiVersion: "v2",
|
|
12
|
+
name,
|
|
13
|
+
version,
|
|
14
|
+
type: "library",
|
|
15
|
+
description,
|
|
16
|
+
};
|
|
17
|
+
if (dependencies.length > 0) {
|
|
18
|
+
chartProps.dependencies = dependencies;
|
|
19
|
+
}
|
|
20
|
+
const chart = new Chart(mergeDefaults(chartProps, defs?.chart));
|
|
21
|
+
// Store helpers list in a Values resource so it's a Declarable member
|
|
22
|
+
const helpersRes = new Values(mergeDefaults({ helpers }, defs?.helpers));
|
|
23
|
+
return { chart, helpers: helpersRes };
|
|
24
|
+
}, "HelmLibrary");
|