timonel 2.10.2 → 2.11.0
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/CHANGELOG.md +6 -0
- package/README.md +5 -9
- package/dist/cli.js +8 -20
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/dist/lib/helmChartWriter.js +17 -2
- package/dist/lib/rutter.d.ts +1 -0
- package/dist/lib/rutter.js +64 -11
- package/dist/lib/templates/flexible-subchart.d.ts +1 -0
- package/dist/lib/templates/flexible-subchart.js +101 -0
- package/dist/lib/templates/umbrella-chart.d.ts +13 -2
- package/dist/lib/templates/umbrella-chart.js +128 -42
- package/dist/lib/utils/helmHelpers/envHelpers.d.ts +2 -0
- package/dist/lib/utils/helmHelpers/envHelpers.js +97 -0
- package/dist/lib/utils/helmHelpers/gitopsHelpers.d.ts +2 -0
- package/dist/lib/utils/helmHelpers/gitopsHelpers.js +132 -0
- package/dist/lib/utils/helmHelpers/index.d.ts +23 -0
- package/dist/lib/utils/helmHelpers/index.js +132 -0
- package/dist/lib/utils/helmHelpers/observabilityHelpers.d.ts +2 -0
- package/dist/lib/utils/helmHelpers/observabilityHelpers.js +221 -0
- package/dist/lib/utils/helmHelpers/types.d.ts +16 -0
- package/dist/lib/utils/helmHelpers/types.js +1 -0
- package/dist/lib/utils/helmHelpers/validationHelpers.d.ts +2 -0
- package/dist/lib/utils/helmHelpers/validationHelpers.js +201 -0
- package/dist/lib/utils/helmHelpers.d.ts +11 -1
- package/dist/lib/utils/helmHelpers.js +20 -7
- package/dist/lib/utils/helmYamlSerializer.d.ts +53 -1
- package/dist/lib/utils/helmYamlSerializer.js +325 -29
- package/dist/lib/utils/logger.d.ts +49 -0
- package/dist/lib/utils/logger.js +418 -0
- package/package.json +21 -11
- package/dist/lib/templates/basic-chart.d.ts +0 -19
- package/dist/lib/templates/basic-chart.js +0 -210
- package/dist/lib/templates/subchart.d.ts +0 -27
- package/dist/lib/templates/subchart.js +0 -219
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
export const OBSERVABILITY_HELPERS = [
|
|
2
|
+
{
|
|
3
|
+
name: 'monitoring.serviceMonitor',
|
|
4
|
+
template: `{{- if and .Values.serviceMonitor.enabled .Values.metrics.enabled -}}
|
|
5
|
+
apiVersion: monitoring.coreos.com/v1
|
|
6
|
+
kind: ServiceMonitor
|
|
7
|
+
metadata:
|
|
8
|
+
name: {{ include "chart.fullname" . }}
|
|
9
|
+
namespace: {{ .Release.Namespace }}
|
|
10
|
+
labels:
|
|
11
|
+
{{- include "chart.labels" . | nindent 4 }}
|
|
12
|
+
{{- with .Values.serviceMonitor.labels }}
|
|
13
|
+
{{- toYaml . | nindent 4 }}
|
|
14
|
+
{{- end }}
|
|
15
|
+
{{- with .Values.serviceMonitor.annotations }}
|
|
16
|
+
annotations:
|
|
17
|
+
{{- toYaml . | nindent 4 }}
|
|
18
|
+
{{- end }}
|
|
19
|
+
spec:
|
|
20
|
+
selector:
|
|
21
|
+
matchLabels:
|
|
22
|
+
{{- include "chart.selectorLabels" . | nindent 6 }}
|
|
23
|
+
{{- with .Values.serviceMonitor.selector }}
|
|
24
|
+
{{- toYaml . | nindent 6 }}
|
|
25
|
+
{{- end }}
|
|
26
|
+
endpoints:
|
|
27
|
+
- port: {{ .Values.metrics.port | default "metrics" }}
|
|
28
|
+
path: {{ .Values.metrics.path | default "/metrics" }}
|
|
29
|
+
interval: {{ .Values.serviceMonitor.interval | default "30s" }}
|
|
30
|
+
scrapeTimeout: {{ .Values.serviceMonitor.scrapeTimeout | default "10s" }}
|
|
31
|
+
{{- with .Values.serviceMonitor.metricRelabelings }}
|
|
32
|
+
metricRelabelings:
|
|
33
|
+
{{- toYaml . | nindent 8 }}
|
|
34
|
+
{{- end }}
|
|
35
|
+
{{- with .Values.serviceMonitor.relabelings }}
|
|
36
|
+
relabelings:
|
|
37
|
+
{{- toYaml . | nindent 8 }}
|
|
38
|
+
{{- end }}
|
|
39
|
+
{{- end }}`,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'monitoring.prometheusRule',
|
|
43
|
+
template: `{{- if .Values.prometheusRule.enabled -}}
|
|
44
|
+
apiVersion: monitoring.coreos.com/v1
|
|
45
|
+
kind: PrometheusRule
|
|
46
|
+
metadata:
|
|
47
|
+
name: {{ include "chart.fullname" . }}
|
|
48
|
+
namespace: {{ .Release.Namespace }}
|
|
49
|
+
labels:
|
|
50
|
+
{{- include "chart.labels" . | nindent 4 }}
|
|
51
|
+
{{- with .Values.prometheusRule.labels }}
|
|
52
|
+
{{- toYaml . | nindent 4 }}
|
|
53
|
+
{{- end }}
|
|
54
|
+
spec:
|
|
55
|
+
groups:
|
|
56
|
+
- name: {{ include "chart.fullname" . }}
|
|
57
|
+
rules:
|
|
58
|
+
{{- with .Values.prometheusRule.rules }}
|
|
59
|
+
{{- toYaml . | nindent 8 }}
|
|
60
|
+
{{- end }}
|
|
61
|
+
{{- end }}`,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'tracing.jaegerConfig',
|
|
65
|
+
template: `{{- if .Values.tracing.enabled -}}
|
|
66
|
+
JAEGER_AGENT_HOST: {{ .Values.tracing.jaeger.agent.host | default "jaeger-agent" }}
|
|
67
|
+
JAEGER_AGENT_PORT: {{ .Values.tracing.jaeger.agent.port | default "6831" }}
|
|
68
|
+
JAEGER_ENDPOINT: {{ .Values.tracing.jaeger.endpoint | default "" }}
|
|
69
|
+
JAEGER_SERVICE_NAME: {{ include "chart.fullname" . }}
|
|
70
|
+
JAEGER_SAMPLER_TYPE: {{ .Values.tracing.jaeger.sampler.type | default "const" }}
|
|
71
|
+
JAEGER_SAMPLER_PARAM: {{ .Values.tracing.jaeger.sampler.param | default "1" }}
|
|
72
|
+
JAEGER_REPORTER_MAX_QUEUE_SIZE: {{ .Values.tracing.jaeger.reporter.maxQueueSize | default "100" }}
|
|
73
|
+
JAEGER_REPORTER_FLUSH_INTERVAL: {{ .Values.tracing.jaeger.reporter.flushInterval | default "1s" }}
|
|
74
|
+
{{- with .Values.tracing.jaeger.tags }}
|
|
75
|
+
JAEGER_TAGS: {{ . | join "," }}
|
|
76
|
+
{{- end }}
|
|
77
|
+
{{- end }}`,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'tracing.otlpConfig',
|
|
81
|
+
template: `{{- if .Values.tracing.enabled -}}
|
|
82
|
+
OTEL_SERVICE_NAME: {{ include "chart.fullname" . }}
|
|
83
|
+
OTEL_SERVICE_VERSION: {{ .Chart.AppVersion }}
|
|
84
|
+
OTEL_RESOURCE_ATTRIBUTES: service.name={{ include "chart.fullname" . }},service.version={{ .Chart.AppVersion }},deployment.environment={{ .Values.environment | default "development" }}
|
|
85
|
+
{{- if .Values.tracing.otlp.endpoint }}
|
|
86
|
+
OTEL_EXPORTER_OTLP_ENDPOINT: {{ .Values.tracing.otlp.endpoint }}
|
|
87
|
+
{{- end }}
|
|
88
|
+
{{- if .Values.tracing.otlp.headers }}
|
|
89
|
+
OTEL_EXPORTER_OTLP_HEADERS: {{ .Values.tracing.otlp.headers | join "," }}
|
|
90
|
+
{{- end }}
|
|
91
|
+
OTEL_TRACES_SAMPLER: {{ .Values.tracing.otlp.sampler | default "parentbased_traceidratio" }}
|
|
92
|
+
OTEL_TRACES_SAMPLER_ARG: {{ .Values.tracing.otlp.samplerArg | default "1.0" }}
|
|
93
|
+
{{- end }}`,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: 'logging.structured',
|
|
97
|
+
template: `LOG_LEVEL: {{ .Values.logging.level | default "info" }}
|
|
98
|
+
LOG_FORMAT: {{ .Values.logging.format | default "json" }}
|
|
99
|
+
{{- if .Values.logging.correlation.enabled }}
|
|
100
|
+
LOG_CORRELATION_ENABLED: "true"
|
|
101
|
+
LOG_CORRELATION_HEADER: {{ .Values.logging.correlation.header | default "X-Correlation-ID" }}
|
|
102
|
+
{{- end }}
|
|
103
|
+
{{- if .Values.logging.sampling.enabled }}
|
|
104
|
+
LOG_SAMPLING_ENABLED: "true"
|
|
105
|
+
LOG_SAMPLING_RATE: {{ .Values.logging.sampling.rate | default "0.1" }}
|
|
106
|
+
{{- end }}`,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'logging.fluentdConfig',
|
|
110
|
+
template: `{{- if .Values.logging.fluentd.enabled -}}
|
|
111
|
+
FLUENTD_HOST: {{ .Values.logging.fluentd.host | default "fluentd" }}
|
|
112
|
+
FLUENTD_PORT: {{ .Values.logging.fluentd.port | default "24224" }}
|
|
113
|
+
FLUENTD_TAG: {{ .Values.logging.fluentd.tag | default (include "chart.fullname" .) }}
|
|
114
|
+
FLUENTD_BUFFER_LIMIT: {{ .Values.logging.fluentd.bufferLimit | default "8MB" }}
|
|
115
|
+
FLUENTD_TIMEOUT: {{ .Values.logging.fluentd.timeout | default "3.0" }}
|
|
116
|
+
{{- end }}`,
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
name: 'metrics.annotations',
|
|
120
|
+
template: `{{- if .Values.metrics.enabled -}}
|
|
121
|
+
prometheus.io/scrape: "true"
|
|
122
|
+
prometheus.io/port: "{{ .Values.metrics.port | default 9090 }}"
|
|
123
|
+
prometheus.io/path: "{{ .Values.metrics.path | default "/metrics" }}"
|
|
124
|
+
{{- if .Values.metrics.scheme }}
|
|
125
|
+
prometheus.io/scheme: "{{ .Values.metrics.scheme }}"
|
|
126
|
+
{{- end }}
|
|
127
|
+
{{- end }}`,
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: 'health.probes',
|
|
131
|
+
template: `{{- $healthPath := .Values.health.path | default "/health" -}}
|
|
132
|
+
{{- $readyPath := .Values.health.readiness.path | default "/ready" -}}
|
|
133
|
+
{{- $port := .Values.service.port | default 8080 -}}
|
|
134
|
+
livenessProbe:
|
|
135
|
+
httpGet:
|
|
136
|
+
path: {{ $healthPath }}
|
|
137
|
+
port: {{ $port }}
|
|
138
|
+
{{- if .Values.health.liveness.httpHeaders }}
|
|
139
|
+
httpHeaders:
|
|
140
|
+
{{- toYaml .Values.health.liveness.httpHeaders | nindent 6 }}
|
|
141
|
+
{{- end }}
|
|
142
|
+
initialDelaySeconds: {{ .Values.health.liveness.initialDelaySeconds | default 30 }}
|
|
143
|
+
periodSeconds: {{ .Values.health.liveness.periodSeconds | default 10 }}
|
|
144
|
+
timeoutSeconds: {{ .Values.health.liveness.timeoutSeconds | default 5 }}
|
|
145
|
+
successThreshold: {{ .Values.health.liveness.successThreshold | default 1 }}
|
|
146
|
+
failureThreshold: {{ .Values.health.liveness.failureThreshold | default 3 }}
|
|
147
|
+
readinessProbe:
|
|
148
|
+
httpGet:
|
|
149
|
+
path: {{ $readyPath }}
|
|
150
|
+
port: {{ $port }}
|
|
151
|
+
{{- if .Values.health.readiness.httpHeaders }}
|
|
152
|
+
httpHeaders:
|
|
153
|
+
{{- toYaml .Values.health.readiness.httpHeaders | nindent 6 }}
|
|
154
|
+
{{- end }}
|
|
155
|
+
initialDelaySeconds: {{ .Values.health.readiness.initialDelaySeconds | default 5 }}
|
|
156
|
+
periodSeconds: {{ .Values.health.readiness.periodSeconds | default 5 }}
|
|
157
|
+
timeoutSeconds: {{ .Values.health.readiness.timeoutSeconds | default 3 }}
|
|
158
|
+
successThreshold: {{ .Values.health.readiness.successThreshold | default 1 }}
|
|
159
|
+
failureThreshold: {{ .Values.health.readiness.failureThreshold | default 3 }}`,
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: 'health.startupProbe',
|
|
163
|
+
template: `{{- if .Values.health.startup.enabled -}}
|
|
164
|
+
{{- $startupPath := .Values.health.startup.path | default "/health" -}}
|
|
165
|
+
{{- $port := .Values.service.port | default 8080 -}}
|
|
166
|
+
startupProbe:
|
|
167
|
+
httpGet:
|
|
168
|
+
path: {{ $startupPath }}
|
|
169
|
+
port: {{ $port }}
|
|
170
|
+
{{- if .Values.health.startup.httpHeaders }}
|
|
171
|
+
httpHeaders:
|
|
172
|
+
{{- toYaml .Values.health.startup.httpHeaders | nindent 6 }}
|
|
173
|
+
{{- end }}
|
|
174
|
+
initialDelaySeconds: {{ .Values.health.startup.initialDelaySeconds | default 10 }}
|
|
175
|
+
periodSeconds: {{ .Values.health.startup.periodSeconds | default 10 }}
|
|
176
|
+
timeoutSeconds: {{ .Values.health.startup.timeoutSeconds | default 5 }}
|
|
177
|
+
successThreshold: {{ .Values.health.startup.successThreshold | default 1 }}
|
|
178
|
+
failureThreshold: {{ .Values.health.startup.failureThreshold | default 30 }}
|
|
179
|
+
{{- end }}`,
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
name: 'alerting.rules',
|
|
183
|
+
template: `{{- $serviceName := include "chart.fullname" . -}}
|
|
184
|
+
- alert: {{ $serviceName }}HighErrorRate
|
|
185
|
+
expr: rate(http_requests_total{job="{{ $serviceName }}", status=~"5.."}[5m]) > 0.1
|
|
186
|
+
for: 5m
|
|
187
|
+
labels:
|
|
188
|
+
severity: critical
|
|
189
|
+
service: {{ $serviceName }}
|
|
190
|
+
annotations:
|
|
191
|
+
summary: "High error rate detected"
|
|
192
|
+
description: "{{ $serviceName }} has error rate above 10% for more than 5 minutes"
|
|
193
|
+
|
|
194
|
+
- alert: {{ $serviceName }}HighLatency
|
|
195
|
+
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket{job="{{ $serviceName }}"}[5m])) > 0.5
|
|
196
|
+
for: 5m
|
|
197
|
+
labels:
|
|
198
|
+
severity: warning
|
|
199
|
+
service: {{ $serviceName }}
|
|
200
|
+
annotations:
|
|
201
|
+
summary: "High latency detected"
|
|
202
|
+
description: "{{ $serviceName }} 95th percentile latency is above 500ms"
|
|
203
|
+
|
|
204
|
+
- alert: {{ $serviceName }}LowAvailability
|
|
205
|
+
expr: avg_over_time(up{job="{{ $serviceName }}"}[5m]) < 0.9
|
|
206
|
+
for: 2m
|
|
207
|
+
labels:
|
|
208
|
+
severity: critical
|
|
209
|
+
service: {{ $serviceName }}
|
|
210
|
+
annotations:
|
|
211
|
+
summary: "Service availability is low"
|
|
212
|
+
description: "{{ $serviceName }} availability is below 90%"`,
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: 'dashboard.annotations',
|
|
216
|
+
template: `{{- if .Values.grafana.dashboard.enabled -}}
|
|
217
|
+
grafana.io/dashboard: "{{ .Values.grafana.dashboard.id | default (include "chart.fullname" .) }}"
|
|
218
|
+
grafana.io/folder: "{{ .Values.grafana.dashboard.folder | default "applications" }}"
|
|
219
|
+
{{- end }}`,
|
|
220
|
+
},
|
|
221
|
+
];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface HelperDefinition {
|
|
2
|
+
name: string;
|
|
3
|
+
template: string;
|
|
4
|
+
}
|
|
5
|
+
export type HelperCategory = 'standard' | 'fileAccess' | 'templateFunction' | 'sprig' | 'kubernetes' | 'aws' | 'env' | 'gitops' | 'observability' | 'validation';
|
|
6
|
+
export type CloudProvider = 'aws' | 'azure' | 'gcp';
|
|
7
|
+
export interface HelperOptions {
|
|
8
|
+
includeFileAccess?: boolean;
|
|
9
|
+
includeTemplateFunction?: boolean;
|
|
10
|
+
includeSprig?: boolean;
|
|
11
|
+
includeKubernetes?: boolean;
|
|
12
|
+
includeEnv?: boolean;
|
|
13
|
+
includeGitops?: boolean;
|
|
14
|
+
includeObservability?: boolean;
|
|
15
|
+
includeValidation?: boolean;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
export const VALIDATION_HELPERS = [
|
|
2
|
+
{
|
|
3
|
+
name: 'validation.semver',
|
|
4
|
+
template: `{{- $version := . -}}
|
|
5
|
+
{{- if not (regexMatch "^(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)(?:-((?:0|[1-9]\\\\d*|\\\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\\\.(?:0|[1-9]\\\\d*|\\\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\\\+([0-9a-zA-Z-]+(?:\\\\.[0-9a-zA-Z-]+)*))?$" $version) -}}
|
|
6
|
+
{{- fail (printf "Invalid semantic version: %s. Must follow semver format (e.g., 1.2.3, 1.0.0-alpha.1)" $version) -}}
|
|
7
|
+
{{- end -}}
|
|
8
|
+
{{- $version }}`,
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
name: 'validation.k8sName',
|
|
12
|
+
template: `{{- $name := . -}}
|
|
13
|
+
{{- if not (regexMatch "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$" $name) -}}
|
|
14
|
+
{{- fail (printf "Invalid Kubernetes resource name: %s. Must be lowercase alphanumeric with hyphens, starting and ending with alphanumeric characters" $name) -}}
|
|
15
|
+
{{- end -}}
|
|
16
|
+
{{- if gt (len $name) 63 -}}
|
|
17
|
+
{{- fail (printf "Kubernetes resource name too long: %s. Maximum 63 characters allowed" $name) -}}
|
|
18
|
+
{{- end -}}
|
|
19
|
+
{{- $name }}`,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'validation.dnsLabel',
|
|
23
|
+
template: `{{- $label := . -}}
|
|
24
|
+
{{- if not (regexMatch "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$" $label) -}}
|
|
25
|
+
{{- fail (printf "Invalid DNS label: %s. Must be lowercase alphanumeric with hyphens" $label) -}}
|
|
26
|
+
{{- end -}}
|
|
27
|
+
{{- if gt (len $label) 63 -}}
|
|
28
|
+
{{- fail (printf "DNS label too long: %s. Maximum 63 characters allowed" $label) -}}
|
|
29
|
+
{{- end -}}
|
|
30
|
+
{{- $label }}`,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'validation.email',
|
|
34
|
+
template: `{{- $email := . -}}
|
|
35
|
+
{{- if not (regexMatch "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,}$" $email) -}}
|
|
36
|
+
{{- fail (printf "Invalid email address: %s" $email) -}}
|
|
37
|
+
{{- end -}}
|
|
38
|
+
{{- $email }}`,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'validation.url',
|
|
42
|
+
template: `{{- $url := . -}}
|
|
43
|
+
{{- if not (regexMatch "^https?://[a-zA-Z0-9.-]+(?:[:/][^\\\\s]*)?$" $url) -}}
|
|
44
|
+
{{- fail (printf "Invalid URL: %s. Must be a valid HTTP or HTTPS URL" $url) -}}
|
|
45
|
+
{{- end -}}
|
|
46
|
+
{{- $url }}`,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'validation.port',
|
|
50
|
+
template: `{{- $port := . | int -}}
|
|
51
|
+
{{- if or (lt $port 1) (gt $port 65535) -}}
|
|
52
|
+
{{- fail (printf "Invalid port number: %d. Must be between 1 and 65535" $port) -}}
|
|
53
|
+
{{- end -}}
|
|
54
|
+
{{- $port }}`,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'validation.memorySize',
|
|
58
|
+
template: `{{- $size := . -}}
|
|
59
|
+
{{- if not (regexMatch "^[0-9]+(\\\\.[0-9]+)?(Ki|Mi|Gi|Ti|Pi|Ei|K|M|G|T|P|E)?$" $size) -}}
|
|
60
|
+
{{- fail (printf "Invalid memory size: %s. Use format like '512Mi', '2Gi', '1.5Gi'" $size) -}}
|
|
61
|
+
{{- end -}}
|
|
62
|
+
{{- $size }}`,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'validation.cpuSize',
|
|
66
|
+
template: `{{- $cpu := . -}}
|
|
67
|
+
{{- if not (regexMatch "^[0-9]+(\\\\.[0-9]+)?m?$" $cpu) -}}
|
|
68
|
+
{{- fail (printf "Invalid CPU size: %s. Use format like '500m', '1', '1.5', '2000m'" $cpu) -}}
|
|
69
|
+
{{- end -}}
|
|
70
|
+
{{- $cpu }}`,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'validation.duration',
|
|
74
|
+
template: `{{- $duration := . -}}
|
|
75
|
+
{{- if not (regexMatch "^[0-9]+(\\\\.[0-9]+)?(ns|us|µs|ms|s|m|h)$" $duration) -}}
|
|
76
|
+
{{- fail (printf "Invalid duration: %s. Use format like '30s', '5m', '2h', '100ms'" $duration) -}}
|
|
77
|
+
{{- end -}}
|
|
78
|
+
{{- $duration }}`,
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'validation.percentage',
|
|
82
|
+
template: `{{- $percentage := . -}}
|
|
83
|
+
{{- if regexMatch "^[0-9]+%$" ($percentage | toString) -}}
|
|
84
|
+
{{- $num := $percentage | toString | trimSuffix "%" | int -}}
|
|
85
|
+
{{- if or (lt $num 0) (gt $num 100) -}}
|
|
86
|
+
{{- fail (printf "Invalid percentage: %s. Must be between 0%% and 100%%" $percentage) -}}
|
|
87
|
+
{{- end -}}
|
|
88
|
+
{{- else -}}
|
|
89
|
+
{{- $num := $percentage | int -}}
|
|
90
|
+
{{- if or (lt $num 0) (gt $num 100) -}}
|
|
91
|
+
{{- fail (printf "Invalid percentage: %d. Must be between 0 and 100" $num) -}}
|
|
92
|
+
{{- end -}}
|
|
93
|
+
{{- end -}}
|
|
94
|
+
{{- $percentage }}`,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'validation.ipAddress',
|
|
98
|
+
template: `{{- $ip := . -}}
|
|
99
|
+
{{- if not (regexMatch "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" $ip) -}}
|
|
100
|
+
{{- fail (printf "Invalid IP address: %s. Must be a valid IPv4 address" $ip) -}}
|
|
101
|
+
{{- end -}}
|
|
102
|
+
{{- $ip }}`,
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'validation.cidr',
|
|
106
|
+
template: `{{- $cidr := . -}}
|
|
107
|
+
{{- if not (regexMatch "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/([0-9]|[1-2][0-9]|3[0-2])$" $cidr) -}}
|
|
108
|
+
{{- fail (printf "Invalid CIDR notation: %s. Must be a valid IPv4 CIDR (e.g., 192.168.1.0/24)" $cidr) -}}
|
|
109
|
+
{{- end -}}
|
|
110
|
+
{{- $cidr }}`,
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: 'validation.base64',
|
|
114
|
+
template: `{{- $value := . -}}
|
|
115
|
+
{{- if not (regexMatch "^[A-Za-z0-9+/]*={0,2}$" $value) -}}
|
|
116
|
+
{{- fail (printf "Invalid base64 string: %s" $value) -}}
|
|
117
|
+
{{- end -}}
|
|
118
|
+
{{- $value }}`,
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'validation.uuid',
|
|
122
|
+
template: `{{- $uuid := . -}}
|
|
123
|
+
{{- if not (regexMatch "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$" ($uuid | lower)) -}}
|
|
124
|
+
{{- fail (printf "Invalid UUID: %s. Must be a valid UUID format" $uuid) -}}
|
|
125
|
+
{{- end -}}
|
|
126
|
+
{{- $uuid }}`,
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
name: 'validation.cronSchedule',
|
|
130
|
+
template: `{{- $cron := . -}}
|
|
131
|
+
{{- $parts := regexSplit "\\\\s+" $cron -1 -}}
|
|
132
|
+
{{- if ne (len $parts) 5 -}}
|
|
133
|
+
{{- fail (printf "Invalid cron schedule: %s. Must have 5 parts (minute hour day month weekday)" $cron) -}}
|
|
134
|
+
{{- end -}}
|
|
135
|
+
{{- range $part := $parts -}}
|
|
136
|
+
{{- if not (regexMatch "^(\\\\*|[0-9,-/]+|\\\\*\\\\/[0-9]+)$" $part) -}}
|
|
137
|
+
{{- fail (printf "Invalid cron part: %s in schedule %s" $part $cron) -}}
|
|
138
|
+
{{- end -}}
|
|
139
|
+
{{- end -}}
|
|
140
|
+
{{- $cron }}`,
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: 'validation.imagePullPolicy',
|
|
144
|
+
template: `{{- $policy := . -}}
|
|
145
|
+
{{- if not (has $policy (list "Always" "IfNotPresent" "Never")) -}}
|
|
146
|
+
{{- fail (printf "Invalid image pull policy: %s. Must be one of: Always, IfNotPresent, Never" $policy) -}}
|
|
147
|
+
{{- end -}}
|
|
148
|
+
{{- $policy }}`,
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
name: 'validation.logLevel',
|
|
152
|
+
template: `{{- $level := . | lower -}}
|
|
153
|
+
{{- if not (has $level (list "trace" "debug" "info" "warn" "warning" "error" "fatal" "panic")) -}}
|
|
154
|
+
{{- fail (printf "Invalid log level: %s. Must be one of: trace, debug, info, warn, error, fatal, panic" .) -}}
|
|
155
|
+
{{- end -}}
|
|
156
|
+
{{- $level }}`,
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: 'validation.serviceType',
|
|
160
|
+
template: `{{- $type := . -}}
|
|
161
|
+
{{- if not (has $type (list "ClusterIP" "NodePort" "LoadBalancer" "ExternalName")) -}}
|
|
162
|
+
{{- fail (printf "Invalid service type: %s. Must be one of: ClusterIP, NodePort, LoadBalancer, ExternalName" $type) -}}
|
|
163
|
+
{{- end -}}
|
|
164
|
+
{{- $type }}`,
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: 'validation.storageAccessMode',
|
|
168
|
+
template: `{{- $mode := . -}}
|
|
169
|
+
{{- if not (has $mode (list "ReadWriteOnce" "ReadOnlyMany" "ReadWriteMany" "ReadWriteOncePod")) -}}
|
|
170
|
+
{{- fail (printf "Invalid storage access mode: %s. Must be one of: ReadWriteOnce, ReadOnlyMany, ReadWriteMany, ReadWriteOncePod" $mode) -}}
|
|
171
|
+
{{- end -}}
|
|
172
|
+
{{- $mode }}`,
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: 'validation.required',
|
|
176
|
+
template: `{{- $value := .value -}}
|
|
177
|
+
{{- $fieldName := .field | default "field" -}}
|
|
178
|
+
{{- if or (not $value) (and (kindIs "string" $value) (eq (trim $value) "")) -}}
|
|
179
|
+
{{- fail (printf "Required field '%s' is missing or empty" $fieldName) -}}
|
|
180
|
+
{{- end -}}
|
|
181
|
+
{{- $value }}`,
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: 'validation.nonEmpty',
|
|
185
|
+
template: `{{- $list := . -}}
|
|
186
|
+
{{- if not (and $list (gt (len $list) 0)) -}}
|
|
187
|
+
{{- fail "List cannot be empty" -}}
|
|
188
|
+
{{- end -}}
|
|
189
|
+
{{- $list }}`,
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: 'validation.range',
|
|
193
|
+
template: `{{- $value := .value | int -}}
|
|
194
|
+
{{- $min := .min | int -}}
|
|
195
|
+
{{- $max := .max | int -}}
|
|
196
|
+
{{- if or (lt $value $min) (gt $value $max) -}}
|
|
197
|
+
{{- fail (printf "Value %d is out of range [%d, %d]" $value $min $max) -}}
|
|
198
|
+
{{- end -}}
|
|
199
|
+
{{- $value }}`,
|
|
200
|
+
},
|
|
201
|
+
];
|
|
@@ -14,12 +14,22 @@ export declare function getDefaultHelpers(cloudProvider?: 'aws', options?: {
|
|
|
14
14
|
includeTemplateFunction?: boolean;
|
|
15
15
|
includeSprig?: boolean;
|
|
16
16
|
includeKubernetes?: boolean;
|
|
17
|
+
includeEnv?: boolean;
|
|
18
|
+
includeGitops?: boolean;
|
|
19
|
+
includeObservability?: boolean;
|
|
20
|
+
includeValidation?: boolean;
|
|
17
21
|
}): HelperDefinition[];
|
|
18
22
|
export declare function generateHelpersTemplate(cloudProvider?: 'aws', customHelpers?: HelperDefinition[], options?: {
|
|
19
23
|
includeFileAccess?: boolean;
|
|
20
24
|
includeTemplateFunction?: boolean;
|
|
21
25
|
includeSprig?: boolean;
|
|
22
26
|
includeKubernetes?: boolean;
|
|
27
|
+
includeEnv?: boolean;
|
|
28
|
+
includeGitops?: boolean;
|
|
29
|
+
includeObservability?: boolean;
|
|
30
|
+
includeValidation?: boolean;
|
|
23
31
|
}): string;
|
|
24
|
-
export declare function getHelpersByCategory(category: 'standard' | 'fileAccess' | 'templateFunction' | 'sprig' | 'kubernetes' | 'aws'): HelperDefinition[];
|
|
32
|
+
export declare function getHelpersByCategory(category: 'standard' | 'fileAccess' | 'templateFunction' | 'sprig' | 'kubernetes' | 'aws' | 'env' | 'gitops' | 'observability' | 'validation'): HelperDefinition[];
|
|
25
33
|
export declare function createHelper(name: string, template: string): HelperDefinition;
|
|
34
|
+
export { getNewHelpersByCategory, getAvailableHelperCategories, getHelpersByCategories, getHelpersByOptions, formatNewHelpers, generateNewHelpersTemplate, getCachedNewHelpersTemplate, createNewHelper, validateHelperNames, filterHelpersByPattern, getHelperStatistics, } from './helmHelpers/index.js';
|
|
35
|
+
export { ENV_HELPERS, GITOPS_HELPERS, OBSERVABILITY_HELPERS, VALIDATION_HELPERS, } from './helmHelpers/index.js';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ENV_HELPERS, GITOPS_HELPERS, OBSERVABILITY_HELPERS, VALIDATION_HELPERS, getNewHelpersByCategory, } from './helmHelpers/index.js';
|
|
1
2
|
export const STANDARD_HELPERS = [
|
|
2
3
|
{
|
|
3
4
|
name: 'chart.name',
|
|
@@ -87,12 +88,6 @@ export const TEMPLATE_FUNCTION_HELPERS = [
|
|
|
87
88
|
{{- $values := .values | default dict -}}
|
|
88
89
|
{{- $context := merge $values . -}}
|
|
89
90
|
{{- tpl $template $context -}}`,
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
name: 'validation.required',
|
|
93
|
-
template: `{{- $value := .value -}}
|
|
94
|
-
{{- $message := .message | default (printf "Value %s is required" .key) -}}
|
|
95
|
-
{{- required $message $value -}}`,
|
|
96
91
|
},
|
|
97
92
|
{
|
|
98
93
|
name: 'validation.requireAny',
|
|
@@ -131,7 +126,8 @@ export const SPRIG_HELPERS = [
|
|
|
131
126
|
name: 'env.getOrDefault',
|
|
132
127
|
template: `{{- $key := .key -}}
|
|
133
128
|
{{- $default := .default | default "" -}}
|
|
134
|
-
{{- $
|
|
129
|
+
{{- $value := index .Values.env $key -}}
|
|
130
|
+
{{- $value | default $default }}`,
|
|
135
131
|
},
|
|
136
132
|
{
|
|
137
133
|
name: 'list.compact',
|
|
@@ -287,6 +283,18 @@ export function getDefaultHelpers(cloudProvider, options) {
|
|
|
287
283
|
if (options?.includeKubernetes !== false) {
|
|
288
284
|
helpers.push(...KUBERNETES_HELPERS);
|
|
289
285
|
}
|
|
286
|
+
if (options?.includeEnv !== false) {
|
|
287
|
+
helpers.push(...ENV_HELPERS);
|
|
288
|
+
}
|
|
289
|
+
if (options?.includeGitops !== false) {
|
|
290
|
+
helpers.push(...GITOPS_HELPERS);
|
|
291
|
+
}
|
|
292
|
+
if (options?.includeObservability !== false) {
|
|
293
|
+
helpers.push(...OBSERVABILITY_HELPERS);
|
|
294
|
+
}
|
|
295
|
+
if (options?.includeValidation !== false) {
|
|
296
|
+
helpers.push(...VALIDATION_HELPERS);
|
|
297
|
+
}
|
|
290
298
|
if (cloudProvider === 'aws') {
|
|
291
299
|
helpers.push(...AWS_HELPERS);
|
|
292
300
|
}
|
|
@@ -300,6 +308,9 @@ export function generateHelpersTemplate(cloudProvider, customHelpers, options) {
|
|
|
300
308
|
return formatHelpers(helpers);
|
|
301
309
|
}
|
|
302
310
|
export function getHelpersByCategory(category) {
|
|
311
|
+
if (['env', 'gitops', 'observability', 'validation'].includes(category)) {
|
|
312
|
+
return getNewHelpersByCategory(category);
|
|
313
|
+
}
|
|
303
314
|
switch (category) {
|
|
304
315
|
case 'standard':
|
|
305
316
|
return [...STANDARD_HELPERS];
|
|
@@ -320,3 +331,5 @@ export function getHelpersByCategory(category) {
|
|
|
320
331
|
export function createHelper(name, template) {
|
|
321
332
|
return { name, template };
|
|
322
333
|
}
|
|
334
|
+
export { getNewHelpersByCategory, getAvailableHelperCategories, getHelpersByCategories, getHelpersByOptions, formatNewHelpers, generateNewHelpersTemplate, getCachedNewHelpersTemplate, createNewHelper, validateHelperNames, filterHelpersByPattern, getHelperStatistics, } from './helmHelpers/index.js';
|
|
335
|
+
export { ENV_HELPERS, GITOPS_HELPERS, OBSERVABILITY_HELPERS, VALIDATION_HELPERS, } from './helmHelpers/index.js';
|
|
@@ -1,8 +1,60 @@
|
|
|
1
1
|
import * as jsYaml from 'js-yaml';
|
|
2
|
+
type HelmExpressionType = 'block' | 'nested' | 'comment' | 'action-trimmed' | 'raw' | 'include-context' | 'generic';
|
|
3
|
+
interface HelmExpressionMatch {
|
|
4
|
+
type: HelmExpressionType;
|
|
5
|
+
expression: string;
|
|
6
|
+
start: number;
|
|
7
|
+
end: number;
|
|
8
|
+
}
|
|
9
|
+
interface HelmExpression {
|
|
10
|
+
__helmExpression: true;
|
|
11
|
+
value: string;
|
|
12
|
+
}
|
|
13
|
+
declare function createHelmExpression(value: string): HelmExpression;
|
|
14
|
+
declare function isHelmExpression(value: unknown): value is HelmExpression;
|
|
15
|
+
declare function detectHelmExpressions(str: string): HelmExpressionMatch[];
|
|
16
|
+
declare function preprocessHelmExpressions(obj: unknown, depth?: number): unknown;
|
|
17
|
+
declare function postProcessHelmExpressions(yaml: string): string;
|
|
2
18
|
export declare function dumpHelmAwareYaml(obj: unknown, options?: jsYaml.DumpOptions): string;
|
|
3
19
|
export declare function stringify(obj: unknown, options?: {
|
|
4
20
|
lineWidth?: number;
|
|
5
21
|
doubleQuotedAsJSON?: boolean;
|
|
6
22
|
simpleKeys?: boolean;
|
|
7
23
|
}): string;
|
|
8
|
-
export
|
|
24
|
+
export interface HelmValidationError {
|
|
25
|
+
type: 'syntax' | 'semantic' | 'reference' | 'type';
|
|
26
|
+
message: string;
|
|
27
|
+
line?: number;
|
|
28
|
+
column?: number;
|
|
29
|
+
expression?: string;
|
|
30
|
+
suggestion?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface HelmValidationResult {
|
|
33
|
+
isValid: boolean;
|
|
34
|
+
errors: HelmValidationError[];
|
|
35
|
+
warnings: HelmValidationError[];
|
|
36
|
+
statistics: {
|
|
37
|
+
totalExpressions: number;
|
|
38
|
+
expressionsByType: Record<string, number>;
|
|
39
|
+
complexity: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export declare function validateHelmYaml(yaml: string): HelmValidationResult;
|
|
43
|
+
export declare function parseHelmExpressions(content: string): Array<{
|
|
44
|
+
type: HelmExpressionType;
|
|
45
|
+
expression: string;
|
|
46
|
+
startLine: number;
|
|
47
|
+
startCol: number;
|
|
48
|
+
endLine: number;
|
|
49
|
+
endCol: number;
|
|
50
|
+
}>;
|
|
51
|
+
export interface PrettifyOptions {
|
|
52
|
+
indentSize?: number;
|
|
53
|
+
alignExpressions?: boolean;
|
|
54
|
+
preserveComments?: boolean;
|
|
55
|
+
maxLineWidth?: number;
|
|
56
|
+
sortKeys?: boolean;
|
|
57
|
+
groupHelpers?: boolean;
|
|
58
|
+
}
|
|
59
|
+
export declare function prettifyHelmTemplate(yaml: string, options?: PrettifyOptions): string;
|
|
60
|
+
export { createHelmExpression, isHelmExpression, detectHelmExpressions, preprocessHelmExpressions, postProcessHelmExpressions, };
|