kubetsx 0.1.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/LICENSE +22 -0
- package/README.md +371 -0
- package/dist/components/index.d.ts +46 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +155 -0
- package/dist/components/index.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx-runtime.d.ts +33 -0
- package/dist/jsx-runtime.d.ts.map +1 -0
- package/dist/jsx-runtime.js +58 -0
- package/dist/jsx-runtime.js.map +1 -0
- package/dist/render.d.ts +12 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +746 -0
- package/dist/render.js.map +1 -0
- package/dist/types.d.ts +339 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/examples/basic.tsx +71 -0
- package/examples/full-stack.tsx +339 -0
- package/examples/tsconfig.json +21 -0
- package/package.json +57 -0
- package/src/components/index.ts +241 -0
- package/src/index.ts +123 -0
- package/src/jsx-runtime.ts +71 -0
- package/src/render.ts +862 -0
- package/src/types.ts +362 -0
- package/tsconfig.examples.json +18 -0
- package/tsconfig.json +22 -0
package/dist/render.js
ADDED
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🎯 Kubetsx - YAML Render Engine
|
|
3
|
+
*
|
|
4
|
+
* Transforms JSX element tree into Kubernetes YAML manifests
|
|
5
|
+
*/
|
|
6
|
+
import { stringify } from 'yaml';
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Main Render Function
|
|
11
|
+
// ============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Render a Kubex JSX tree to Kubernetes YAML
|
|
14
|
+
*/
|
|
15
|
+
export function render(element, options = {}) {
|
|
16
|
+
const resources = processElement(element, {});
|
|
17
|
+
const yamls = resources.map(r => stringify(r, { indent: 2 }));
|
|
18
|
+
const output = yamls.join('---\n');
|
|
19
|
+
if (options.output && !options.dryRun) {
|
|
20
|
+
if (options.splitFiles) {
|
|
21
|
+
// Write each resource to a separate file
|
|
22
|
+
resources.forEach((resource, i) => {
|
|
23
|
+
const filename = `${resource.metadata.name}-${resource.kind.toLowerCase()}.yaml`;
|
|
24
|
+
const filepath = path.join(options.output, filename);
|
|
25
|
+
fs.mkdirSync(options.output, { recursive: true });
|
|
26
|
+
fs.writeFileSync(filepath, stringify(resource, { indent: 2 }));
|
|
27
|
+
console.log(`✅ Generated: ${filepath}`);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
// Write all resources to a single file
|
|
32
|
+
fs.mkdirSync(path.dirname(options.output), { recursive: true });
|
|
33
|
+
fs.writeFileSync(options.output, output);
|
|
34
|
+
console.log(`✅ Generated: ${options.output}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else if (!options.dryRun) {
|
|
38
|
+
console.log(output);
|
|
39
|
+
}
|
|
40
|
+
return output;
|
|
41
|
+
}
|
|
42
|
+
function processElement(node, ctx) {
|
|
43
|
+
if (!node || typeof node !== 'object' || !('type' in node)) {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
const element = node;
|
|
47
|
+
// Handle function components
|
|
48
|
+
if (typeof element.type === 'function') {
|
|
49
|
+
const result = element.type({ ...element.props, children: element.children });
|
|
50
|
+
return result ? processElement(result, ctx) : [];
|
|
51
|
+
}
|
|
52
|
+
const type = element.type;
|
|
53
|
+
const props = element.props;
|
|
54
|
+
const children = element.children;
|
|
55
|
+
switch (type) {
|
|
56
|
+
case 'Fragment':
|
|
57
|
+
case 'Manifest':
|
|
58
|
+
return children.flatMap(child => processElement(child, ctx));
|
|
59
|
+
case 'Cluster':
|
|
60
|
+
return children.flatMap(child => processElement(child, ctx));
|
|
61
|
+
case 'Namespace':
|
|
62
|
+
return processNamespace(props, children, ctx);
|
|
63
|
+
case 'Deployment':
|
|
64
|
+
return processDeployment(props, children, ctx);
|
|
65
|
+
case 'Service':
|
|
66
|
+
return [processService(props, ctx)];
|
|
67
|
+
case 'Ingress':
|
|
68
|
+
return [processIngress(props, children, ctx)];
|
|
69
|
+
case 'ConfigMap':
|
|
70
|
+
return [processConfigMap(props, ctx)];
|
|
71
|
+
case 'Secret':
|
|
72
|
+
return [processSecret(props, ctx)];
|
|
73
|
+
case 'Pvc':
|
|
74
|
+
return [processPvc(props, ctx)];
|
|
75
|
+
case 'Hpa':
|
|
76
|
+
return [processHpa(props, ctx)];
|
|
77
|
+
case 'Job':
|
|
78
|
+
return processJob(props, children, ctx);
|
|
79
|
+
case 'CronJob':
|
|
80
|
+
return processCronJob(props, children, ctx);
|
|
81
|
+
case 'ServiceAccount':
|
|
82
|
+
return [processServiceAccount(props, ctx)];
|
|
83
|
+
case 'Role':
|
|
84
|
+
return [processRole(props, ctx)];
|
|
85
|
+
case 'ClusterRole':
|
|
86
|
+
return [processClusterRole(props, ctx)];
|
|
87
|
+
case 'RoleBinding':
|
|
88
|
+
return [processRoleBinding(props, ctx)];
|
|
89
|
+
case 'ClusterRoleBinding':
|
|
90
|
+
return [processClusterRoleBinding(props, ctx)];
|
|
91
|
+
default:
|
|
92
|
+
// Unknown element, process children
|
|
93
|
+
return children.flatMap(child => processElement(child, ctx));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// ============================================================================
|
|
97
|
+
// Resource Processors
|
|
98
|
+
// ============================================================================
|
|
99
|
+
function processNamespace(props, children, ctx) {
|
|
100
|
+
const name = props.name;
|
|
101
|
+
const labels = props.labels;
|
|
102
|
+
const nsResource = {
|
|
103
|
+
apiVersion: 'v1',
|
|
104
|
+
kind: 'Namespace',
|
|
105
|
+
metadata: { name, labels },
|
|
106
|
+
};
|
|
107
|
+
const childResources = children.flatMap(child => processElement(child, { ...ctx, namespace: name }));
|
|
108
|
+
return [nsResource, ...childResources];
|
|
109
|
+
}
|
|
110
|
+
function processDeployment(props, children, ctx) {
|
|
111
|
+
const name = props.name;
|
|
112
|
+
const namespace = props.namespace || ctx.namespace;
|
|
113
|
+
const replicas = props.replicas ?? 1;
|
|
114
|
+
const labels = { app: name, ...props.labels };
|
|
115
|
+
const annotations = props.annotations;
|
|
116
|
+
const selector = props.selector || { app: name };
|
|
117
|
+
const strategy = props.strategy;
|
|
118
|
+
// Process children to extract containers, volumes, etc.
|
|
119
|
+
const containers = [];
|
|
120
|
+
const volumes = [];
|
|
121
|
+
for (const child of children) {
|
|
122
|
+
processDeploymentChild(child, containers, volumes, ctx);
|
|
123
|
+
}
|
|
124
|
+
const resource = {
|
|
125
|
+
apiVersion: 'apps/v1',
|
|
126
|
+
kind: 'Deployment',
|
|
127
|
+
metadata: {
|
|
128
|
+
name,
|
|
129
|
+
namespace,
|
|
130
|
+
labels,
|
|
131
|
+
annotations,
|
|
132
|
+
},
|
|
133
|
+
spec: {
|
|
134
|
+
replicas,
|
|
135
|
+
selector: { matchLabels: selector },
|
|
136
|
+
...(strategy && { strategy: { type: strategy } }),
|
|
137
|
+
template: {
|
|
138
|
+
metadata: { labels },
|
|
139
|
+
spec: {
|
|
140
|
+
containers,
|
|
141
|
+
...(volumes.length > 0 && { volumes }),
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
return [resource];
|
|
147
|
+
}
|
|
148
|
+
function processDeploymentChild(node, containers, volumes, ctx) {
|
|
149
|
+
if (!node || typeof node !== 'object' || !('type' in node))
|
|
150
|
+
return;
|
|
151
|
+
const element = node;
|
|
152
|
+
// Handle function components
|
|
153
|
+
if (typeof element.type === 'function') {
|
|
154
|
+
const result = element.type({ ...element.props, children: element.children });
|
|
155
|
+
if (result)
|
|
156
|
+
processDeploymentChild(result, containers, volumes, ctx);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const type = element.type;
|
|
160
|
+
if (type === 'Fragment') {
|
|
161
|
+
for (const child of element.children) {
|
|
162
|
+
processDeploymentChild(child, containers, volumes, ctx);
|
|
163
|
+
}
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (type === 'Container') {
|
|
167
|
+
containers.push(processContainer(element));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (type === 'Volume') {
|
|
171
|
+
volumes.push(processVolume(element));
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function processContainer(element) {
|
|
176
|
+
const props = element.props;
|
|
177
|
+
const children = element.children;
|
|
178
|
+
const container = {
|
|
179
|
+
name: props.name,
|
|
180
|
+
image: props.image,
|
|
181
|
+
};
|
|
182
|
+
if (props.imagePullPolicy)
|
|
183
|
+
container.imagePullPolicy = props.imagePullPolicy;
|
|
184
|
+
if (props.command)
|
|
185
|
+
container.command = props.command;
|
|
186
|
+
if (props.args)
|
|
187
|
+
container.args = props.args;
|
|
188
|
+
if (props.workingDir)
|
|
189
|
+
container.workingDir = props.workingDir;
|
|
190
|
+
// Process children
|
|
191
|
+
for (const child of children) {
|
|
192
|
+
processContainerChild(child, container);
|
|
193
|
+
}
|
|
194
|
+
return container;
|
|
195
|
+
}
|
|
196
|
+
function processContainerChild(node, container) {
|
|
197
|
+
if (!node || typeof node !== 'object' || !('type' in node))
|
|
198
|
+
return;
|
|
199
|
+
const element = node;
|
|
200
|
+
if (typeof element.type === 'function') {
|
|
201
|
+
const result = element.type({ ...element.props, children: element.children });
|
|
202
|
+
if (result)
|
|
203
|
+
processContainerChild(result, container);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const type = element.type;
|
|
207
|
+
const props = element.props;
|
|
208
|
+
switch (type) {
|
|
209
|
+
case 'Fragment':
|
|
210
|
+
for (const child of element.children) {
|
|
211
|
+
processContainerChild(child, container);
|
|
212
|
+
}
|
|
213
|
+
break;
|
|
214
|
+
case 'Port':
|
|
215
|
+
container.ports = container.ports || [];
|
|
216
|
+
const portEntry = {
|
|
217
|
+
containerPort: props.container,
|
|
218
|
+
};
|
|
219
|
+
if (props.name)
|
|
220
|
+
portEntry.name = props.name;
|
|
221
|
+
if (props.protocol)
|
|
222
|
+
portEntry.protocol = props.protocol;
|
|
223
|
+
container.ports.push(portEntry);
|
|
224
|
+
break;
|
|
225
|
+
case 'Env':
|
|
226
|
+
container.env = container.env || [];
|
|
227
|
+
const envEntry = {
|
|
228
|
+
name: props.name,
|
|
229
|
+
};
|
|
230
|
+
if (props.value !== undefined) {
|
|
231
|
+
envEntry.value = props.value;
|
|
232
|
+
}
|
|
233
|
+
else if (element.children.length > 0) {
|
|
234
|
+
const valueFrom = processEnvChild(element.children[0]);
|
|
235
|
+
if (valueFrom)
|
|
236
|
+
envEntry.valueFrom = valueFrom;
|
|
237
|
+
}
|
|
238
|
+
container.env.push(envEntry);
|
|
239
|
+
break;
|
|
240
|
+
case 'Resources':
|
|
241
|
+
const requests = {};
|
|
242
|
+
const limits = {};
|
|
243
|
+
if (props.requestMemory)
|
|
244
|
+
requests.memory = props.requestMemory;
|
|
245
|
+
if (props.requestCpu)
|
|
246
|
+
requests.cpu = props.requestCpu;
|
|
247
|
+
if (props.requestEphemeralStorage)
|
|
248
|
+
requests['ephemeral-storage'] = props.requestEphemeralStorage;
|
|
249
|
+
if (props.limitMemory)
|
|
250
|
+
limits.memory = props.limitMemory;
|
|
251
|
+
if (props.limitCpu)
|
|
252
|
+
limits.cpu = props.limitCpu;
|
|
253
|
+
if (props.limitEphemeralStorage)
|
|
254
|
+
limits['ephemeral-storage'] = props.limitEphemeralStorage;
|
|
255
|
+
container.resources = { requests, limits };
|
|
256
|
+
break;
|
|
257
|
+
case 'Probe':
|
|
258
|
+
const probeType = props.type;
|
|
259
|
+
const probe = processProbe(element);
|
|
260
|
+
if (probeType === 'liveness')
|
|
261
|
+
container.livenessProbe = probe;
|
|
262
|
+
else if (probeType === 'readiness')
|
|
263
|
+
container.readinessProbe = probe;
|
|
264
|
+
else if (probeType === 'startup')
|
|
265
|
+
container.startupProbe = probe;
|
|
266
|
+
break;
|
|
267
|
+
case 'VolumeMount':
|
|
268
|
+
container.volumeMounts = container.volumeMounts || [];
|
|
269
|
+
const volumeMount = {
|
|
270
|
+
name: props.name,
|
|
271
|
+
mountPath: props.mountPath,
|
|
272
|
+
};
|
|
273
|
+
if (props.subPath)
|
|
274
|
+
volumeMount.subPath = props.subPath;
|
|
275
|
+
if (props.readOnly)
|
|
276
|
+
volumeMount.readOnly = props.readOnly;
|
|
277
|
+
container.volumeMounts.push(volumeMount);
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function resolveElement(node) {
|
|
282
|
+
if (!node || typeof node !== 'object' || !('type' in node))
|
|
283
|
+
return null;
|
|
284
|
+
let element = node;
|
|
285
|
+
// If type is a function component, call it to get the actual element
|
|
286
|
+
while (typeof element.type === 'function') {
|
|
287
|
+
const result = element.type({ ...element.props, children: element.children });
|
|
288
|
+
if (!result || typeof result !== 'object' || !('type' in result))
|
|
289
|
+
return null;
|
|
290
|
+
element = result;
|
|
291
|
+
}
|
|
292
|
+
return element;
|
|
293
|
+
}
|
|
294
|
+
function processEnvChild(node) {
|
|
295
|
+
const element = resolveElement(node);
|
|
296
|
+
if (!element)
|
|
297
|
+
return null;
|
|
298
|
+
const type = element.type;
|
|
299
|
+
const props = element.props;
|
|
300
|
+
if (type === 'SecretRef') {
|
|
301
|
+
return {
|
|
302
|
+
secretKeyRef: {
|
|
303
|
+
name: props.name,
|
|
304
|
+
key: props.secretKey,
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
if (type === 'ConfigMapRef') {
|
|
309
|
+
return {
|
|
310
|
+
configMapKeyRef: {
|
|
311
|
+
name: props.name,
|
|
312
|
+
key: props.configKey,
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
function processProbe(element) {
|
|
319
|
+
const props = element.props;
|
|
320
|
+
const children = element.children;
|
|
321
|
+
const probe = {};
|
|
322
|
+
if (props.delay)
|
|
323
|
+
probe.initialDelaySeconds = props.delay;
|
|
324
|
+
if (props.period)
|
|
325
|
+
probe.periodSeconds = props.period;
|
|
326
|
+
if (props.timeout)
|
|
327
|
+
probe.timeoutSeconds = props.timeout;
|
|
328
|
+
if (props.successThreshold)
|
|
329
|
+
probe.successThreshold = props.successThreshold;
|
|
330
|
+
if (props.failureThreshold)
|
|
331
|
+
probe.failureThreshold = props.failureThreshold;
|
|
332
|
+
for (const child of children) {
|
|
333
|
+
const childEl = resolveElement(child);
|
|
334
|
+
if (!childEl)
|
|
335
|
+
continue;
|
|
336
|
+
const type = childEl.type;
|
|
337
|
+
const childProps = childEl.props;
|
|
338
|
+
if (type === 'HttpProbe') {
|
|
339
|
+
const httpGet = {
|
|
340
|
+
path: childProps.path,
|
|
341
|
+
port: childProps.port,
|
|
342
|
+
};
|
|
343
|
+
if (childProps.scheme)
|
|
344
|
+
httpGet.scheme = childProps.scheme;
|
|
345
|
+
probe.httpGet = httpGet;
|
|
346
|
+
}
|
|
347
|
+
else if (type === 'TcpProbe') {
|
|
348
|
+
probe.tcpSocket = { port: childProps.port };
|
|
349
|
+
}
|
|
350
|
+
else if (type === 'ExecProbe') {
|
|
351
|
+
probe.exec = { command: childProps.command };
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return probe;
|
|
355
|
+
}
|
|
356
|
+
function processVolume(element) {
|
|
357
|
+
const name = element.props.name;
|
|
358
|
+
const volume = { name };
|
|
359
|
+
for (const child of element.children) {
|
|
360
|
+
const childEl = resolveElement(child);
|
|
361
|
+
if (!childEl)
|
|
362
|
+
continue;
|
|
363
|
+
const type = childEl.type;
|
|
364
|
+
const props = childEl.props;
|
|
365
|
+
if (type === 'EmptyDir') {
|
|
366
|
+
const emptyDir = {};
|
|
367
|
+
if (props.medium)
|
|
368
|
+
emptyDir.medium = props.medium;
|
|
369
|
+
if (props.sizeLimit)
|
|
370
|
+
emptyDir.sizeLimit = props.sizeLimit;
|
|
371
|
+
volume.emptyDir = emptyDir;
|
|
372
|
+
}
|
|
373
|
+
else if (type === 'PvcVolume') {
|
|
374
|
+
const pvc = {
|
|
375
|
+
claimName: props.claimName,
|
|
376
|
+
};
|
|
377
|
+
if (props.readOnly)
|
|
378
|
+
pvc.readOnly = props.readOnly;
|
|
379
|
+
volume.persistentVolumeClaim = pvc;
|
|
380
|
+
}
|
|
381
|
+
else if (type === 'ConfigMapVolume') {
|
|
382
|
+
const configMap = {
|
|
383
|
+
name: props.name,
|
|
384
|
+
};
|
|
385
|
+
if (props.items)
|
|
386
|
+
configMap.items = props.items;
|
|
387
|
+
volume.configMap = configMap;
|
|
388
|
+
}
|
|
389
|
+
else if (type === 'SecretVolume') {
|
|
390
|
+
const secret = {
|
|
391
|
+
secretName: props.secretName,
|
|
392
|
+
};
|
|
393
|
+
if (props.items)
|
|
394
|
+
secret.items = props.items;
|
|
395
|
+
volume.secret = secret;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return volume;
|
|
399
|
+
}
|
|
400
|
+
function processService(props, ctx) {
|
|
401
|
+
const name = props.name;
|
|
402
|
+
const namespace = props.namespace || ctx.namespace;
|
|
403
|
+
const type = props.type || 'ClusterIP';
|
|
404
|
+
const port = props.port;
|
|
405
|
+
const targetPort = props.targetPort || port;
|
|
406
|
+
const nodePort = props.nodePort;
|
|
407
|
+
const selector = props.selector || { app: name };
|
|
408
|
+
const labels = props.labels;
|
|
409
|
+
return {
|
|
410
|
+
apiVersion: 'v1',
|
|
411
|
+
kind: 'Service',
|
|
412
|
+
metadata: { name, namespace, labels },
|
|
413
|
+
spec: {
|
|
414
|
+
type,
|
|
415
|
+
selector,
|
|
416
|
+
ports: [
|
|
417
|
+
{
|
|
418
|
+
port,
|
|
419
|
+
targetPort,
|
|
420
|
+
...(nodePort && { nodePort }),
|
|
421
|
+
},
|
|
422
|
+
],
|
|
423
|
+
},
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
function processIngress(props, children, ctx) {
|
|
427
|
+
const name = props.name;
|
|
428
|
+
const namespace = props.namespace || ctx.namespace;
|
|
429
|
+
const className = props.className;
|
|
430
|
+
const ssl = props.ssl;
|
|
431
|
+
const annotations = {
|
|
432
|
+
...(ssl && { 'nginx.ingress.kubernetes.io/ssl-redirect': 'true' }),
|
|
433
|
+
...props.annotations,
|
|
434
|
+
};
|
|
435
|
+
const rules = [];
|
|
436
|
+
const tls = [];
|
|
437
|
+
for (const child of children) {
|
|
438
|
+
const childEl = resolveElement(child);
|
|
439
|
+
if (!childEl)
|
|
440
|
+
continue;
|
|
441
|
+
const childType = childEl.type;
|
|
442
|
+
if (childType === 'IngressHost') {
|
|
443
|
+
const host = childEl.props.host;
|
|
444
|
+
const paths = [];
|
|
445
|
+
for (const routeChild of childEl.children) {
|
|
446
|
+
const routeEl = resolveElement(routeChild);
|
|
447
|
+
if (!routeEl)
|
|
448
|
+
continue;
|
|
449
|
+
if (routeEl.type === 'Route') {
|
|
450
|
+
paths.push({
|
|
451
|
+
path: routeEl.props.path,
|
|
452
|
+
pathType: routeEl.props.pathType || 'Prefix',
|
|
453
|
+
backend: {
|
|
454
|
+
service: {
|
|
455
|
+
name: routeEl.props.service,
|
|
456
|
+
port: { number: routeEl.props.port },
|
|
457
|
+
},
|
|
458
|
+
},
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
rules.push({ host, http: { paths } });
|
|
463
|
+
if (ssl) {
|
|
464
|
+
tls.push({ hosts: [host], secretName: `${name}-tls` });
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
else if (childType === 'Route') {
|
|
468
|
+
// Direct route without host wrapper
|
|
469
|
+
const hostFromProps = props.host;
|
|
470
|
+
if (hostFromProps) {
|
|
471
|
+
const existingRule = rules.find((r) => r.host === hostFromProps);
|
|
472
|
+
if (existingRule) {
|
|
473
|
+
existingRule.http.paths.push({
|
|
474
|
+
path: childEl.props.path,
|
|
475
|
+
pathType: childEl.props.pathType || 'Prefix',
|
|
476
|
+
backend: {
|
|
477
|
+
service: {
|
|
478
|
+
name: childEl.props.service,
|
|
479
|
+
port: { number: childEl.props.port },
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
rules.push({
|
|
486
|
+
host: hostFromProps,
|
|
487
|
+
http: {
|
|
488
|
+
paths: [{
|
|
489
|
+
path: childEl.props.path,
|
|
490
|
+
pathType: childEl.props.pathType || 'Prefix',
|
|
491
|
+
backend: {
|
|
492
|
+
service: {
|
|
493
|
+
name: childEl.props.service,
|
|
494
|
+
port: { number: childEl.props.port },
|
|
495
|
+
},
|
|
496
|
+
},
|
|
497
|
+
}],
|
|
498
|
+
},
|
|
499
|
+
});
|
|
500
|
+
if (ssl) {
|
|
501
|
+
tls.push({ hosts: [hostFromProps], secretName: `${name}-tls` });
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return {
|
|
508
|
+
apiVersion: 'networking.k8s.io/v1',
|
|
509
|
+
kind: 'Ingress',
|
|
510
|
+
metadata: { name, namespace, annotations },
|
|
511
|
+
spec: {
|
|
512
|
+
...(className && { ingressClassName: className }),
|
|
513
|
+
rules,
|
|
514
|
+
...(tls.length > 0 && { tls }),
|
|
515
|
+
},
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
function processConfigMap(props, ctx) {
|
|
519
|
+
const name = props.name;
|
|
520
|
+
const namespace = props.namespace || ctx.namespace;
|
|
521
|
+
const data = props.data;
|
|
522
|
+
const labels = props.labels;
|
|
523
|
+
return {
|
|
524
|
+
apiVersion: 'v1',
|
|
525
|
+
kind: 'ConfigMap',
|
|
526
|
+
metadata: { name, namespace, labels },
|
|
527
|
+
data,
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
function processSecret(props, ctx) {
|
|
531
|
+
const name = props.name;
|
|
532
|
+
const namespace = props.namespace || ctx.namespace;
|
|
533
|
+
const type = props.type || 'Opaque';
|
|
534
|
+
const data = props.data;
|
|
535
|
+
const stringData = props.stringData;
|
|
536
|
+
const labels = props.labels;
|
|
537
|
+
return {
|
|
538
|
+
apiVersion: 'v1',
|
|
539
|
+
kind: 'Secret',
|
|
540
|
+
metadata: { name, namespace, labels },
|
|
541
|
+
...(type && { type }),
|
|
542
|
+
...(data && { data }),
|
|
543
|
+
...(stringData && { stringData }),
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
function processPvc(props, ctx) {
|
|
547
|
+
const name = props.name;
|
|
548
|
+
const namespace = props.namespace || ctx.namespace;
|
|
549
|
+
const storage = props.storage;
|
|
550
|
+
const accessModes = props.accessModes || ['ReadWriteOnce'];
|
|
551
|
+
const storageClassName = props.storageClassName;
|
|
552
|
+
const labels = props.labels;
|
|
553
|
+
return {
|
|
554
|
+
apiVersion: 'v1',
|
|
555
|
+
kind: 'PersistentVolumeClaim',
|
|
556
|
+
metadata: { name, namespace, labels },
|
|
557
|
+
spec: {
|
|
558
|
+
accessModes,
|
|
559
|
+
resources: {
|
|
560
|
+
requests: { storage },
|
|
561
|
+
},
|
|
562
|
+
...(storageClassName && { storageClassName }),
|
|
563
|
+
},
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
function processHpa(props, ctx) {
|
|
567
|
+
const name = props.name;
|
|
568
|
+
const namespace = props.namespace || ctx.namespace;
|
|
569
|
+
const target = props.target;
|
|
570
|
+
const minReplicas = props.minReplicas || 1;
|
|
571
|
+
const maxReplicas = props.maxReplicas;
|
|
572
|
+
const targetCpuUtilization = props.targetCpuUtilization;
|
|
573
|
+
const targetMemoryUtilization = props.targetMemoryUtilization;
|
|
574
|
+
const metrics = [];
|
|
575
|
+
if (targetCpuUtilization) {
|
|
576
|
+
metrics.push({
|
|
577
|
+
type: 'Resource',
|
|
578
|
+
resource: {
|
|
579
|
+
name: 'cpu',
|
|
580
|
+
target: { type: 'Utilization', averageUtilization: targetCpuUtilization },
|
|
581
|
+
},
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
if (targetMemoryUtilization) {
|
|
585
|
+
metrics.push({
|
|
586
|
+
type: 'Resource',
|
|
587
|
+
resource: {
|
|
588
|
+
name: 'memory',
|
|
589
|
+
target: { type: 'Utilization', averageUtilization: targetMemoryUtilization },
|
|
590
|
+
},
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
return {
|
|
594
|
+
apiVersion: 'autoscaling/v2',
|
|
595
|
+
kind: 'HorizontalPodAutoscaler',
|
|
596
|
+
metadata: { name, namespace },
|
|
597
|
+
spec: {
|
|
598
|
+
scaleTargetRef: {
|
|
599
|
+
apiVersion: 'apps/v1',
|
|
600
|
+
kind: 'Deployment',
|
|
601
|
+
name: target,
|
|
602
|
+
},
|
|
603
|
+
minReplicas,
|
|
604
|
+
maxReplicas,
|
|
605
|
+
...(metrics.length > 0 && { metrics }),
|
|
606
|
+
},
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
function processJob(props, children, ctx) {
|
|
610
|
+
const name = props.name;
|
|
611
|
+
const namespace = props.namespace || ctx.namespace;
|
|
612
|
+
const backoffLimit = props.backoffLimit;
|
|
613
|
+
const ttlSecondsAfterFinished = props.ttlSecondsAfterFinished;
|
|
614
|
+
const labels = props.labels;
|
|
615
|
+
const containers = [];
|
|
616
|
+
const volumes = [];
|
|
617
|
+
for (const child of children) {
|
|
618
|
+
processDeploymentChild(child, containers, volumes, ctx);
|
|
619
|
+
}
|
|
620
|
+
return [{
|
|
621
|
+
apiVersion: 'batch/v1',
|
|
622
|
+
kind: 'Job',
|
|
623
|
+
metadata: { name, namespace, labels },
|
|
624
|
+
spec: {
|
|
625
|
+
...(backoffLimit !== undefined && { backoffLimit }),
|
|
626
|
+
...(ttlSecondsAfterFinished !== undefined && { ttlSecondsAfterFinished }),
|
|
627
|
+
template: {
|
|
628
|
+
spec: {
|
|
629
|
+
containers,
|
|
630
|
+
restartPolicy: 'Never',
|
|
631
|
+
...(volumes.length > 0 && { volumes }),
|
|
632
|
+
},
|
|
633
|
+
},
|
|
634
|
+
},
|
|
635
|
+
}];
|
|
636
|
+
}
|
|
637
|
+
function processCronJob(props, children, ctx) {
|
|
638
|
+
const name = props.name;
|
|
639
|
+
const namespace = props.namespace || ctx.namespace;
|
|
640
|
+
const schedule = props.schedule;
|
|
641
|
+
const concurrencyPolicy = props.concurrencyPolicy;
|
|
642
|
+
const suspend = props.suspend;
|
|
643
|
+
const labels = props.labels;
|
|
644
|
+
const containers = [];
|
|
645
|
+
const volumes = [];
|
|
646
|
+
for (const child of children) {
|
|
647
|
+
processDeploymentChild(child, containers, volumes, ctx);
|
|
648
|
+
}
|
|
649
|
+
return [{
|
|
650
|
+
apiVersion: 'batch/v1',
|
|
651
|
+
kind: 'CronJob',
|
|
652
|
+
metadata: { name, namespace, labels },
|
|
653
|
+
spec: {
|
|
654
|
+
schedule,
|
|
655
|
+
...(concurrencyPolicy && { concurrencyPolicy }),
|
|
656
|
+
...(suspend !== undefined && { suspend }),
|
|
657
|
+
jobTemplate: {
|
|
658
|
+
spec: {
|
|
659
|
+
template: {
|
|
660
|
+
spec: {
|
|
661
|
+
containers,
|
|
662
|
+
restartPolicy: 'Never',
|
|
663
|
+
...(volumes.length > 0 && { volumes }),
|
|
664
|
+
},
|
|
665
|
+
},
|
|
666
|
+
},
|
|
667
|
+
},
|
|
668
|
+
},
|
|
669
|
+
}];
|
|
670
|
+
}
|
|
671
|
+
function processServiceAccount(props, ctx) {
|
|
672
|
+
const name = props.name;
|
|
673
|
+
const namespace = props.namespace || ctx.namespace;
|
|
674
|
+
const labels = props.labels;
|
|
675
|
+
return {
|
|
676
|
+
apiVersion: 'v1',
|
|
677
|
+
kind: 'ServiceAccount',
|
|
678
|
+
metadata: { name, namespace, labels },
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
function processRole(props, ctx) {
|
|
682
|
+
const name = props.name;
|
|
683
|
+
const namespace = props.namespace || ctx.namespace;
|
|
684
|
+
const rules = props.rules;
|
|
685
|
+
const labels = props.labels;
|
|
686
|
+
return {
|
|
687
|
+
apiVersion: 'rbac.authorization.k8s.io/v1',
|
|
688
|
+
kind: 'Role',
|
|
689
|
+
metadata: { name, namespace, labels },
|
|
690
|
+
rules,
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
function processClusterRole(props, ctx) {
|
|
694
|
+
const name = props.name;
|
|
695
|
+
const rules = props.rules;
|
|
696
|
+
const labels = props.labels;
|
|
697
|
+
return {
|
|
698
|
+
apiVersion: 'rbac.authorization.k8s.io/v1',
|
|
699
|
+
kind: 'ClusterRole',
|
|
700
|
+
metadata: { name, labels },
|
|
701
|
+
rules,
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
function processRoleBinding(props, ctx) {
|
|
705
|
+
const name = props.name;
|
|
706
|
+
const namespace = props.namespace || ctx.namespace;
|
|
707
|
+
const roleRef = props.roleRef;
|
|
708
|
+
const subjects = props.subjects;
|
|
709
|
+
return {
|
|
710
|
+
apiVersion: 'rbac.authorization.k8s.io/v1',
|
|
711
|
+
kind: 'RoleBinding',
|
|
712
|
+
metadata: { name, namespace },
|
|
713
|
+
roleRef: {
|
|
714
|
+
apiGroup: 'rbac.authorization.k8s.io',
|
|
715
|
+
kind: roleRef.kind,
|
|
716
|
+
name: roleRef.name,
|
|
717
|
+
},
|
|
718
|
+
subjects: subjects.map(s => ({
|
|
719
|
+
kind: s.kind,
|
|
720
|
+
name: s.name,
|
|
721
|
+
...(s.namespace && { namespace: s.namespace }),
|
|
722
|
+
})),
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
function processClusterRoleBinding(props, ctx) {
|
|
726
|
+
const name = props.name;
|
|
727
|
+
const roleRef = props.roleRef;
|
|
728
|
+
const subjects = props.subjects;
|
|
729
|
+
return {
|
|
730
|
+
apiVersion: 'rbac.authorization.k8s.io/v1',
|
|
731
|
+
kind: 'ClusterRoleBinding',
|
|
732
|
+
metadata: { name },
|
|
733
|
+
roleRef: {
|
|
734
|
+
apiGroup: 'rbac.authorization.k8s.io',
|
|
735
|
+
kind: roleRef.kind,
|
|
736
|
+
name: roleRef.name,
|
|
737
|
+
},
|
|
738
|
+
subjects: subjects.map(s => ({
|
|
739
|
+
kind: s.kind,
|
|
740
|
+
name: s.name,
|
|
741
|
+
...(s.namespace && { namespace: s.namespace }),
|
|
742
|
+
})),
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
export default render;
|
|
746
|
+
//# sourceMappingURL=render.js.map
|