@intentius/chant-lexicon-k8s 0.37.2 → 0.38.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/dist/crd/crd-sources.d.ts.map +1 -1
- package/dist/crd/parser.d.ts.map +1 -1
- package/dist/generated/index.d.ts +134 -0
- package/dist/generated/index.d.ts.map +1 -1
- package/dist/integrity.json +4 -4
- package/dist/manifest.json +1 -1
- package/dist/meta.json +1086 -45
- package/dist/plugin.d.ts.map +1 -1
- package/dist/serializer.d.ts.map +1 -1
- package/dist/types/index.d.ts +229 -0
- package/package.json +2 -2
- package/src/crd/cnpg.test.ts +186 -0
- package/src/crd/crd-sources.ts +123 -0
- package/src/crd/infisical.test.ts +100 -0
- package/src/crd/parser.ts +8 -0
- package/src/crd/traefik.test.ts +108 -0
- package/src/generated/index.d.ts +229 -0
- package/src/generated/index.ts +134 -0
- package/src/generated/lexicon-k8s.json +1086 -45
- package/src/generated/operations.json +288 -0
- package/src/lifecycle-integration.test.ts +1 -0
- package/src/plugin.ts +2 -0
- package/src/serializer.ts +4 -0
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAqC,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAqC,MAAM,0BAA0B,CAAC;AAuBjG,eAAO,MAAM,SAAS,EAAE,aA4mBvB,CAAC"}
|
package/dist/serializer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAsC,MAAM,6BAA6B,CAAC;AA2IlG;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAsC,MAAM,6BAA6B,CAAC;AA2IlG;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,UA+I3B,CAAC"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -128,6 +128,20 @@ export declare class AppProject {
|
|
|
128
128
|
readonly uid: string;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
export declare class Backup {
|
|
132
|
+
constructor(props: {
|
|
133
|
+
/** Specification of the desired behavior of the backup.
|
|
134
|
+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */
|
|
135
|
+
spec: Record<string, unknown>;
|
|
136
|
+
/** Standard object's metadata. */
|
|
137
|
+
metadata?: ObjectMeta;
|
|
138
|
+
});
|
|
139
|
+
readonly name: string;
|
|
140
|
+
readonly namespace: string;
|
|
141
|
+
readonly status: Record<string, unknown>;
|
|
142
|
+
readonly uid: string;
|
|
143
|
+
}
|
|
144
|
+
|
|
131
145
|
export declare class BatchJob {
|
|
132
146
|
constructor(props: {
|
|
133
147
|
/** Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */
|
|
@@ -228,6 +242,20 @@ export declare class Challenge {
|
|
|
228
242
|
readonly uid: string;
|
|
229
243
|
}
|
|
230
244
|
|
|
245
|
+
export declare class Cluster {
|
|
246
|
+
constructor(props: {
|
|
247
|
+
/** Specification of the desired behavior of the cluster.
|
|
248
|
+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */
|
|
249
|
+
spec: Record<string, unknown>;
|
|
250
|
+
/** Standard object's metadata. */
|
|
251
|
+
metadata?: ObjectMeta;
|
|
252
|
+
});
|
|
253
|
+
readonly name: string;
|
|
254
|
+
readonly namespace: string;
|
|
255
|
+
readonly status: Record<string, unknown>;
|
|
256
|
+
readonly uid: string;
|
|
257
|
+
}
|
|
258
|
+
|
|
231
259
|
export declare class ClusterIssuer {
|
|
232
260
|
constructor(props: {
|
|
233
261
|
/** Desired state of the ClusterIssuer resource. */
|
|
@@ -1101,6 +1129,45 @@ export declare class ImageUpdateAutomation {
|
|
|
1101
1129
|
readonly uid: string;
|
|
1102
1130
|
}
|
|
1103
1131
|
|
|
1132
|
+
export declare class InfisicalDynamicSecret {
|
|
1133
|
+
constructor(props: {
|
|
1134
|
+
/** Standard object's metadata. */
|
|
1135
|
+
metadata?: ObjectMeta;
|
|
1136
|
+
/** InfisicalDynamicSecretSpec defines the desired state of InfisicalDynamicSecret. */
|
|
1137
|
+
spec?: Record<string, unknown>;
|
|
1138
|
+
});
|
|
1139
|
+
readonly name: string;
|
|
1140
|
+
readonly namespace: string;
|
|
1141
|
+
readonly status: Record<string, unknown>;
|
|
1142
|
+
readonly uid: string;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
export declare class InfisicalPushSecret {
|
|
1146
|
+
constructor(props: {
|
|
1147
|
+
/** Standard object's metadata. */
|
|
1148
|
+
metadata?: ObjectMeta;
|
|
1149
|
+
/** InfisicalPushSecretSpec defines the desired state of InfisicalPushSecret */
|
|
1150
|
+
spec?: Record<string, unknown>;
|
|
1151
|
+
});
|
|
1152
|
+
readonly name: string;
|
|
1153
|
+
readonly namespace: string;
|
|
1154
|
+
readonly status: Record<string, unknown>;
|
|
1155
|
+
readonly uid: string;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
export declare class InfisicalSecret {
|
|
1159
|
+
constructor(props: {
|
|
1160
|
+
/** Standard object's metadata. */
|
|
1161
|
+
metadata?: ObjectMeta;
|
|
1162
|
+
/** InfisicalSecretSpec defines the desired state of InfisicalSecret */
|
|
1163
|
+
spec?: Record<string, unknown>;
|
|
1164
|
+
});
|
|
1165
|
+
readonly name: string;
|
|
1166
|
+
readonly namespace: string;
|
|
1167
|
+
readonly status: Record<string, unknown>;
|
|
1168
|
+
readonly uid: string;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1104
1171
|
export declare class Ing {
|
|
1105
1172
|
constructor(props: {
|
|
1106
1173
|
/** Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */
|
|
@@ -1161,6 +1228,42 @@ export declare class IngressList {
|
|
|
1161
1228
|
readonly uid: string;
|
|
1162
1229
|
}
|
|
1163
1230
|
|
|
1231
|
+
export declare class IngressRoute {
|
|
1232
|
+
constructor(props: {
|
|
1233
|
+
/** IngressRouteSpec defines the desired state of IngressRoute. */
|
|
1234
|
+
spec: Record<string, unknown>;
|
|
1235
|
+
/** Standard object's metadata. */
|
|
1236
|
+
metadata?: ObjectMeta;
|
|
1237
|
+
});
|
|
1238
|
+
readonly name: string;
|
|
1239
|
+
readonly namespace: string;
|
|
1240
|
+
readonly uid: string;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
export declare class IngressRouteTCP {
|
|
1244
|
+
constructor(props: {
|
|
1245
|
+
/** IngressRouteTCPSpec defines the desired state of IngressRouteTCP. */
|
|
1246
|
+
spec: Record<string, unknown>;
|
|
1247
|
+
/** Standard object's metadata. */
|
|
1248
|
+
metadata?: ObjectMeta;
|
|
1249
|
+
});
|
|
1250
|
+
readonly name: string;
|
|
1251
|
+
readonly namespace: string;
|
|
1252
|
+
readonly uid: string;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
export declare class IngressRouteUDP {
|
|
1256
|
+
constructor(props: {
|
|
1257
|
+
/** IngressRouteUDPSpec defines the desired state of a IngressRouteUDP. */
|
|
1258
|
+
spec: Record<string, unknown>;
|
|
1259
|
+
/** Standard object's metadata. */
|
|
1260
|
+
metadata?: ObjectMeta;
|
|
1261
|
+
});
|
|
1262
|
+
readonly name: string;
|
|
1263
|
+
readonly namespace: string;
|
|
1264
|
+
readonly uid: string;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1164
1267
|
export declare class IPAddress {
|
|
1165
1268
|
constructor(props: {
|
|
1166
1269
|
/** spec is the desired state of the IPAddress. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */
|
|
@@ -1379,6 +1482,30 @@ export declare class MicroVMReplicaSet {
|
|
|
1379
1482
|
readonly uid: string;
|
|
1380
1483
|
}
|
|
1381
1484
|
|
|
1485
|
+
export declare class Middleware {
|
|
1486
|
+
constructor(props: {
|
|
1487
|
+
/** MiddlewareSpec defines the desired state of a Middleware. */
|
|
1488
|
+
spec: Record<string, unknown>;
|
|
1489
|
+
/** Standard object's metadata. */
|
|
1490
|
+
metadata?: ObjectMeta;
|
|
1491
|
+
});
|
|
1492
|
+
readonly name: string;
|
|
1493
|
+
readonly namespace: string;
|
|
1494
|
+
readonly uid: string;
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
export declare class MiddlewareTCP {
|
|
1498
|
+
constructor(props: {
|
|
1499
|
+
/** MiddlewareTCPSpec defines the desired state of a MiddlewareTCP. */
|
|
1500
|
+
spec: Record<string, unknown>;
|
|
1501
|
+
/** Standard object's metadata. */
|
|
1502
|
+
metadata?: ObjectMeta;
|
|
1503
|
+
});
|
|
1504
|
+
readonly name: string;
|
|
1505
|
+
readonly namespace: string;
|
|
1506
|
+
readonly uid: string;
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1382
1509
|
export declare class MutatingAdmissionPolicy {
|
|
1383
1510
|
constructor(props: {
|
|
1384
1511
|
/** metadata is the standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. */
|
|
@@ -1547,6 +1674,20 @@ export declare class NS {
|
|
|
1547
1674
|
readonly uid: string;
|
|
1548
1675
|
}
|
|
1549
1676
|
|
|
1677
|
+
export declare class ObjectStore {
|
|
1678
|
+
constructor(props: {
|
|
1679
|
+
/** Specification of the desired behavior of the ObjectStore.
|
|
1680
|
+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */
|
|
1681
|
+
spec: Record<string, unknown>;
|
|
1682
|
+
/** Standard object's metadata. */
|
|
1683
|
+
metadata?: ObjectMeta;
|
|
1684
|
+
});
|
|
1685
|
+
readonly name: string;
|
|
1686
|
+
readonly namespace: string;
|
|
1687
|
+
readonly status: Record<string, unknown>;
|
|
1688
|
+
readonly uid: string;
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1550
1691
|
export declare class OCIRepository {
|
|
1551
1692
|
constructor(props: {
|
|
1552
1693
|
/** Standard object's metadata. */
|
|
@@ -1728,6 +1869,20 @@ export declare class PodTemplateList {
|
|
|
1728
1869
|
readonly uid: string;
|
|
1729
1870
|
}
|
|
1730
1871
|
|
|
1872
|
+
export declare class Pooler {
|
|
1873
|
+
constructor(props: {
|
|
1874
|
+
/** Specification of the desired behavior of the Pooler.
|
|
1875
|
+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */
|
|
1876
|
+
spec: Record<string, unknown>;
|
|
1877
|
+
/** Standard object's metadata. */
|
|
1878
|
+
metadata?: ObjectMeta;
|
|
1879
|
+
});
|
|
1880
|
+
readonly name: string;
|
|
1881
|
+
readonly namespace: string;
|
|
1882
|
+
readonly status: Record<string, unknown>;
|
|
1883
|
+
readonly uid: string;
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1731
1886
|
export declare class PriorityClass {
|
|
1732
1887
|
constructor(props: {
|
|
1733
1888
|
/** description is an arbitrary string that usually provides guidelines on when this priority class should be used. */
|
|
@@ -2172,6 +2327,20 @@ export declare class Scale {
|
|
|
2172
2327
|
readonly uid: string;
|
|
2173
2328
|
}
|
|
2174
2329
|
|
|
2330
|
+
export declare class ScheduledBackup {
|
|
2331
|
+
constructor(props: {
|
|
2332
|
+
/** Specification of the desired behavior of the ScheduledBackup.
|
|
2333
|
+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */
|
|
2334
|
+
spec: Record<string, unknown>;
|
|
2335
|
+
/** Standard object's metadata. */
|
|
2336
|
+
metadata?: ObjectMeta;
|
|
2337
|
+
});
|
|
2338
|
+
readonly name: string;
|
|
2339
|
+
readonly namespace: string;
|
|
2340
|
+
readonly status: Record<string, unknown>;
|
|
2341
|
+
readonly uid: string;
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2175
2344
|
export declare class Sec {
|
|
2176
2345
|
constructor(props: {
|
|
2177
2346
|
/** Data contains the secret data. Each key must consist of alphanumeric characters, '-', '_' or '.'. The serialized form of the secret data is a base64 encoded string, representing the arbitrary (possibly non-string) data value here. Described in https://tools.ietf.org/html/rfc4648#section-4 */
|
|
@@ -2254,6 +2423,30 @@ export declare class SelfSubjectRulesReview {
|
|
|
2254
2423
|
readonly uid: string;
|
|
2255
2424
|
}
|
|
2256
2425
|
|
|
2426
|
+
export declare class ServersTransport {
|
|
2427
|
+
constructor(props: {
|
|
2428
|
+
/** ServersTransportSpec defines the desired state of a ServersTransport. */
|
|
2429
|
+
spec: Record<string, unknown>;
|
|
2430
|
+
/** Standard object's metadata. */
|
|
2431
|
+
metadata?: ObjectMeta;
|
|
2432
|
+
});
|
|
2433
|
+
readonly name: string;
|
|
2434
|
+
readonly namespace: string;
|
|
2435
|
+
readonly uid: string;
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
export declare class ServersTransportTCP {
|
|
2439
|
+
constructor(props: {
|
|
2440
|
+
/** ServersTransportTCPSpec defines the desired state of a ServersTransportTCP. */
|
|
2441
|
+
spec: Record<string, unknown>;
|
|
2442
|
+
/** Standard object's metadata. */
|
|
2443
|
+
metadata?: ObjectMeta;
|
|
2444
|
+
});
|
|
2445
|
+
readonly name: string;
|
|
2446
|
+
readonly namespace: string;
|
|
2447
|
+
readonly uid: string;
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2257
2450
|
export declare class Service {
|
|
2258
2451
|
constructor(props: {
|
|
2259
2452
|
/** Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */
|
|
@@ -2469,6 +2662,30 @@ export declare class SubjectAccessReview {
|
|
|
2469
2662
|
readonly uid: string;
|
|
2470
2663
|
}
|
|
2471
2664
|
|
|
2665
|
+
export declare class TLSOption {
|
|
2666
|
+
constructor(props: {
|
|
2667
|
+
/** TLSOptionSpec defines the desired state of a TLSOption. */
|
|
2668
|
+
spec: Record<string, unknown>;
|
|
2669
|
+
/** Standard object's metadata. */
|
|
2670
|
+
metadata?: ObjectMeta;
|
|
2671
|
+
});
|
|
2672
|
+
readonly name: string;
|
|
2673
|
+
readonly namespace: string;
|
|
2674
|
+
readonly uid: string;
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2677
|
+
export declare class TLSStore {
|
|
2678
|
+
constructor(props: {
|
|
2679
|
+
/** TLSStoreSpec defines the desired state of a TLSStore. */
|
|
2680
|
+
spec: Record<string, unknown>;
|
|
2681
|
+
/** Standard object's metadata. */
|
|
2682
|
+
metadata?: ObjectMeta;
|
|
2683
|
+
});
|
|
2684
|
+
readonly name: string;
|
|
2685
|
+
readonly namespace: string;
|
|
2686
|
+
readonly uid: string;
|
|
2687
|
+
}
|
|
2688
|
+
|
|
2472
2689
|
export declare class TokenRequest {
|
|
2473
2690
|
constructor(props: {
|
|
2474
2691
|
/** metadata is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */
|
|
@@ -2493,6 +2710,18 @@ export declare class TokenReview {
|
|
|
2493
2710
|
readonly uid: string;
|
|
2494
2711
|
}
|
|
2495
2712
|
|
|
2713
|
+
export declare class TraefikService {
|
|
2714
|
+
constructor(props: {
|
|
2715
|
+
/** TraefikServiceSpec defines the desired state of a TraefikService. */
|
|
2716
|
+
spec: Record<string, unknown>;
|
|
2717
|
+
/** Standard object's metadata. */
|
|
2718
|
+
metadata?: ObjectMeta;
|
|
2719
|
+
});
|
|
2720
|
+
readonly name: string;
|
|
2721
|
+
readonly namespace: string;
|
|
2722
|
+
readonly uid: string;
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2496
2725
|
export declare class ValidatingAdmissionPolicy {
|
|
2497
2726
|
constructor(props: {
|
|
2498
2727
|
/** metadata is the standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-k8s",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.38.0",
|
|
4
4
|
"description": "Kubernetes lexicon for chant — declarative IaC in TypeScript",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://intentius.io/chant",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"typescript": "^5.9.3"
|
|
79
79
|
},
|
|
80
80
|
"peerDependencies": {
|
|
81
|
-
"@intentius/chant": "^0.
|
|
81
|
+
"@intentius/chant": "^0.38.0",
|
|
82
82
|
"typescript": "^5.9.3"
|
|
83
83
|
}
|
|
84
84
|
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CNPG acceptance test.
|
|
3
|
+
*
|
|
4
|
+
* The bar set by #1319 is that fountain's real `k8s/` overlay — postgres.yaml,
|
|
5
|
+
* scheduledbackup.yaml, objectstore.yaml — is reproducible from typed chant
|
|
6
|
+
* source. So these assertions are transcribed from that overlay rather than
|
|
7
|
+
* from a fixture invented to pass, and every value here is one a running
|
|
8
|
+
* cluster has.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, test, expect } from "vitest";
|
|
12
|
+
import { Cluster, ScheduledBackup, ObjectStore } from "../generated";
|
|
13
|
+
import { k8sSerializer } from "../serializer";
|
|
14
|
+
import { parseYAML } from "@intentius/chant/yaml";
|
|
15
|
+
|
|
16
|
+
/** Serialize one declaration the way `chant build` would, and read it back. */
|
|
17
|
+
function synth(logicalName: string, resource: unknown): any {
|
|
18
|
+
const yaml = k8sSerializer.serialize(new Map([[logicalName, resource as never]]));
|
|
19
|
+
return parseYAML(yaml);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe("CNPG Cluster", () => {
|
|
23
|
+
const cluster = new Cluster({
|
|
24
|
+
metadata: { name: "fountain-pg", namespace: "fountain", labels: { app: "fountain" } },
|
|
25
|
+
spec: {
|
|
26
|
+
instances: 1,
|
|
27
|
+
imageName: "ghcr.io/cloudnative-pg/postgresql:18.4-standard-trixie",
|
|
28
|
+
plugins: [
|
|
29
|
+
{
|
|
30
|
+
name: "barman-cloud.cloudnative-pg.io",
|
|
31
|
+
isWALArchiver: true,
|
|
32
|
+
parameters: { barmanObjectName: "fountain-backups" },
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
bootstrap: {
|
|
36
|
+
initdb: {
|
|
37
|
+
database: "fountain",
|
|
38
|
+
owner: "fountain",
|
|
39
|
+
postInitTemplateSQL: ["CREATE EXTENSION IF NOT EXISTS vector;"],
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
storage: { storageClass: "longhorn", size: "10Gi" },
|
|
43
|
+
resources: {
|
|
44
|
+
requests: { cpu: "100m", memory: "512Mi" },
|
|
45
|
+
limits: { memory: "1Gi" },
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("carries the CNPG apiVersion and kind", () => {
|
|
51
|
+
const doc = synth("fountainPg", cluster);
|
|
52
|
+
expect(doc.apiVersion).toBe("postgresql.cnpg.io/v1");
|
|
53
|
+
expect(doc.kind).toBe("Cluster");
|
|
54
|
+
expect(doc.metadata.name).toBe("fountain-pg");
|
|
55
|
+
expect(doc.metadata.namespace).toBe("fountain");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("reproduces fountain's postgres.yaml spec", () => {
|
|
59
|
+
const { spec } = synth("fountainPg", cluster);
|
|
60
|
+
expect(spec.instances).toBe(1);
|
|
61
|
+
expect(spec.imageName).toBe("ghcr.io/cloudnative-pg/postgresql:18.4-standard-trixie");
|
|
62
|
+
expect(spec.storage).toEqual({ storageClass: "longhorn", size: "10Gi" });
|
|
63
|
+
expect(spec.bootstrap.initdb.database).toBe("fountain");
|
|
64
|
+
expect(spec.bootstrap.initdb.owner).toBe("fountain");
|
|
65
|
+
expect(spec.bootstrap.initdb.postInitTemplateSQL).toEqual([
|
|
66
|
+
"CREATE EXTENSION IF NOT EXISTS vector;",
|
|
67
|
+
]);
|
|
68
|
+
// A memory limit with no CPU limit is deliberate upstream: a CPU limit
|
|
69
|
+
// throttles a database. It has to survive serialization as written.
|
|
70
|
+
expect(spec.resources).toEqual({
|
|
71
|
+
requests: { cpu: "100m", memory: "512Mi" },
|
|
72
|
+
limits: { memory: "1Gi" },
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("wires WAL archiving to the ObjectStore by name", () => {
|
|
77
|
+
const { spec } = synth("fountainPg", cluster);
|
|
78
|
+
// This block is the whole link between the two CRDs. `isWALArchiver` must
|
|
79
|
+
// stay a boolean -- quoted, the plugin ignores it and archiving is silently
|
|
80
|
+
// off, which looks exactly like a healthy cluster until a restore.
|
|
81
|
+
expect(spec.plugins).toEqual([
|
|
82
|
+
{
|
|
83
|
+
name: "barman-cloud.cloudnative-pg.io",
|
|
84
|
+
isWALArchiver: true,
|
|
85
|
+
parameters: { barmanObjectName: "fountain-backups" },
|
|
86
|
+
},
|
|
87
|
+
]);
|
|
88
|
+
expect(typeof spec.plugins[0].isWALArchiver).toBe("boolean");
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe("CNPG ScheduledBackup", () => {
|
|
93
|
+
const backup = new ScheduledBackup({
|
|
94
|
+
metadata: { name: "fountain-pg-base", namespace: "fountain", labels: { app: "fountain" } },
|
|
95
|
+
spec: {
|
|
96
|
+
schedule: "0 47 2 * * *",
|
|
97
|
+
backupOwnerReference: "self",
|
|
98
|
+
cluster: { name: "fountain-pg" },
|
|
99
|
+
method: "plugin",
|
|
100
|
+
pluginConfiguration: { name: "barman-cloud.cloudnative-pg.io" },
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("reproduces fountain's scheduledbackup.yaml", () => {
|
|
105
|
+
const doc = synth("fountainPgBase", backup);
|
|
106
|
+
expect(doc.apiVersion).toBe("postgresql.cnpg.io/v1");
|
|
107
|
+
expect(doc.kind).toBe("ScheduledBackup");
|
|
108
|
+
expect(doc.spec.backupOwnerReference).toBe("self");
|
|
109
|
+
expect(doc.spec.cluster).toEqual({ name: "fountain-pg" });
|
|
110
|
+
expect(doc.spec.method).toBe("plugin");
|
|
111
|
+
expect(doc.spec.pluginConfiguration).toEqual({ name: "barman-cloud.cloudnative-pg.io" });
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("round-trips a six-field schedule", () => {
|
|
115
|
+
const { spec } = synth("fountainPgBase", backup);
|
|
116
|
+
// CNPG schedules lead with seconds, so this is six fields where a
|
|
117
|
+
// Kubernetes CronJob takes five. The schema types it as a plain string, so
|
|
118
|
+
// nothing here or upstream rejects the five-field form -- it just means a
|
|
119
|
+
// different time. The count is the only thing that catches it.
|
|
120
|
+
expect(spec.schedule).toBe("0 47 2 * * *");
|
|
121
|
+
expect(spec.schedule.trim().split(/\s+/)).toHaveLength(6);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe("barman-cloud ObjectStore", () => {
|
|
126
|
+
const store = new ObjectStore({
|
|
127
|
+
metadata: { name: "fountain-backups", namespace: "fountain", labels: { app: "fountain" } },
|
|
128
|
+
spec: {
|
|
129
|
+
retentionPolicy: "14d",
|
|
130
|
+
configuration: {
|
|
131
|
+
destinationPath: "s3://fountain-backups/barman",
|
|
132
|
+
endpointURL: "http://s3.garage.svc.cluster.local:3900",
|
|
133
|
+
s3Credentials: {
|
|
134
|
+
accessKeyId: { name: "fountain-backup-s3-credentials", key: "AWS_ACCESS_KEY_ID" },
|
|
135
|
+
secretAccessKey: { name: "fountain-backup-s3-credentials", key: "AWS_SECRET_ACCESS_KEY" },
|
|
136
|
+
},
|
|
137
|
+
wal: { compression: "gzip" },
|
|
138
|
+
data: { compression: "gzip" },
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("reproduces fountain's objectstore.yaml", () => {
|
|
144
|
+
const doc = synth("fountainBackups", store);
|
|
145
|
+
// Its own group, mapped onto the same `Cnpg` namespace as the Cluster.
|
|
146
|
+
expect(doc.apiVersion).toBe("barmancloud.cnpg.io/v1");
|
|
147
|
+
expect(doc.kind).toBe("ObjectStore");
|
|
148
|
+
expect(doc.spec.retentionPolicy).toBe("14d");
|
|
149
|
+
expect(doc.spec.configuration.destinationPath).toBe("s3://fountain-backups/barman");
|
|
150
|
+
expect(doc.spec.configuration.endpointURL).toBe("http://s3.garage.svc.cluster.local:3900");
|
|
151
|
+
expect(doc.spec.configuration.wal).toEqual({ compression: "gzip" });
|
|
152
|
+
expect(doc.spec.configuration.data).toEqual({ compression: "gzip" });
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("keeps credentials as secret references, never values", () => {
|
|
156
|
+
const { spec } = synth("fountainBackups", store);
|
|
157
|
+
expect(spec.configuration.s3Credentials).toEqual({
|
|
158
|
+
accessKeyId: { name: "fountain-backup-s3-credentials", key: "AWS_ACCESS_KEY_ID" },
|
|
159
|
+
secretAccessKey: { name: "fountain-backup-s3-credentials", key: "AWS_SECRET_ACCESS_KEY" },
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("the Cluster's barmanObjectName matches this store's name", () => {
|
|
164
|
+
// The two CRDs are joined by a string. Nothing upstream checks it: a typo
|
|
165
|
+
// leaves the cluster running with archiving pointed at a store that does
|
|
166
|
+
// not exist.
|
|
167
|
+
const clusterDoc = synth(
|
|
168
|
+
"fountainPg",
|
|
169
|
+
new Cluster({
|
|
170
|
+
metadata: { name: "fountain-pg", namespace: "fountain" },
|
|
171
|
+
spec: {
|
|
172
|
+
instances: 1,
|
|
173
|
+
plugins: [
|
|
174
|
+
{
|
|
175
|
+
name: "barman-cloud.cloudnative-pg.io",
|
|
176
|
+
isWALArchiver: true,
|
|
177
|
+
parameters: { barmanObjectName: "fountain-backups" },
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
},
|
|
181
|
+
}),
|
|
182
|
+
);
|
|
183
|
+
const storeDoc = synth("fountainBackups", store);
|
|
184
|
+
expect(clusterDoc.spec.plugins[0].parameters.barmanObjectName).toBe(storeDoc.metadata.name);
|
|
185
|
+
});
|
|
186
|
+
});
|
package/src/crd/crd-sources.ts
CHANGED
|
@@ -93,6 +93,111 @@ const COCKROACH_OPERATOR_CRD_BASE = `https://raw.githubusercontent.com/cockroach
|
|
|
93
93
|
const CERT_MANAGER_VERSION = "v1.16.2";
|
|
94
94
|
const CERT_MANAGER_CRD_BUNDLE = `https://github.com/cert-manager/cert-manager/releases/download/${CERT_MANAGER_VERSION}/cert-manager.crds.yaml`;
|
|
95
95
|
|
|
96
|
+
/**
|
|
97
|
+
* CloudNativePG CRDs — postgresql.cnpg.io/v1
|
|
98
|
+
*
|
|
99
|
+
* The Postgres operator. Produces, under the `Cnpg` namespace (both groups are
|
|
100
|
+
* mapped there explicitly in parser.ts; the first-segment rule would otherwise
|
|
101
|
+
* split them into `Postgresql` and `Barmancloud`):
|
|
102
|
+
* K8s::Cnpg::Cluster → postgresql.cnpg.io/v1
|
|
103
|
+
* K8s::Cnpg::ScheduledBackup → postgresql.cnpg.io/v1
|
|
104
|
+
* K8s::Cnpg::Backup → postgresql.cnpg.io/v1
|
|
105
|
+
* K8s::Cnpg::Pooler → postgresql.cnpg.io/v1
|
|
106
|
+
*
|
|
107
|
+
* Pinned to 1.29.1 rather than latest (1.30.0) because that is the operator a
|
|
108
|
+
* real consumer runs — BinaryBourbon/fountain's k8s overlay.
|
|
109
|
+
*
|
|
110
|
+
* Note on ScheduledBackup.schedule: it is a **six**-field cron with leading
|
|
111
|
+
* seconds, not the five-field form Kubernetes CronJob takes. The schema types
|
|
112
|
+
* it as a plain string, so a five-field value passes every check here and
|
|
113
|
+
* silently means something else on the cluster.
|
|
114
|
+
*
|
|
115
|
+
* Database, Publication and Subscription are deliberately left out — no known
|
|
116
|
+
* consumer needs them, and pulling a whole provider is what the note at the top
|
|
117
|
+
* of this file warns against.
|
|
118
|
+
*
|
|
119
|
+
* Operator install: kubectl apply --server-side -f
|
|
120
|
+
* https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.29/releases/cnpg-1.29.1.yaml
|
|
121
|
+
*/
|
|
122
|
+
const CNPG_VERSION = "v1.29.1";
|
|
123
|
+
const CNPG_CRD_BASE = `https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/${CNPG_VERSION}/config/crd/bases`;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* barman-cloud plugin CRD — barmancloud.cnpg.io/v1
|
|
127
|
+
*
|
|
128
|
+
* CNPG's WAL archiving / object-storage backend, shipped as a separate plugin
|
|
129
|
+
* with its own release train. Produces:
|
|
130
|
+
* K8s::Cnpg::ObjectStore → barmancloud.cnpg.io/v1
|
|
131
|
+
*
|
|
132
|
+
* A CNPG Cluster reaches it through `spec.plugins[]` — `name:
|
|
133
|
+
* barman-cloud.cloudnative-pg.io`, `isWALArchiver: true`,
|
|
134
|
+
* `parameters.barmanObjectName` naming the ObjectStore — so the two are only
|
|
135
|
+
* ever useful together.
|
|
136
|
+
*
|
|
137
|
+
* Pinned to 0.14.0 (latest). Its ObjectStore schema is a superset of 0.7.0's:
|
|
138
|
+
* same four spec properties, more detail inside them.
|
|
139
|
+
*
|
|
140
|
+
* Plugin install: kubectl apply -f
|
|
141
|
+
* https://github.com/cloudnative-pg/plugin-barman-cloud/releases/download/v0.14.0/manifest.yaml
|
|
142
|
+
*/
|
|
143
|
+
const BARMAN_PLUGIN_VERSION = "v0.14.0";
|
|
144
|
+
const BARMAN_PLUGIN_CRD_BASE = `https://raw.githubusercontent.com/cloudnative-pg/plugin-barman-cloud/${BARMAN_PLUGIN_VERSION}/config/crd/bases`;
|
|
145
|
+
/**
|
|
146
|
+
* Traefik proxy CRDs — traefik.io/v1alpha1
|
|
147
|
+
*
|
|
148
|
+
* Traefik's own routing surface. An `IngressRoute` is not a
|
|
149
|
+
* `networking.k8s.io` Ingress with annotations — it is a distinct CRD with its
|
|
150
|
+
* own matcher grammar, so an estate fronted by Traefik has no expressible edge
|
|
151
|
+
* without these. Produces, under the `Traefik` namespace (first-segment rule,
|
|
152
|
+
* no override needed):
|
|
153
|
+
* K8s::Traefik::IngressRoute K8s::Traefik::Middleware
|
|
154
|
+
* K8s::Traefik::IngressRouteTCP K8s::Traefik::MiddlewareTCP
|
|
155
|
+
* K8s::Traefik::IngressRouteUDP K8s::Traefik::ServersTransport
|
|
156
|
+
* K8s::Traefik::TLSOption K8s::Traefik::ServersTransportTCP
|
|
157
|
+
* K8s::Traefik::TLSStore K8s::Traefik::TraefikService
|
|
158
|
+
*
|
|
159
|
+
* Only the `traefik.io` group. The chart's crds/ directory also ships
|
|
160
|
+
* `hub.traefik.io_*` (Traefik Hub, a different commercial product, ~12 kinds,
|
|
161
|
+
* no known consumer) and a vendored copy of the Gateway API, which is already
|
|
162
|
+
* generated here from its upstream repo and would collide.
|
|
163
|
+
*
|
|
164
|
+
* Version footgun: the pin below is the **chart** version, and the chart
|
|
165
|
+
* version is not the Traefik version. Chart v41.1.0 ships Traefik v3.7.9.
|
|
166
|
+
* When bumping, record both.
|
|
167
|
+
*
|
|
168
|
+
* Controller install: helm repo add traefik https://traefik.github.io/charts
|
|
169
|
+
* && helm install traefik traefik/traefik --version 41.1.0
|
|
170
|
+
*/
|
|
171
|
+
const TRAEFIK_CHART_VERSION = "v41.1.0";
|
|
172
|
+
const TRAEFIK_CRD_BASE = `https://raw.githubusercontent.com/traefik/traefik-helm-chart/${TRAEFIK_CHART_VERSION}/traefik/crds`;
|
|
173
|
+
/**
|
|
174
|
+
* Infisical operator CRDs — secrets.infisical.com/v1alpha1
|
|
175
|
+
*
|
|
176
|
+
* The declarative form of chant's own secrets boundary. An `InfisicalSecret`
|
|
177
|
+
* says where a secret comes from and who may fetch it; it never carries a
|
|
178
|
+
* value. Without it an estate can declare the Deployment that consumes a
|
|
179
|
+
* Secret but not the thing that makes the Secret exist. Produces, under the
|
|
180
|
+
* `Infisical` namespace:
|
|
181
|
+
* K8s::Infisical::InfisicalSecret
|
|
182
|
+
* K8s::Infisical::InfisicalPushSecret
|
|
183
|
+
* K8s::Infisical::InfisicalDynamicSecret
|
|
184
|
+
*
|
|
185
|
+
* The group is overridden to `Infisical` in parser.ts. The first-segment rule
|
|
186
|
+
* would give `K8s::Secrets::InfisicalSecret`, which reads like a core Secret
|
|
187
|
+
* next to the `K8s::Core::Secret` that already exists.
|
|
188
|
+
*
|
|
189
|
+
* Two things about the URL, both easy to lose an hour to:
|
|
190
|
+
* - The operator lives in its own repo, `Infisical/kubernetes-operator`.
|
|
191
|
+
* The path under the `Infisical/infisical` monorepo 404s.
|
|
192
|
+
* - The tag is path-shaped — `infisical-k8-operator/v0.11.7`. Not a typo,
|
|
193
|
+
* and not a directory.
|
|
194
|
+
*
|
|
195
|
+
* Operator install: helm repo add infisical https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/
|
|
196
|
+
* && helm install infisical-secrets-operator infisical/secrets-operator
|
|
197
|
+
*/
|
|
198
|
+
const INFISICAL_OPERATOR_VERSION = "infisical-k8-operator/v0.11.7";
|
|
199
|
+
const INFISICAL_CRD_BASE = `https://raw.githubusercontent.com/Infisical/kubernetes-operator/${INFISICAL_OPERATOR_VERSION}/config/crd/bases`;
|
|
200
|
+
|
|
96
201
|
/**
|
|
97
202
|
* Prometheus Operator CRDs — monitoring.coreos.com/v1
|
|
98
203
|
*
|
|
@@ -188,6 +293,24 @@ export const CRD_SOURCES: CRDSource[] = [
|
|
|
188
293
|
{ type: "url", url: CERT_MANAGER_CRD_BUNDLE },
|
|
189
294
|
{ type: "url", url: `${PROM_OPERATOR_CRD_BASE}/monitoring.coreos.com_servicemonitors.yaml` },
|
|
190
295
|
{ type: "url", url: `${PROM_OPERATOR_CRD_BASE}/monitoring.coreos.com_prometheusrules.yaml` },
|
|
296
|
+
{ type: "url", url: `${CNPG_CRD_BASE}/postgresql.cnpg.io_clusters.yaml` },
|
|
297
|
+
{ type: "url", url: `${CNPG_CRD_BASE}/postgresql.cnpg.io_scheduledbackups.yaml` },
|
|
298
|
+
{ type: "url", url: `${CNPG_CRD_BASE}/postgresql.cnpg.io_backups.yaml` },
|
|
299
|
+
{ type: "url", url: `${CNPG_CRD_BASE}/postgresql.cnpg.io_poolers.yaml` },
|
|
300
|
+
{ type: "url", url: `${BARMAN_PLUGIN_CRD_BASE}/barmancloud.cnpg.io_objectstores.yaml` },
|
|
301
|
+
{ type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_ingressroutes.yaml` },
|
|
302
|
+
{ type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_ingressroutetcps.yaml` },
|
|
303
|
+
{ type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_ingressrouteudps.yaml` },
|
|
304
|
+
{ type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_middlewares.yaml` },
|
|
305
|
+
{ type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_middlewaretcps.yaml` },
|
|
306
|
+
{ type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_serverstransports.yaml` },
|
|
307
|
+
{ type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_serverstransporttcps.yaml` },
|
|
308
|
+
{ type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_tlsoptions.yaml` },
|
|
309
|
+
{ type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_tlsstores.yaml` },
|
|
310
|
+
{ type: "url", url: `${TRAEFIK_CRD_BASE}/traefik.io_traefikservices.yaml` },
|
|
311
|
+
{ type: "url", url: `${INFISICAL_CRD_BASE}/secrets.infisical.com_infisicalsecrets.yaml` },
|
|
312
|
+
{ type: "url", url: `${INFISICAL_CRD_BASE}/secrets.infisical.com_infisicalpushsecrets.yaml` },
|
|
313
|
+
{ type: "url", url: `${INFISICAL_CRD_BASE}/secrets.infisical.com_infisicaldynamicsecrets.yaml` },
|
|
191
314
|
{
|
|
192
315
|
type: "url",
|
|
193
316
|
url: FLUX_TOOLKIT_INSTALL,
|