crossplane-provider-cli 1.0.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 +73 -0
- package/dist/index.js +505 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# crossplane-provider-cli
|
|
2
|
+
|
|
3
|
+
Crossplane provider and composition configuration generator CLI
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g crossplane-provider-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Initialize configuration
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
crossplane-provider init
|
|
17
|
+
crossplane-provider init --template advanced
|
|
18
|
+
crossplane-provider init --output custom-config.json
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Validate configuration
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
crossplane-provider validate
|
|
25
|
+
crossplane-provider validate path/to/config.json
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### View configuration
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
crossplane-provider show
|
|
32
|
+
crossplane-provider show --env production
|
|
33
|
+
crossplane-provider show --json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Modify configuration
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
crossplane-provider set settings.debug true
|
|
40
|
+
crossplane-provider set settings.logLevel \"warn\"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Compare configurations
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
crossplane-provider diff config-dev.json config-prod.json
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### List templates
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
crossplane-provider templates
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Templates
|
|
56
|
+
|
|
57
|
+
| Template | Description |
|
|
58
|
+
|----------|-------------|
|
|
59
|
+
| `minimal` | Bare minimum configuration |
|
|
60
|
+
| `standard` | Recommended defaults for most projects |
|
|
61
|
+
| `advanced` | Full-featured with security, caching, and multi-environment support |
|
|
62
|
+
|
|
63
|
+
## Why crossplane-provider-cli?
|
|
64
|
+
|
|
65
|
+
- **Zero dependencies at runtime** — just `commander` and `chalk`
|
|
66
|
+
- **Template-based** — start with minimal, standard, or advanced presets
|
|
67
|
+
- **Validation built-in** — catch config errors before deployment
|
|
68
|
+
- **Environment-aware** — manage dev/staging/production configs in one file
|
|
69
|
+
- **Diff support** — compare configs across environments
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import * as path from "path";
|
|
8
|
+
import * as yaml from "js-yaml";
|
|
9
|
+
function writeYaml(outDir, filename, obj) {
|
|
10
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
11
|
+
const outPath = path.join(outDir, filename);
|
|
12
|
+
const docs = Array.isArray(obj) ? obj : [obj];
|
|
13
|
+
const content = docs.map((d) => yaml.dump(d, { noRefs: true, lineWidth: 120 })).join("---\n");
|
|
14
|
+
fs.writeFileSync(outPath, content, "utf8");
|
|
15
|
+
console.log(chalk.green(" wrote ") + chalk.cyan(outPath));
|
|
16
|
+
}
|
|
17
|
+
function log(msg) {
|
|
18
|
+
console.log(chalk.bold(msg));
|
|
19
|
+
}
|
|
20
|
+
function buildProvider(cloud, version) {
|
|
21
|
+
const pkgMap = {
|
|
22
|
+
aws: `xpkg.upbound.io/upbound/provider-aws:${version}`,
|
|
23
|
+
gcp: `xpkg.upbound.io/upbound/provider-gcp:${version}`,
|
|
24
|
+
azure: `xpkg.upbound.io/upbound/provider-azure:${version}`
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
apiVersion: "pkg.crossplane.io/v1",
|
|
28
|
+
kind: "Provider",
|
|
29
|
+
metadata: {
|
|
30
|
+
name: `provider-${cloud}`,
|
|
31
|
+
annotations: {
|
|
32
|
+
"crossplane.io/external-name": `provider-${cloud}`
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
spec: {
|
|
36
|
+
package: pkgMap[cloud],
|
|
37
|
+
controllerConfigRef: { name: `provider-${cloud}-controller-config` },
|
|
38
|
+
installationPolicy: "Automatic",
|
|
39
|
+
revisionActivationPolicy: "Automatic"
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function buildControllerConfig(cloud) {
|
|
44
|
+
return {
|
|
45
|
+
apiVersion: "pkg.crossplane.io/v1alpha1",
|
|
46
|
+
kind: "ControllerConfig",
|
|
47
|
+
metadata: {
|
|
48
|
+
name: `provider-${cloud}-controller-config`,
|
|
49
|
+
annotations: {
|
|
50
|
+
"eks.amazonaws.com/role-arn": cloud === "aws" ? "arn:aws:iam::ACCOUNT_ID:role/crossplane-provider-aws" : ""
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
spec: {
|
|
54
|
+
podSecurityContext: { fsGroup: 2e3 },
|
|
55
|
+
resources: {
|
|
56
|
+
limits: { cpu: "500m", memory: "128Mi" },
|
|
57
|
+
requests: { cpu: "100m", memory: "64Mi" }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function buildProviderConfig(cloud) {
|
|
63
|
+
const credSources = {
|
|
64
|
+
aws: {
|
|
65
|
+
source: "InjectedIdentity"
|
|
66
|
+
},
|
|
67
|
+
gcp: {
|
|
68
|
+
source: "Secret",
|
|
69
|
+
secretRef: {
|
|
70
|
+
namespace: "crossplane-system",
|
|
71
|
+
name: "gcp-credentials",
|
|
72
|
+
key: "credentials.json"
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
azure: {
|
|
76
|
+
source: "Secret",
|
|
77
|
+
secretRef: {
|
|
78
|
+
namespace: "crossplane-system",
|
|
79
|
+
name: "azure-credentials",
|
|
80
|
+
key: "credentials"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
apiVersion: `${cloud}.upbound.io/v1beta1`,
|
|
86
|
+
kind: "ProviderConfig",
|
|
87
|
+
metadata: {
|
|
88
|
+
name: `${cloud}-provider-config`
|
|
89
|
+
},
|
|
90
|
+
spec: {
|
|
91
|
+
credentials: credSources[cloud]
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function initCommand() {
|
|
96
|
+
return new Command("init").description("Generate Provider and ProviderConfig manifests for AWS, GCP, or Azure").requiredOption("-c, --cloud <cloud>", "Cloud provider: aws | gcp | azure").option("-v, --version <version>", "Provider package version", "v0.43.1").option("-o, --out <dir>", "Output directory", "./crossplane").action((opts) => {
|
|
97
|
+
const cloud = opts.cloud.toLowerCase();
|
|
98
|
+
if (!["aws", "gcp", "azure"].includes(cloud)) {
|
|
99
|
+
console.error(chalk.red(`Unknown cloud provider: ${opts.cloud}`));
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
log(`
|
|
103
|
+
Initialising Crossplane provider manifests for ${chalk.bold(cloud.toUpperCase())}...
|
|
104
|
+
`);
|
|
105
|
+
const outDir = path.resolve(opts.out, cloud);
|
|
106
|
+
writeYaml(outDir, "provider.yaml", buildProvider(cloud, opts.version));
|
|
107
|
+
writeYaml(outDir, "controller-config.yaml", buildControllerConfig(cloud));
|
|
108
|
+
writeYaml(outDir, "provider-config.yaml", buildProviderConfig(cloud));
|
|
109
|
+
console.log(chalk.green("\nDone. Edit credentials refs before applying.\n"));
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function buildXRD(group, kind, claimKind, version) {
|
|
113
|
+
const plural = kind.toLowerCase() + "s";
|
|
114
|
+
const claimPlural = claimKind.toLowerCase() + "s";
|
|
115
|
+
return {
|
|
116
|
+
apiVersion: "apiextensions.crossplane.io/v1",
|
|
117
|
+
kind: "CompositeResourceDefinition",
|
|
118
|
+
metadata: {
|
|
119
|
+
name: `${plural}.${group}`
|
|
120
|
+
},
|
|
121
|
+
spec: {
|
|
122
|
+
group,
|
|
123
|
+
names: { kind, plural },
|
|
124
|
+
claimNames: { kind: claimKind, plural: claimPlural },
|
|
125
|
+
versions: [
|
|
126
|
+
{
|
|
127
|
+
name: version,
|
|
128
|
+
served: true,
|
|
129
|
+
referenceable: true,
|
|
130
|
+
schema: {
|
|
131
|
+
openAPIV3Schema: {
|
|
132
|
+
type: "object",
|
|
133
|
+
properties: {
|
|
134
|
+
spec: {
|
|
135
|
+
type: "object",
|
|
136
|
+
properties: {
|
|
137
|
+
parameters: {
|
|
138
|
+
type: "object",
|
|
139
|
+
description: "Parameters for the composite resource",
|
|
140
|
+
properties: {
|
|
141
|
+
region: { type: "string", description: "Cloud region", default: "us-east-1" },
|
|
142
|
+
environment: {
|
|
143
|
+
type: "string",
|
|
144
|
+
description: "Deployment environment",
|
|
145
|
+
enum: ["dev", "staging", "prod"]
|
|
146
|
+
},
|
|
147
|
+
size: {
|
|
148
|
+
type: "string",
|
|
149
|
+
description: "T-shirt size for resource allocation",
|
|
150
|
+
enum: ["small", "medium", "large"],
|
|
151
|
+
default: "small"
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
required: ["region", "environment"]
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
required: ["parameters"]
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function buildComposition(group, kind, cloud, version) {
|
|
168
|
+
const plural = kind.toLowerCase() + "s";
|
|
169
|
+
const apiVersionMap = {
|
|
170
|
+
aws: "s3.aws.upbound.io/v1beta1",
|
|
171
|
+
gcp: "storage.gcp.upbound.io/v1beta1",
|
|
172
|
+
azure: "storage.azure.upbound.io/v1beta1"
|
|
173
|
+
};
|
|
174
|
+
const kindMap = {
|
|
175
|
+
aws: "Bucket",
|
|
176
|
+
gcp: "Bucket",
|
|
177
|
+
azure: "Account"
|
|
178
|
+
};
|
|
179
|
+
const providerConfigRefMap = {
|
|
180
|
+
aws: "aws-provider-config",
|
|
181
|
+
gcp: "gcp-provider-config",
|
|
182
|
+
azure: "azure-provider-config"
|
|
183
|
+
};
|
|
184
|
+
return {
|
|
185
|
+
apiVersion: "apiextensions.crossplane.io/v1",
|
|
186
|
+
kind: "Composition",
|
|
187
|
+
metadata: {
|
|
188
|
+
name: `${plural}-${cloud}`,
|
|
189
|
+
labels: {
|
|
190
|
+
"crossplane.io/xrd": `${plural}.${group}`,
|
|
191
|
+
provider: cloud
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
spec: {
|
|
195
|
+
compositeTypeRef: { apiVersion: `${group}/${version}`, kind },
|
|
196
|
+
mode: "Pipeline",
|
|
197
|
+
pipeline: [
|
|
198
|
+
{
|
|
199
|
+
step: "patch-and-transform",
|
|
200
|
+
functionRef: { name: "function-patch-and-transform" },
|
|
201
|
+
input: {
|
|
202
|
+
apiVersion: "pt.fn.crossplane.io/v1beta1",
|
|
203
|
+
kind: "Resources",
|
|
204
|
+
resources: [
|
|
205
|
+
{
|
|
206
|
+
name: `${cloud}-resource`,
|
|
207
|
+
base: {
|
|
208
|
+
apiVersion: apiVersionMap[cloud],
|
|
209
|
+
kind: kindMap[cloud],
|
|
210
|
+
spec: {
|
|
211
|
+
forProvider: {
|
|
212
|
+
region: "us-east-1"
|
|
213
|
+
},
|
|
214
|
+
providerConfigRef: { name: providerConfigRefMap[cloud] }
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
patches: [
|
|
218
|
+
{
|
|
219
|
+
type: "FromCompositeFieldPath",
|
|
220
|
+
fromFieldPath: "spec.parameters.region",
|
|
221
|
+
toFieldPath: "spec.forProvider.region"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
type: "FromCompositeFieldPath",
|
|
225
|
+
fromFieldPath: "metadata.name",
|
|
226
|
+
toFieldPath: "metadata.name",
|
|
227
|
+
transforms: [
|
|
228
|
+
{
|
|
229
|
+
type: "string",
|
|
230
|
+
string: { type: "Format", fmt: "%s-resource" }
|
|
231
|
+
}
|
|
232
|
+
]
|
|
233
|
+
}
|
|
234
|
+
]
|
|
235
|
+
}
|
|
236
|
+
]
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
]
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function compositionCommand() {
|
|
244
|
+
return new Command("composition").description("Generate a Composition and CompositeResourceDefinition (XRD)").requiredOption("-g, --group <group>", "API group, e.g. platform.example.com").requiredOption("-k, --kind <kind>", "Composite resource kind, e.g. XDatabase").option("--claim-kind <claimKind>", "Claim kind (defaults to Kind without X prefix)").option("-c, --cloud <cloud>", "Target cloud provider: aws | gcp | azure", "aws").option("--version <version>", "CRD version", "v1alpha1").option("-o, --out <dir>", "Output directory", "./crossplane/compositions").action(
|
|
245
|
+
(opts) => {
|
|
246
|
+
const cloud = opts.cloud.toLowerCase();
|
|
247
|
+
const claimKind = opts.claimKind ?? opts.kind.replace(/^X/, "");
|
|
248
|
+
log(`
|
|
249
|
+
Generating Composition for ${chalk.bold(opts.kind)} (${cloud.toUpperCase()})...
|
|
250
|
+
`);
|
|
251
|
+
const outDir = path.resolve(opts.out);
|
|
252
|
+
writeYaml(outDir, `xrd-${opts.kind.toLowerCase()}.yaml`, buildXRD(opts.group, opts.kind, claimKind, opts.version));
|
|
253
|
+
writeYaml(outDir, `composition-${opts.kind.toLowerCase()}-${cloud}.yaml`, buildComposition(opts.group, opts.kind, cloud, opts.version));
|
|
254
|
+
console.log(chalk.green("\nDone. Register the Composition Functions before applying.\n"));
|
|
255
|
+
}
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
function buildClaim(group, claimKind, name, namespace, region, env, size, version) {
|
|
259
|
+
return {
|
|
260
|
+
apiVersion: `${group}/${version}`,
|
|
261
|
+
kind: claimKind,
|
|
262
|
+
metadata: {
|
|
263
|
+
name,
|
|
264
|
+
namespace,
|
|
265
|
+
labels: {
|
|
266
|
+
environment: env,
|
|
267
|
+
"managed-by": "crossplane"
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
spec: {
|
|
271
|
+
parameters: {
|
|
272
|
+
region,
|
|
273
|
+
environment: env,
|
|
274
|
+
size
|
|
275
|
+
},
|
|
276
|
+
compositionSelector: {
|
|
277
|
+
matchLabels: {
|
|
278
|
+
"crossplane.io/xrd": `${claimKind.toLowerCase()}s.${group}`
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
writeConnectionSecretToRef: {
|
|
282
|
+
name: `${name}-connection`
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
function claimCommand() {
|
|
288
|
+
return new Command("claim").description("Generate a Claim manifest for an infrastructure request").requiredOption("-g, --group <group>", "API group, e.g. platform.example.com").requiredOption("-k, --kind <kind>", "Claim kind, e.g. Database").option("-n, --name <name>", "Resource name", "my-resource").option("--namespace <ns>", "Kubernetes namespace", "default").option("-r, --region <region>", "Cloud region", "us-east-1").option("-e, --env <env>", "Environment: dev | staging | prod", "dev").option("-s, --size <size>", "Size: small | medium | large", "small").option("--version <version>", "API version", "v1alpha1").option("-o, --out <dir>", "Output directory", "./crossplane/claims").action(
|
|
289
|
+
(opts) => {
|
|
290
|
+
log(`
|
|
291
|
+
Generating Claim: ${chalk.bold(opts.name)} (${opts.kind})...
|
|
292
|
+
`);
|
|
293
|
+
const outDir = path.resolve(opts.out);
|
|
294
|
+
const claim = buildClaim(
|
|
295
|
+
opts.group,
|
|
296
|
+
opts.kind,
|
|
297
|
+
opts.name,
|
|
298
|
+
opts.namespace,
|
|
299
|
+
opts.region,
|
|
300
|
+
opts.env,
|
|
301
|
+
opts.size,
|
|
302
|
+
opts.version
|
|
303
|
+
);
|
|
304
|
+
writeYaml(outDir, `claim-${opts.name}.yaml`, claim);
|
|
305
|
+
console.log(chalk.green("\nDone.\n"));
|
|
306
|
+
}
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
function buildFunctionPAT() {
|
|
310
|
+
return {
|
|
311
|
+
apiVersion: "pkg.crossplane.io/v1beta1",
|
|
312
|
+
kind: "Function",
|
|
313
|
+
metadata: {
|
|
314
|
+
name: "function-patch-and-transform",
|
|
315
|
+
annotations: {
|
|
316
|
+
"pkg.crossplane.io/revision-history-limit": "3"
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
spec: {
|
|
320
|
+
package: "xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.5.0",
|
|
321
|
+
installationPolicy: "Automatic",
|
|
322
|
+
revisionActivationPolicy: "Automatic"
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function buildFunctionGoTemplate() {
|
|
327
|
+
return {
|
|
328
|
+
apiVersion: "pkg.crossplane.io/v1beta1",
|
|
329
|
+
kind: "Function",
|
|
330
|
+
metadata: {
|
|
331
|
+
name: "function-go-templating"
|
|
332
|
+
},
|
|
333
|
+
spec: {
|
|
334
|
+
package: "xpkg.upbound.io/crossplane-contrib/function-go-templating:v0.4.1",
|
|
335
|
+
installationPolicy: "Automatic",
|
|
336
|
+
revisionActivationPolicy: "Automatic"
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
function buildFunctionAutoReady() {
|
|
341
|
+
return {
|
|
342
|
+
apiVersion: "pkg.crossplane.io/v1beta1",
|
|
343
|
+
kind: "Function",
|
|
344
|
+
metadata: {
|
|
345
|
+
name: "function-auto-ready"
|
|
346
|
+
},
|
|
347
|
+
spec: {
|
|
348
|
+
package: "xpkg.upbound.io/crossplane-contrib/function-auto-ready:v0.2.1",
|
|
349
|
+
installationPolicy: "Automatic",
|
|
350
|
+
revisionActivationPolicy: "Automatic"
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
function buildFunctionKCL() {
|
|
355
|
+
return {
|
|
356
|
+
apiVersion: "pkg.crossplane.io/v1beta1",
|
|
357
|
+
kind: "Function",
|
|
358
|
+
metadata: {
|
|
359
|
+
name: "function-kcl"
|
|
360
|
+
},
|
|
361
|
+
spec: {
|
|
362
|
+
package: "xpkg.upbound.io/crossplane-contrib/function-kcl:v0.9.4",
|
|
363
|
+
installationPolicy: "Automatic",
|
|
364
|
+
revisionActivationPolicy: "Automatic"
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
function buildFunctionExtraResources() {
|
|
369
|
+
return {
|
|
370
|
+
apiVersion: "pkg.crossplane.io/v1beta1",
|
|
371
|
+
kind: "Function",
|
|
372
|
+
metadata: {
|
|
373
|
+
name: "function-extra-resources"
|
|
374
|
+
},
|
|
375
|
+
spec: {
|
|
376
|
+
package: "xpkg.upbound.io/crossplane-contrib/function-extra-resources:v0.1.0",
|
|
377
|
+
installationPolicy: "Automatic",
|
|
378
|
+
revisionActivationPolicy: "Automatic"
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
function functionCommand() {
|
|
383
|
+
return new Command("function").description("Generate composition Function pipeline configuration manifests").option(
|
|
384
|
+
"-f, --fn <name>",
|
|
385
|
+
"Function name: patch-and-transform | go-templating | auto-ready | kcl | extra-resources | all",
|
|
386
|
+
"all"
|
|
387
|
+
).option("-o, --out <dir>", "Output directory", "./crossplane/functions").action((opts) => {
|
|
388
|
+
const fnName = opts.fn;
|
|
389
|
+
const outDir = path.resolve(opts.out);
|
|
390
|
+
log(`
|
|
391
|
+
Generating Function manifests (${chalk.bold(fnName)})...
|
|
392
|
+
`);
|
|
393
|
+
const fnMap = {
|
|
394
|
+
"patch-and-transform": buildFunctionPAT,
|
|
395
|
+
"go-templating": buildFunctionGoTemplate,
|
|
396
|
+
"auto-ready": buildFunctionAutoReady,
|
|
397
|
+
kcl: buildFunctionKCL,
|
|
398
|
+
"extra-resources": buildFunctionExtraResources
|
|
399
|
+
};
|
|
400
|
+
if (fnName === "all") {
|
|
401
|
+
for (const [name, builder] of Object.entries(fnMap)) {
|
|
402
|
+
writeYaml(outDir, `function-${name}.yaml`, builder());
|
|
403
|
+
}
|
|
404
|
+
} else if (fnMap[fnName]) {
|
|
405
|
+
writeYaml(outDir, `function-${fnName}.yaml`, fnMap[fnName]());
|
|
406
|
+
} else {
|
|
407
|
+
console.error(chalk.red(`Unknown function: ${fnName}`));
|
|
408
|
+
process.exit(1);
|
|
409
|
+
}
|
|
410
|
+
console.log(chalk.green("\nDone.\n"));
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
function buildEnvironmentConfig(env, cloud, region, accountId) {
|
|
414
|
+
const regionMap = {
|
|
415
|
+
aws: { dev: "us-east-1", staging: "us-east-2", prod: "us-west-2" },
|
|
416
|
+
gcp: { dev: "us-central1", staging: "us-east1", prod: "us-east4" },
|
|
417
|
+
azure: { dev: "eastus", staging: "eastus2", prod: "westus2" }
|
|
418
|
+
};
|
|
419
|
+
const defaultRegion = region || regionMap[cloud][env];
|
|
420
|
+
const policyMap = {
|
|
421
|
+
dev: {
|
|
422
|
+
deletionPolicy: "Delete",
|
|
423
|
+
managementPolicies: ["*"]
|
|
424
|
+
},
|
|
425
|
+
staging: {
|
|
426
|
+
deletionPolicy: "Delete",
|
|
427
|
+
managementPolicies: ["Observe", "Create", "Update", "Delete"]
|
|
428
|
+
},
|
|
429
|
+
prod: {
|
|
430
|
+
deletionPolicy: "Orphan",
|
|
431
|
+
managementPolicies: ["Observe", "Create", "Update"]
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
const cloudSpecific = {
|
|
435
|
+
aws: {
|
|
436
|
+
accountId: accountId || "REPLACE_WITH_ACCOUNT_ID",
|
|
437
|
+
iamRolePrefix: `arn:aws:iam::${accountId || "ACCOUNT_ID"}:role/crossplane`,
|
|
438
|
+
kmsKeyArn: `arn:aws:kms:${defaultRegion}:${accountId || "ACCOUNT_ID"}:key/REPLACE_KEY_ID`
|
|
439
|
+
},
|
|
440
|
+
gcp: {
|
|
441
|
+
projectId: accountId || "REPLACE_WITH_PROJECT_ID",
|
|
442
|
+
serviceAccountEmail: `crossplane@${accountId || "PROJECT_ID"}.iam.gserviceaccount.com`
|
|
443
|
+
},
|
|
444
|
+
azure: {
|
|
445
|
+
subscriptionId: accountId || "REPLACE_WITH_SUBSCRIPTION_ID",
|
|
446
|
+
tenantId: "REPLACE_WITH_TENANT_ID",
|
|
447
|
+
resourceGroupPrefix: `rg-crossplane-${env}`
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
return {
|
|
451
|
+
apiVersion: "apiextensions.crossplane.io/v1alpha1",
|
|
452
|
+
kind: "EnvironmentConfig",
|
|
453
|
+
metadata: {
|
|
454
|
+
name: `${cloud}-${env}`,
|
|
455
|
+
labels: {
|
|
456
|
+
environment: env,
|
|
457
|
+
cloud,
|
|
458
|
+
"managed-by": "crossplane"
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
data: {
|
|
462
|
+
environment: env,
|
|
463
|
+
cloud,
|
|
464
|
+
region: defaultRegion,
|
|
465
|
+
policy: policyMap[env],
|
|
466
|
+
...cloudSpecific[cloud],
|
|
467
|
+
tags: {
|
|
468
|
+
Environment: env,
|
|
469
|
+
ManagedBy: "crossplane",
|
|
470
|
+
Cloud: cloud
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
function environmentCommand() {
|
|
476
|
+
return new Command("environment").description("Generate EnvironmentConfig manifests for multi-environment setups").option("-c, --cloud <cloud>", "Cloud provider: aws | gcp | azure", "aws").option("-e, --env <env>", "Single env: dev | staging | prod (omit to generate all)", "").option("-r, --region <region>", "Override default region", "").option("-a, --account <accountId>", "Cloud account/project/subscription ID", "").option("-o, --out <dir>", "Output directory", "./crossplane/environments").action((opts) => {
|
|
477
|
+
const cloud = opts.cloud.toLowerCase();
|
|
478
|
+
if (!["aws", "gcp", "azure"].includes(cloud)) {
|
|
479
|
+
console.error(chalk.red(`Unknown cloud provider: ${opts.cloud}`));
|
|
480
|
+
process.exit(1);
|
|
481
|
+
}
|
|
482
|
+
const envs = opts.env ? [opts.env] : ["dev", "staging", "prod"];
|
|
483
|
+
log(`
|
|
484
|
+
Generating EnvironmentConfig manifests for ${chalk.bold(cloud.toUpperCase())} (${envs.join(", ")})...
|
|
485
|
+
`);
|
|
486
|
+
const outDir = path.resolve(opts.out);
|
|
487
|
+
for (const env of envs) {
|
|
488
|
+
if (!["dev", "staging", "prod"].includes(env)) {
|
|
489
|
+
console.error(chalk.red(`Unknown env: ${env}`));
|
|
490
|
+
process.exit(1);
|
|
491
|
+
}
|
|
492
|
+
const cfg = buildEnvironmentConfig(env, cloud, opts.region, opts.account);
|
|
493
|
+
writeYaml(outDir, `environment-config-${cloud}-${env}.yaml`, cfg);
|
|
494
|
+
}
|
|
495
|
+
console.log(chalk.green("\nDone. Replace placeholder values before applying.\n"));
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
var program = new Command();
|
|
499
|
+
program.name("crossplane-provider").description(chalk.cyan("Crossplane provider and composition configuration generator")).version("1.0.0");
|
|
500
|
+
program.addCommand(initCommand());
|
|
501
|
+
program.addCommand(compositionCommand());
|
|
502
|
+
program.addCommand(claimCommand());
|
|
503
|
+
program.addCommand(functionCommand());
|
|
504
|
+
program.addCommand(environmentCommand());
|
|
505
|
+
program.parse(process.argv);
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "crossplane-provider-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Crossplane provider and composition configuration generator CLI",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"bin": {
|
|
10
|
+
"crossplane-provider": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "node node_modules/tsup/dist/cli-default.js",
|
|
14
|
+
"dev": "node node_modules/tsup/dist/cli-default.js --watch",
|
|
15
|
+
"prepublishOnly": "node node_modules/tsup/dist/cli-default.js"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"crossplane",
|
|
19
|
+
"kubernetes",
|
|
20
|
+
"infrastructure",
|
|
21
|
+
"cloud",
|
|
22
|
+
"cli",
|
|
23
|
+
"composition",
|
|
24
|
+
"xrd",
|
|
25
|
+
"provider",
|
|
26
|
+
"aws",
|
|
27
|
+
"gcp",
|
|
28
|
+
"azure"
|
|
29
|
+
],
|
|
30
|
+
"author": "crossplane-provider-cli",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18.0.0"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"chalk": "^5.6.2",
|
|
37
|
+
"commander": "^14.0.3",
|
|
38
|
+
"js-yaml": "^4.1.1"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/js-yaml": "^4.0.9",
|
|
42
|
+
"@types/node": "^25.5.2",
|
|
43
|
+
"tsup": "^8.5.1",
|
|
44
|
+
"typescript": "^6.0.2"
|
|
45
|
+
},
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/okirmio-create/cli-forge.git",
|
|
49
|
+
"directory": "crossplane-provider-cli"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://github.com/okirmio-create/cli-forge/tree/main/crossplane-provider-cli",
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/okirmio-create/cli-forge/issues"
|
|
54
|
+
}
|
|
55
|
+
}
|