kustodian 1.5.2 → 1.6.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/README.md +3 -0
- package/dist/cli/bin.js +5 -1
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/apply.d.ts.map +1 -1
- package/dist/cli/commands/apply.js +87 -153
- package/dist/cli/commands/apply.js.map +1 -1
- package/dist/cli/commands/diff.d.ts +12 -0
- package/dist/cli/commands/diff.d.ts.map +1 -0
- package/dist/cli/commands/diff.js +276 -0
- package/dist/cli/commands/diff.js.map +1 -0
- package/dist/cli/commands/kubeconfig.d.ts.map +1 -1
- package/dist/cli/commands/kubeconfig.js +10 -39
- package/dist/cli/commands/kubeconfig.js.map +1 -1
- package/dist/cli/commands/preview.d.ts +5 -0
- package/dist/cli/commands/preview.d.ts.map +1 -0
- package/dist/cli/commands/preview.js +243 -0
- package/dist/cli/commands/preview.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/runner.d.ts.map +1 -1
- package/dist/cli/runner.js +40 -9
- package/dist/cli/runner.js.map +1 -1
- package/dist/cli/utils/defaults.d.ts +1 -0
- package/dist/cli/utils/defaults.d.ts.map +1 -1
- package/dist/cli/utils/defaults.js +4 -0
- package/dist/cli/utils/defaults.js.map +1 -1
- package/dist/cli/utils/k0s-provider.d.ts +35 -0
- package/dist/cli/utils/k0s-provider.d.ts.map +1 -0
- package/dist/cli/utils/k0s-provider.js +53 -0
- package/dist/cli/utils/k0s-provider.js.map +1 -0
- package/dist/cli/utils/k8s-errors.d.ts +12 -0
- package/dist/cli/utils/k8s-errors.d.ts.map +1 -0
- package/dist/cli/utils/k8s-errors.js +22 -0
- package/dist/cli/utils/k8s-errors.js.map +1 -0
- package/dist/cli/utils/oci.d.ts +19 -0
- package/dist/cli/utils/oci.d.ts.map +1 -0
- package/dist/cli/utils/oci.js +80 -0
- package/dist/cli/utils/oci.js.map +1 -0
- package/dist/cli/utils/project.d.ts +18 -0
- package/dist/cli/utils/project.d.ts.map +1 -0
- package/dist/cli/utils/project.js +51 -0
- package/dist/cli/utils/project.js.map +1 -0
- package/dist/cli/utils/validation.d.ts +13 -0
- package/dist/cli/utils/validation.d.ts.map +1 -0
- package/dist/cli/utils/validation.js +30 -0
- package/dist/cli/utils/validation.js.map +1 -0
- package/dist/generator/flux.d.ts +5 -1
- package/dist/generator/flux.d.ts.map +1 -1
- package/dist/generator/flux.js +104 -9
- package/dist/generator/flux.js.map +1 -1
- package/dist/generator/generator.d.ts +4 -2
- package/dist/generator/generator.d.ts.map +1 -1
- package/dist/generator/generator.js +4 -3
- package/dist/generator/generator.js.map +1 -1
- package/dist/generator/output.d.ts +5 -0
- package/dist/generator/output.d.ts.map +1 -1
- package/dist/generator/output.js +58 -0
- package/dist/generator/output.js.map +1 -1
- package/dist/k8s/exec.d.ts +7 -0
- package/dist/k8s/exec.d.ts.map +1 -1
- package/dist/k8s/exec.js +90 -7
- package/dist/k8s/exec.js.map +1 -1
- package/dist/k8s/flux.d.ts +5 -1
- package/dist/k8s/flux.d.ts.map +1 -1
- package/dist/k8s/flux.js +40 -0
- package/dist/k8s/flux.js.map +1 -1
- package/dist/k8s/kubeconfig.d.ts.map +1 -1
- package/dist/k8s/kubeconfig.js +23 -31
- package/dist/k8s/kubeconfig.js.map +1 -1
- package/dist/k8s/kubectl.d.ts +5 -1
- package/dist/k8s/kubectl.d.ts.map +1 -1
- package/dist/k8s/kubectl.js +32 -31
- package/dist/k8s/kubectl.js.map +1 -1
- package/dist/k8s/types.d.ts +21 -0
- package/dist/k8s/types.d.ts.map +1 -1
- package/dist/registry/helm.d.ts.map +1 -1
- package/dist/registry/helm.js +49 -2
- package/dist/registry/helm.js.map +1 -1
- package/dist/schema/cluster.d.ts +2670 -160
- package/dist/schema/cluster.d.ts.map +1 -1
- package/dist/schema/cluster.js +24 -1
- package/dist/schema/cluster.js.map +1 -1
- package/dist/schema/project.d.ts +18 -0
- package/dist/schema/project.d.ts.map +1 -1
- package/dist/schema/project.js +2 -0
- package/dist/schema/project.js.map +1 -1
- package/dist/schema/template.d.ts +24 -24
- package/dist/sources/cache/index.js +2 -0
- package/dist/sources/cache/index.js.map +1 -1
- package/dist/sources/fetchers/git.js +68 -33
- package/dist/sources/fetchers/git.js.map +1 -1
- package/dist/sources/fetchers/http.js +9 -9
- package/dist/sources/fetchers/http.js.map +1 -1
- package/dist/sources/fetchers/oci.js +12 -9
- package/dist/sources/fetchers/oci.js.map +1 -1
- package/dist/sources/resolver.js +4 -4
- package/dist/sources/resolver.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { mkdtemp, rm, unlink, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { is_success, success } from '../../core/index.js';
|
|
5
|
+
import { create_generator, serialize_resource } from '../../generator/index.js';
|
|
6
|
+
import { create_flux_client } from '../../k8s/flux.js';
|
|
7
|
+
import { create_kubectl_client } from '../../k8s/kubectl.js';
|
|
8
|
+
import { define_command } from '../command.js';
|
|
9
|
+
import { OCI_REGISTRY_PROVIDER } from '../utils/cluster-secrets.js';
|
|
10
|
+
import { resolve_defaults } from '../utils/defaults.js';
|
|
11
|
+
import { build_node_list, create_k0s_provider_instance, resolve_k0s_provider_options, } from '../utils/k0s-provider.js';
|
|
12
|
+
import { is_not_found_error } from '../utils/k8s-errors.js';
|
|
13
|
+
import { create_namespace_manifest, create_registry_secret_manifest, get_oci_tag, get_provider_token_from_env, } from '../utils/oci.js';
|
|
14
|
+
import { load_and_resolve_project, sanitize_filename_part } from '../utils/project.js';
|
|
15
|
+
import { validate_cluster_template_requirements } from '../utils/validation.js';
|
|
16
|
+
/**
|
|
17
|
+
* Diff command - previews cluster changes without applying:
|
|
18
|
+
* 1. Diff Flux control-plane resources with kubectl diff
|
|
19
|
+
* 2. Diff rendered workloads with flux diff kustomization
|
|
20
|
+
*
|
|
21
|
+
* Exit codes follow Unix diff convention:
|
|
22
|
+
* 0 = no changes detected
|
|
23
|
+
* 1 = changes detected (not an error)
|
|
24
|
+
* 2 = error occurred
|
|
25
|
+
*/
|
|
26
|
+
export const diff_command = define_command({
|
|
27
|
+
name: 'diff',
|
|
28
|
+
description: 'Preview cluster changes without applying them',
|
|
29
|
+
options: [
|
|
30
|
+
{
|
|
31
|
+
name: 'cluster',
|
|
32
|
+
short: 'c',
|
|
33
|
+
description: 'Cluster name to diff (defaults to all clusters)',
|
|
34
|
+
type: 'string',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'provider',
|
|
38
|
+
short: 'P',
|
|
39
|
+
description: 'Cluster provider for kubeconfig retrieval',
|
|
40
|
+
type: 'string',
|
|
41
|
+
default_value: 'k0s',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'project',
|
|
45
|
+
short: 'p',
|
|
46
|
+
description: 'Path to project root',
|
|
47
|
+
type: 'string',
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
handler: async (ctx) => {
|
|
51
|
+
const cluster_filter = ctx.options['cluster'];
|
|
52
|
+
const provider_name = ctx.options['provider'];
|
|
53
|
+
const project_path = ctx.options['project'] || process.cwd();
|
|
54
|
+
if (provider_name !== 'k0s') {
|
|
55
|
+
return {
|
|
56
|
+
success: false,
|
|
57
|
+
error: {
|
|
58
|
+
code: 'UNSUPPORTED_PROVIDER',
|
|
59
|
+
message: `Provider '${provider_name}' is not supported for diff`,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
console.log('\n━━━ Kustodian Diff ━━━');
|
|
64
|
+
const project_result = await load_and_resolve_project(project_path, cluster_filter);
|
|
65
|
+
if (!is_success(project_result)) {
|
|
66
|
+
return project_result;
|
|
67
|
+
}
|
|
68
|
+
const { project_root, project, target_clusters } = project_result.value;
|
|
69
|
+
let has_changes = false;
|
|
70
|
+
for (const loaded_cluster of target_clusters) {
|
|
71
|
+
const cluster_name = loaded_cluster.cluster.metadata.name;
|
|
72
|
+
const defaults = resolve_defaults(loaded_cluster.cluster, project.config);
|
|
73
|
+
const flux_namespace = defaults.flux_namespace;
|
|
74
|
+
const oci_registry_secret_name = defaults.oci_registry_secret_name;
|
|
75
|
+
console.log(`\n━━━ Cluster: ${cluster_name} ━━━`);
|
|
76
|
+
console.log(` Provider: ${provider_name}`);
|
|
77
|
+
console.log(` ✓ Loaded ${loaded_cluster.nodes.length} nodes`);
|
|
78
|
+
if (!loaded_cluster.cluster.spec.oci) {
|
|
79
|
+
process.exitCode = 2;
|
|
80
|
+
return {
|
|
81
|
+
success: false,
|
|
82
|
+
error: { code: 'INVALID_CONFIG', message: 'spec.oci configuration required' },
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const validation_result = validate_cluster_template_requirements(loaded_cluster, project.templates);
|
|
86
|
+
if (!is_success(validation_result)) {
|
|
87
|
+
process.exitCode = 2;
|
|
88
|
+
return validation_result;
|
|
89
|
+
}
|
|
90
|
+
let temp_kubeconfig;
|
|
91
|
+
let temp_flux_kustomization_dir;
|
|
92
|
+
let provider;
|
|
93
|
+
try {
|
|
94
|
+
const node_list = build_node_list(loaded_cluster);
|
|
95
|
+
const provider_options = resolve_k0s_provider_options(loaded_cluster);
|
|
96
|
+
const provider_instance = await create_k0s_provider_instance(provider_options);
|
|
97
|
+
provider = provider_instance;
|
|
98
|
+
const validate_result = provider_instance.validate(node_list);
|
|
99
|
+
if (!is_success(validate_result)) {
|
|
100
|
+
process.exitCode = 2;
|
|
101
|
+
return validate_result;
|
|
102
|
+
}
|
|
103
|
+
const kubeconfig_result = await provider_instance.get_kubeconfig(node_list);
|
|
104
|
+
if (!is_success(kubeconfig_result)) {
|
|
105
|
+
process.exitCode = 2;
|
|
106
|
+
return kubeconfig_result;
|
|
107
|
+
}
|
|
108
|
+
temp_kubeconfig = path.join(tmpdir(), `kustodian-diff-kubeconfig-${sanitize_filename_part(cluster_name)}.yaml`);
|
|
109
|
+
await writeFile(temp_kubeconfig, kubeconfig_result.value, 'utf-8');
|
|
110
|
+
const client_options = { kubeconfig: temp_kubeconfig };
|
|
111
|
+
const kubectl_client = create_kubectl_client(client_options);
|
|
112
|
+
const flux_client = create_flux_client(client_options);
|
|
113
|
+
const flux_cli_result = await flux_client.check_cli();
|
|
114
|
+
if (!is_success(flux_cli_result) || !flux_cli_result.value) {
|
|
115
|
+
process.exitCode = 2;
|
|
116
|
+
return {
|
|
117
|
+
success: false,
|
|
118
|
+
error: { code: 'MISSING_DEPENDENCY', message: 'flux CLI not found' },
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
const templates_dir = path.join(project_root, 'templates');
|
|
122
|
+
const template_paths = new Map();
|
|
123
|
+
for (const t of project.templates) {
|
|
124
|
+
template_paths.set(t.template.metadata.name, path.relative(templates_dir, t.path));
|
|
125
|
+
}
|
|
126
|
+
const generator = create_generator({
|
|
127
|
+
flux_namespace: defaults.flux_namespace,
|
|
128
|
+
git_repository_name: defaults.oci_repository_name,
|
|
129
|
+
template_paths,
|
|
130
|
+
flux_reconciliation_interval: defaults.flux_reconciliation_interval,
|
|
131
|
+
flux_reconciliation_timeout: defaults.flux_reconciliation_timeout,
|
|
132
|
+
flux_reconciliation_retry_interval: defaults.flux_reconciliation_retry_interval,
|
|
133
|
+
});
|
|
134
|
+
const gen_result = await generator.generate(loaded_cluster.cluster, project.templates.map((t) => t.template), {});
|
|
135
|
+
if (!is_success(gen_result)) {
|
|
136
|
+
process.exitCode = 2;
|
|
137
|
+
return gen_result;
|
|
138
|
+
}
|
|
139
|
+
const gen_data = gen_result.value;
|
|
140
|
+
const tag = await get_oci_tag(loaded_cluster.cluster, project_root);
|
|
141
|
+
let oci_has_auth = false;
|
|
142
|
+
const resources = [];
|
|
143
|
+
const secret_check = await kubectl_client.get({
|
|
144
|
+
kind: 'Secret',
|
|
145
|
+
name: oci_registry_secret_name,
|
|
146
|
+
namespace: flux_namespace,
|
|
147
|
+
});
|
|
148
|
+
if (is_success(secret_check)) {
|
|
149
|
+
oci_has_auth = true;
|
|
150
|
+
}
|
|
151
|
+
else if (!is_not_found_error(secret_check.error.message)) {
|
|
152
|
+
process.exitCode = 2;
|
|
153
|
+
return {
|
|
154
|
+
success: false,
|
|
155
|
+
error: {
|
|
156
|
+
code: 'KUBECTL_GET_ERROR',
|
|
157
|
+
message: `Failed to check OCI secret: ${secret_check.error.message}`,
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
const token = get_provider_token_from_env(OCI_REGISTRY_PROVIDER.env_vars);
|
|
163
|
+
if (token) {
|
|
164
|
+
oci_has_auth = true;
|
|
165
|
+
const namespace_check = await kubectl_client.get({
|
|
166
|
+
kind: 'Namespace',
|
|
167
|
+
name: flux_namespace,
|
|
168
|
+
});
|
|
169
|
+
if (!is_success(namespace_check)) {
|
|
170
|
+
if (is_not_found_error(namespace_check.error.message)) {
|
|
171
|
+
resources.push(create_namespace_manifest(flux_namespace));
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
process.exitCode = 2;
|
|
175
|
+
return {
|
|
176
|
+
success: false,
|
|
177
|
+
error: {
|
|
178
|
+
code: 'KUBECTL_GET_ERROR',
|
|
179
|
+
message: `Failed to check namespace '${flux_namespace}': ${namespace_check.error.message}`,
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
resources.push(create_registry_secret_manifest(loaded_cluster.cluster.spec.oci.registry, token, oci_registry_secret_name, flux_namespace));
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
console.warn(` ⚠ ${OCI_REGISTRY_PROVIDER.skip_warning}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (gen_data.oci_repository) {
|
|
191
|
+
const oci_repo = {
|
|
192
|
+
...gen_data.oci_repository,
|
|
193
|
+
spec: {
|
|
194
|
+
...gen_data.oci_repository.spec,
|
|
195
|
+
ref: { tag },
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
if (oci_has_auth) {
|
|
199
|
+
oci_repo.spec = {
|
|
200
|
+
...oci_repo.spec,
|
|
201
|
+
secretRef: { name: oci_registry_secret_name },
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
resources.push(oci_repo);
|
|
205
|
+
}
|
|
206
|
+
for (const k of gen_data.kustomizations) {
|
|
207
|
+
resources.push(k.flux_kustomization);
|
|
208
|
+
}
|
|
209
|
+
if (resources.length > 0) {
|
|
210
|
+
console.log('\n → Diffing Flux control-plane resources...');
|
|
211
|
+
const object_diff_result = await kubectl_client.diff_stdin(resources.map((resource) => serialize_resource(resource)).join('---\n'));
|
|
212
|
+
if (!is_success(object_diff_result)) {
|
|
213
|
+
process.exitCode = 2;
|
|
214
|
+
return object_diff_result;
|
|
215
|
+
}
|
|
216
|
+
if (object_diff_result.value.stdout) {
|
|
217
|
+
console.log(object_diff_result.value.stdout);
|
|
218
|
+
}
|
|
219
|
+
if (object_diff_result.value.stderr) {
|
|
220
|
+
console.error(object_diff_result.value.stderr);
|
|
221
|
+
}
|
|
222
|
+
if (object_diff_result.value.has_changes) {
|
|
223
|
+
has_changes = true;
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
console.log(' ✓ No Flux object changes');
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
console.log('\n → Diffing rendered workloads...');
|
|
230
|
+
temp_flux_kustomization_dir = await mkdtemp(path.join(tmpdir(), `kustodian-diff-${sanitize_filename_part(cluster_name)}-`));
|
|
231
|
+
for (const generated of gen_data.kustomizations) {
|
|
232
|
+
const flux_kustomization_file = path.join(temp_flux_kustomization_dir, `${generated.name}.yaml`);
|
|
233
|
+
await writeFile(flux_kustomization_file, serialize_resource(generated.flux_kustomization), 'utf-8');
|
|
234
|
+
const local_path = path.join(project_root, generated.path.replace(/^\.\//, ''));
|
|
235
|
+
const workload_diff_result = await flux_client.diff_kustomization(generated.name, {
|
|
236
|
+
path: local_path,
|
|
237
|
+
kustomization_file: flux_kustomization_file,
|
|
238
|
+
namespace: flux_namespace,
|
|
239
|
+
progress_bar: false,
|
|
240
|
+
});
|
|
241
|
+
if (!is_success(workload_diff_result)) {
|
|
242
|
+
process.exitCode = 2;
|
|
243
|
+
return workload_diff_result;
|
|
244
|
+
}
|
|
245
|
+
if (workload_diff_result.value.stdout) {
|
|
246
|
+
console.log(workload_diff_result.value.stdout);
|
|
247
|
+
}
|
|
248
|
+
if (workload_diff_result.value.stderr) {
|
|
249
|
+
console.error(workload_diff_result.value.stderr);
|
|
250
|
+
}
|
|
251
|
+
if (workload_diff_result.value.has_changes) {
|
|
252
|
+
has_changes = true;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
finally {
|
|
257
|
+
await provider?.cleanup?.();
|
|
258
|
+
if (temp_kubeconfig) {
|
|
259
|
+
await unlink(temp_kubeconfig).catch(() => undefined);
|
|
260
|
+
}
|
|
261
|
+
if (temp_flux_kustomization_dir) {
|
|
262
|
+
await rm(temp_flux_kustomization_dir, { recursive: true, force: true }).catch(() => undefined);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (has_changes) {
|
|
267
|
+
process.exitCode = 1;
|
|
268
|
+
console.log('\n━━━ Diff Complete: changes detected ━━━\n');
|
|
269
|
+
return success(undefined);
|
|
270
|
+
}
|
|
271
|
+
process.exitCode = 0;
|
|
272
|
+
console.log('\n━━━ Diff Complete: no changes ━━━\n');
|
|
273
|
+
return success(undefined);
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/cli/commands/diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kubeconfig.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/kubeconfig.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"kubeconfig.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/kubeconfig.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,eAAO,MAAM,kBAAkB,qCA0G7B,CAAC"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as path from 'node:path';
|
|
2
2
|
import { is_success, success } from '../../core/index.js';
|
|
3
3
|
import { create_kubeconfig_manager } from '../../k8s/kubeconfig.js';
|
|
4
|
-
import { find_cluster, find_project_root, load_project } from '../../loader/index.js';
|
|
5
4
|
import { define_command } from '../command.js';
|
|
5
|
+
import { build_node_list, create_k0s_provider_instance, resolve_k0s_provider_options, } from '../utils/k0s-provider.js';
|
|
6
|
+
import { load_and_resolve_project, sanitize_filename_part } from '../utils/project.js';
|
|
6
7
|
/**
|
|
7
8
|
* Kubeconfig command - pulls kubeconfig from a k0s cluster and merges it
|
|
8
9
|
* into the local ~/.kube/config.
|
|
@@ -36,54 +37,24 @@ export const kubeconfig_command = define_command({
|
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
39
|
console.log('\n━━━ Kustodian Kubeconfig ━━━\n');
|
|
39
|
-
|
|
40
|
-
console.log('Loading project configuration...');
|
|
41
|
-
const root_result = await find_project_root(project_path);
|
|
42
|
-
if (!is_success(root_result)) {
|
|
43
|
-
console.error(` ✗ ${root_result.error.message}`);
|
|
44
|
-
return root_result;
|
|
45
|
-
}
|
|
46
|
-
const project_root = root_result.value;
|
|
47
|
-
const project_result = await load_project(project_root);
|
|
40
|
+
const project_result = await load_and_resolve_project(project_path, cluster_filter);
|
|
48
41
|
if (!is_success(project_result)) {
|
|
49
|
-
console.error(` ✗ ${project_result.error.message}`);
|
|
50
42
|
return project_result;
|
|
51
43
|
}
|
|
52
|
-
const
|
|
53
|
-
// Find target cluster
|
|
54
|
-
const loaded_cluster = find_cluster(project.clusters, cluster_filter);
|
|
44
|
+
const loaded_cluster = project_result.value.target_clusters[0];
|
|
55
45
|
if (!loaded_cluster) {
|
|
56
|
-
console.error(` ✗ Cluster '${cluster_filter}' not found`);
|
|
57
46
|
return {
|
|
58
47
|
success: false,
|
|
59
|
-
error: { code: 'NOT_FOUND', message:
|
|
48
|
+
error: { code: 'NOT_FOUND', message: 'No clusters found in project' },
|
|
60
49
|
};
|
|
61
50
|
}
|
|
62
51
|
const cluster_name = loaded_cluster.cluster.metadata.name;
|
|
63
52
|
console.log(` → Cluster: ${cluster_name}`);
|
|
64
53
|
console.log(` → Nodes: ${loaded_cluster.nodes.length}`);
|
|
65
|
-
// Build NodeListType
|
|
66
|
-
const node_list =
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
...(loaded_cluster.cluster.spec.node_defaults?.label_prefix && {
|
|
70
|
-
label_prefix: loaded_cluster.cluster.spec.node_defaults.label_prefix,
|
|
71
|
-
}),
|
|
72
|
-
};
|
|
73
|
-
// Load k0s provider
|
|
74
|
-
const k0s_package = 'kustodian-k0s';
|
|
75
|
-
const { create_k0s_provider } = await import(k0s_package);
|
|
76
|
-
const k0s_plugin = loaded_cluster.cluster.spec.plugins?.find((p) => p.name === 'k0s' || p.name === '@kustodian/plugin-k0s');
|
|
77
|
-
const plugin_config = k0s_plugin?.config ?? {};
|
|
78
|
-
const provider_options = {};
|
|
79
|
-
if (plugin_config['k0s_version']) {
|
|
80
|
-
provider_options['k0s_version'] = plugin_config['k0s_version'];
|
|
81
|
-
}
|
|
82
|
-
if (plugin_config['default_ssh']) {
|
|
83
|
-
provider_options['default_ssh'] = plugin_config['default_ssh'];
|
|
84
|
-
}
|
|
85
|
-
provider_options['cluster_name'] = loaded_cluster.cluster.metadata.code ?? cluster_name;
|
|
86
|
-
const provider = create_k0s_provider(provider_options);
|
|
54
|
+
// Build NodeListType and provider
|
|
55
|
+
const node_list = build_node_list(loaded_cluster);
|
|
56
|
+
const provider_options = resolve_k0s_provider_options(loaded_cluster, { include_all: false });
|
|
57
|
+
const provider = await create_k0s_provider_instance(provider_options);
|
|
87
58
|
// Validate
|
|
88
59
|
console.log('\n → Validating cluster configuration...');
|
|
89
60
|
const validate_result = provider.validate(node_list);
|
|
@@ -102,7 +73,7 @@ export const kubeconfig_command = define_command({
|
|
|
102
73
|
// Write to temp file for merging
|
|
103
74
|
const { writeFile, unlink } = await import('node:fs/promises');
|
|
104
75
|
const { tmpdir } = await import('node:os');
|
|
105
|
-
const temp_kubeconfig = path.join(tmpdir(), `kustodian-kubeconfig-${cluster_name}.yaml`);
|
|
76
|
+
const temp_kubeconfig = path.join(tmpdir(), `kustodian-kubeconfig-${sanitize_filename_part(cluster_name)}.yaml`);
|
|
106
77
|
await writeFile(temp_kubeconfig, kubeconfig_result.value, 'utf-8');
|
|
107
78
|
// Merge into ~/.kube/config
|
|
108
79
|
console.log(' → Merging into ~/.kube/config...');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kubeconfig.js","sourceRoot":"","sources":["../../../src/cli/commands/kubeconfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"kubeconfig.js","sourceRoot":"","sources":["../../../src/cli/commands/kubeconfig.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/preview.ts"],"names":[],"mappings":"AAsGA;;GAEG;AACH,eAAO,MAAM,eAAe,qCA+L1B,CAAC"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { execSync, spawnSync } from 'node:child_process';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import { is_success, success } from '../../core/index.js';
|
|
6
|
+
import { create_generator } from '../../generator/generator.js';
|
|
7
|
+
import { write_generation_result } from '../../generator/output.js';
|
|
8
|
+
import { define_command } from '../command.js';
|
|
9
|
+
import { resolve_defaults } from '../utils/defaults.js';
|
|
10
|
+
import { load_and_resolve_project } from '../utils/project.js';
|
|
11
|
+
function detect_editor() {
|
|
12
|
+
try {
|
|
13
|
+
execSync('command -v nvim', { stdio: 'ignore' });
|
|
14
|
+
return 'nvim';
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return 'vi';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Generates the k0s provider config preview and writes it to the output directory.
|
|
22
|
+
* Returns the written file path, or undefined if not applicable.
|
|
23
|
+
*/
|
|
24
|
+
async function generate_k0s_preview(loaded_cluster, output_dir) {
|
|
25
|
+
const cluster_name = loaded_cluster.cluster.metadata.name;
|
|
26
|
+
// Build NodeListType from loaded cluster
|
|
27
|
+
const node_list = {
|
|
28
|
+
cluster: cluster_name,
|
|
29
|
+
nodes: loaded_cluster.nodes,
|
|
30
|
+
...(loaded_cluster.cluster.spec.node_defaults?.label_prefix && {
|
|
31
|
+
label_prefix: loaded_cluster.cluster.spec.node_defaults.label_prefix,
|
|
32
|
+
}),
|
|
33
|
+
};
|
|
34
|
+
// Load k0s provider with plugin config
|
|
35
|
+
let create_k0s_provider;
|
|
36
|
+
try {
|
|
37
|
+
const k0s_package = 'kustodian-k0s';
|
|
38
|
+
const k0s_module = await import(k0s_package);
|
|
39
|
+
create_k0s_provider = k0s_module.create_k0s_provider;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// k0s package not available, skip
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
// Extract k0s plugin config from cluster spec
|
|
46
|
+
const k0s_plugin = loaded_cluster.cluster.spec.plugins?.find((p) => p.name === 'k0s' || p.name === '@kustodian/plugin-k0s');
|
|
47
|
+
const plugin_config = k0s_plugin?.config ?? {};
|
|
48
|
+
const provider_options = {};
|
|
49
|
+
if (plugin_config['k0s_version']) {
|
|
50
|
+
provider_options['k0s_version'] = plugin_config['k0s_version'];
|
|
51
|
+
}
|
|
52
|
+
if (plugin_config['telemetry_enabled'] !== undefined) {
|
|
53
|
+
provider_options['telemetry_enabled'] = plugin_config['telemetry_enabled'];
|
|
54
|
+
}
|
|
55
|
+
if (plugin_config['dynamic_config'] !== undefined) {
|
|
56
|
+
provider_options['dynamic_config'] = plugin_config['dynamic_config'];
|
|
57
|
+
}
|
|
58
|
+
if (plugin_config['sans']) {
|
|
59
|
+
provider_options['sans'] = plugin_config['sans'];
|
|
60
|
+
}
|
|
61
|
+
if (plugin_config['default_ssh']) {
|
|
62
|
+
provider_options['default_ssh'] = plugin_config['default_ssh'];
|
|
63
|
+
}
|
|
64
|
+
provider_options['cluster_name'] = loaded_cluster.cluster.metadata.code ?? cluster_name;
|
|
65
|
+
const provider = create_k0s_provider(provider_options);
|
|
66
|
+
if (!provider.get_config_preview) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
const preview_result = provider.get_config_preview(node_list);
|
|
70
|
+
if (!preview_result.success) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
// Write k0sctl config to output directory
|
|
74
|
+
const k0s_dir = path.join(output_dir, 'k0s');
|
|
75
|
+
fs.mkdirSync(k0s_dir, { recursive: true });
|
|
76
|
+
const k0s_file = path.join(k0s_dir, 'k0sctl.yaml');
|
|
77
|
+
fs.writeFileSync(k0s_file, preview_result.value, 'utf-8');
|
|
78
|
+
return k0s_file;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Preview command - generates Flux manifests and opens them for inspection.
|
|
82
|
+
*/
|
|
83
|
+
export const preview_command = define_command({
|
|
84
|
+
name: 'preview',
|
|
85
|
+
description: 'Preview generated manifests (Flux + k0s) for a cluster',
|
|
86
|
+
options: [
|
|
87
|
+
{
|
|
88
|
+
name: 'cluster',
|
|
89
|
+
short: 'c',
|
|
90
|
+
description: 'Cluster name or code (defaults to all clusters)',
|
|
91
|
+
type: 'string',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'template',
|
|
95
|
+
short: 't',
|
|
96
|
+
description: 'Filter to specific template(s), comma-separated',
|
|
97
|
+
type: 'string',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'project',
|
|
101
|
+
short: 'p',
|
|
102
|
+
description: 'Path to project root (defaults to current directory)',
|
|
103
|
+
type: 'string',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'output-dir',
|
|
107
|
+
short: 'o',
|
|
108
|
+
description: 'Write to this directory instead of opening in editor',
|
|
109
|
+
type: 'string',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: 'format',
|
|
113
|
+
short: 'f',
|
|
114
|
+
description: 'Output format: yaml or json',
|
|
115
|
+
type: 'string',
|
|
116
|
+
default_value: 'yaml',
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
handler: async (ctx) => {
|
|
120
|
+
const cluster_filter = ctx.options['cluster'];
|
|
121
|
+
const template_filter = ctx.options['template'];
|
|
122
|
+
const project_path = ctx.options['project'] || process.cwd();
|
|
123
|
+
const output_dir_option = ctx.options['output-dir'];
|
|
124
|
+
const format = ctx.options['format'] || 'yaml';
|
|
125
|
+
const project_result = await load_and_resolve_project(project_path, cluster_filter);
|
|
126
|
+
if (!is_success(project_result)) {
|
|
127
|
+
return project_result;
|
|
128
|
+
}
|
|
129
|
+
const { project_root, project, target_clusters } = project_result.value;
|
|
130
|
+
// Filter templates if --template specified
|
|
131
|
+
const template_names = template_filter
|
|
132
|
+
? template_filter.split(',').map((t) => t.trim())
|
|
133
|
+
: undefined;
|
|
134
|
+
let templates = project.templates;
|
|
135
|
+
if (template_names) {
|
|
136
|
+
templates = templates.filter((t) => template_names.includes(t.template.metadata.name));
|
|
137
|
+
if (templates.length === 0) {
|
|
138
|
+
return {
|
|
139
|
+
success: false,
|
|
140
|
+
error: {
|
|
141
|
+
code: 'NOT_FOUND',
|
|
142
|
+
message: `No matching templates found for: ${template_names.join(', ')}`,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const is_multi = target_clusters.length > 1;
|
|
148
|
+
const use_temp = !output_dir_option;
|
|
149
|
+
const base_output_dir = output_dir_option ??
|
|
150
|
+
path.join(tmpdir(), `kustodian-preview-${is_multi ? 'all' : target_clusters[0]?.cluster.metadata.name}`);
|
|
151
|
+
let total_written = 0;
|
|
152
|
+
for (const loaded_cluster of target_clusters) {
|
|
153
|
+
const cluster_name = loaded_cluster.cluster.metadata.name;
|
|
154
|
+
if (is_multi) {
|
|
155
|
+
console.log(`\nGenerating preview for cluster: ${cluster_name}`);
|
|
156
|
+
}
|
|
157
|
+
// Filter the cluster's template list so only selected templates are "enabled"
|
|
158
|
+
let cluster_for_generation = loaded_cluster.cluster;
|
|
159
|
+
if (template_names && cluster_for_generation.spec.templates) {
|
|
160
|
+
cluster_for_generation = {
|
|
161
|
+
...cluster_for_generation,
|
|
162
|
+
spec: {
|
|
163
|
+
...cluster_for_generation.spec,
|
|
164
|
+
templates: cluster_for_generation.spec.templates.filter((t) => template_names.includes(t.name)),
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
const defaults = resolve_defaults(loaded_cluster.cluster, project.config);
|
|
169
|
+
// Build template_paths map
|
|
170
|
+
const templates_dir = path.join(project_root, 'templates');
|
|
171
|
+
const template_paths = new Map();
|
|
172
|
+
for (const t of templates) {
|
|
173
|
+
const relative_path = path.relative(templates_dir, t.path);
|
|
174
|
+
template_paths.set(t.template.metadata.name, relative_path);
|
|
175
|
+
}
|
|
176
|
+
// Determine output directory (use subdirs for multi-cluster)
|
|
177
|
+
const output_dir = is_multi ? path.join(base_output_dir, cluster_name) : base_output_dir;
|
|
178
|
+
// Create generator and generate
|
|
179
|
+
const generator = create_generator({
|
|
180
|
+
flux_namespace: defaults.flux_namespace,
|
|
181
|
+
git_repository_name: defaults.oci_repository_name,
|
|
182
|
+
template_paths,
|
|
183
|
+
flux_reconciliation_interval: defaults.flux_reconciliation_interval,
|
|
184
|
+
flux_reconciliation_timeout: defaults.flux_reconciliation_timeout,
|
|
185
|
+
flux_reconciliation_retry_interval: defaults.flux_reconciliation_retry_interval,
|
|
186
|
+
});
|
|
187
|
+
const gen_result = await generator.generate(cluster_for_generation, templates.map((t) => t.template), { output_dir, skip_validation: !!template_names });
|
|
188
|
+
if (!is_success(gen_result)) {
|
|
189
|
+
console.error(`Error: ${gen_result.error.message}`);
|
|
190
|
+
return gen_result;
|
|
191
|
+
}
|
|
192
|
+
// Write files
|
|
193
|
+
const write_result = await write_generation_result(gen_result.value, { format });
|
|
194
|
+
if (!is_success(write_result)) {
|
|
195
|
+
console.error(`Error: ${write_result.error.message}`);
|
|
196
|
+
return write_result;
|
|
197
|
+
}
|
|
198
|
+
const written_files = write_result.value;
|
|
199
|
+
total_written += written_files.length;
|
|
200
|
+
// Generate k0s manifest if cluster has nodes
|
|
201
|
+
if (loaded_cluster.nodes.length > 0) {
|
|
202
|
+
const k0s_file = await generate_k0s_preview(loaded_cluster, output_dir);
|
|
203
|
+
if (k0s_file) {
|
|
204
|
+
written_files.push(k0s_file);
|
|
205
|
+
total_written += 1;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (!use_temp) {
|
|
209
|
+
console.log(`\nGenerated ${written_files.length} files in ${output_dir}:\n`);
|
|
210
|
+
for (const file of written_files) {
|
|
211
|
+
console.log(` ${path.relative(output_dir, file)}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (!use_temp) {
|
|
216
|
+
return success(undefined);
|
|
217
|
+
}
|
|
218
|
+
// Temp mode: open editor, then clean up
|
|
219
|
+
const editor = process.env['VISUAL'] || process.env['EDITOR'] || detect_editor();
|
|
220
|
+
console.log(`Opening ${editor} with ${total_written} generated manifests...`);
|
|
221
|
+
const cleanup = () => {
|
|
222
|
+
try {
|
|
223
|
+
fs.rmSync(base_output_dir, { recursive: true, force: true });
|
|
224
|
+
console.log(`Cleaned up ${base_output_dir}`);
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
// Best-effort cleanup
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
process.on('SIGINT', cleanup);
|
|
231
|
+
process.on('SIGTERM', cleanup);
|
|
232
|
+
try {
|
|
233
|
+
spawnSync(editor, [base_output_dir], { stdio: 'inherit' });
|
|
234
|
+
}
|
|
235
|
+
finally {
|
|
236
|
+
cleanup();
|
|
237
|
+
process.removeListener('SIGINT', cleanup);
|
|
238
|
+
process.removeListener('SIGTERM', cleanup);
|
|
239
|
+
}
|
|
240
|
+
return success(undefined);
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
//# sourceMappingURL=preview.js.map
|