@intentius/chant-lexicon-gcp 0.124.30 → 0.124.32

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.
Files changed (103) hide show
  1. package/dist/actions/index.js +45 -0
  2. package/dist/api/read-client.js +105 -0
  3. package/dist/codegen/docs-cli.js +6 -0
  4. package/dist/codegen/docs.js +115 -0
  5. package/dist/codegen/generate-cli.js +17 -0
  6. package/dist/codegen/generate.js +214 -0
  7. package/dist/codegen/naming.js +164 -0
  8. package/dist/codegen/package.js +43 -0
  9. package/dist/composites/catalog.js +1245 -0
  10. package/dist/composites/cloud-function.js +65 -0
  11. package/dist/composites/cloud-run-service.js +71 -0
  12. package/dist/composites/cloud-sql-instance.js +85 -0
  13. package/dist/composites/gcs-bucket.js +64 -0
  14. package/dist/composites/gke-cluster.js +113 -0
  15. package/dist/composites/gke-crdb-region.js +137 -0
  16. package/dist/composites/gpu-node-pool.js +74 -0
  17. package/dist/composites/index.js +15 -0
  18. package/dist/composites/landing-zone.js +89 -0
  19. package/dist/composites/managed-certificate.js +46 -0
  20. package/dist/composites/memorystore-redis.js +52 -0
  21. package/dist/composites/multi-region-vpc.js +108 -0
  22. package/dist/composites/private-service.js +50 -0
  23. package/dist/composites/pubsub-pipeline.js +63 -0
  24. package/dist/composites/secure-project.js +85 -0
  25. package/dist/composites/vpc-network.js +113 -0
  26. package/dist/coverage.js +28 -0
  27. package/dist/deep-observe-hooks.js +152 -0
  28. package/dist/deep-observe.js +273 -0
  29. package/dist/default-labels.js +67 -0
  30. package/dist/describe-resources.js +264 -0
  31. package/dist/detect.js +16 -0
  32. package/dist/export-resources.js +59 -0
  33. package/dist/generated/index.js +1804 -0
  34. package/dist/generated/runtime.js +4 -0
  35. package/dist/governance.js +98 -0
  36. package/dist/import/generator.js +68 -0
  37. package/dist/import/live-export.js +73 -0
  38. package/dist/import/parser.js +61 -0
  39. package/dist/index.js +36 -0
  40. package/dist/integrity.json +3 -3
  41. package/dist/lint/audit-catalog.js +38 -0
  42. package/dist/lint/audit-lineage.js +63 -0
  43. package/dist/lint/post-synth/gcp-helpers.js +91 -0
  44. package/dist/lint/post-synth/index.js +54 -0
  45. package/dist/lint/post-synth/schema-registry.d.ts.map +1 -1
  46. package/dist/lint/post-synth/schema-registry.js +69 -0
  47. package/dist/lint/post-synth/wgc101.js +47 -0
  48. package/dist/lint/post-synth/wgc102.js +29 -0
  49. package/dist/lint/post-synth/wgc103.js +37 -0
  50. package/dist/lint/post-synth/wgc104.js +34 -0
  51. package/dist/lint/post-synth/wgc105.js +39 -0
  52. package/dist/lint/post-synth/wgc106.js +30 -0
  53. package/dist/lint/post-synth/wgc107.js +33 -0
  54. package/dist/lint/post-synth/wgc108.js +34 -0
  55. package/dist/lint/post-synth/wgc109.js +33 -0
  56. package/dist/lint/post-synth/wgc110.js +32 -0
  57. package/dist/lint/post-synth/wgc111.js +47 -0
  58. package/dist/lint/post-synth/wgc112.js +46 -0
  59. package/dist/lint/post-synth/wgc113.js +35 -0
  60. package/dist/lint/post-synth/wgc201.js +30 -0
  61. package/dist/lint/post-synth/wgc202.js +33 -0
  62. package/dist/lint/post-synth/wgc203.js +35 -0
  63. package/dist/lint/post-synth/wgc204.js +33 -0
  64. package/dist/lint/post-synth/wgc301.js +28 -0
  65. package/dist/lint/post-synth/wgc302.js +28 -0
  66. package/dist/lint/post-synth/wgc303.js +29 -0
  67. package/dist/lint/post-synth/wgc401.js +50 -0
  68. package/dist/lint/post-synth/wgc402.js +46 -0
  69. package/dist/lint/post-synth/wgc403.js +74 -0
  70. package/dist/lint/post-synth/wgc501.js +63 -0
  71. package/dist/lint/post-synth/wgc502.js +37 -0
  72. package/dist/lint/post-synth/wgc503.js +49 -0
  73. package/dist/lint/rules/hardcoded-project.js +51 -0
  74. package/dist/lint/rules/hardcoded-region.js +51 -0
  75. package/dist/lint/rules/index.js +3 -0
  76. package/dist/lint/rules/public-iam.js +37 -0
  77. package/dist/lsp/completions.d.ts.map +1 -1
  78. package/dist/lsp/completions.js +15 -0
  79. package/dist/lsp/hover.d.ts.map +1 -1
  80. package/dist/lsp/hover.js +46 -0
  81. package/dist/manifest.json +1 -1
  82. package/dist/op/activities/floci-gcp.js +49 -0
  83. package/dist/op/activities/gcp-apply.js +618 -0
  84. package/dist/op/activities/index.js +10 -0
  85. package/dist/op/builders.js +50 -0
  86. package/dist/ownership.js +38 -0
  87. package/dist/package-cli.js +20 -0
  88. package/dist/plugin.js +371 -0
  89. package/dist/pseudo.js +15 -0
  90. package/dist/rules/schema-registry.ts +2 -1
  91. package/dist/serializer.d.ts.map +1 -1
  92. package/dist/serializer.js +233 -0
  93. package/dist/spec/fetch.js +107 -0
  94. package/dist/spec/parse.js +323 -0
  95. package/dist/validate-cli.js +11 -0
  96. package/dist/validate.js +24 -0
  97. package/dist/variables.js +15 -0
  98. package/package.json +8 -8
  99. package/src/codegen/package.ts +2 -2
  100. package/src/lint/post-synth/schema-registry.ts +2 -1
  101. package/src/lsp/completions.ts +2 -1
  102. package/src/lsp/hover.ts +2 -1
  103. package/src/serializer.ts +2 -1
@@ -0,0 +1,65 @@
1
+ /**
2
+ * CloudFunctionWithTrigger composite — CloudFunction + source bucket + optional PubSub/HTTP trigger + invoker IAM.
3
+ */
4
+ import { Composite, mergeDefaults } from "@intentius/chant";
5
+ import { CloudFunction as CloudFunctionResource, StorageBucket, IAMPolicyMember, } from "../generated/index.js";
6
+ export const CloudFunctionWithTrigger = Composite((props) => {
7
+ const { name, runtime, entryPoint, region, availableMemoryMb = "256M", timeout = 60, triggerType = "http", triggerTopic, publicAccess = false, environmentVariables, labels: extraLabels = {}, namespace, defaults: defs, } = props;
8
+ const commonLabels = {
9
+ "app.kubernetes.io/name": name,
10
+ "app.kubernetes.io/managed-by": "chant",
11
+ ...extraLabels,
12
+ };
13
+ const sourceBucket = new StorageBucket(mergeDefaults({
14
+ metadata: {
15
+ name: `${name}-source`,
16
+ ...(namespace && { namespace }),
17
+ labels: { ...commonLabels, "app.kubernetes.io/component": "source" },
18
+ },
19
+ location: region ?? "US",
20
+ uniformBucketLevelAccess: true,
21
+ }, defs?.sourceBucket));
22
+ const eventTrigger = triggerType === "pubsub" && triggerTopic
23
+ ? { eventType: "google.cloud.pubsub.topic.v1.messagePublished", pubsubTopic: triggerTopic }
24
+ : undefined;
25
+ const fn = new CloudFunctionResource(mergeDefaults({
26
+ metadata: {
27
+ name,
28
+ ...(namespace && { namespace }),
29
+ labels: { ...commonLabels, "app.kubernetes.io/component": "function" },
30
+ },
31
+ ...(region && { location: region }),
32
+ runtime,
33
+ entryPoint,
34
+ availableMemoryMb,
35
+ timeout: `${timeout}s`,
36
+ buildConfig: {
37
+ sourceRef: {
38
+ storageBucketRef: { name: `${name}-source` },
39
+ },
40
+ },
41
+ ...(eventTrigger && { eventTrigger }),
42
+ ...(environmentVariables && { environmentVariables }),
43
+ }, defs?.function));
44
+ const result = {
45
+ function: fn,
46
+ sourceBucket,
47
+ };
48
+ if (publicAccess && triggerType === "http") {
49
+ result.invokerIam = new IAMPolicyMember(mergeDefaults({
50
+ metadata: {
51
+ name: `${name}-invoker`,
52
+ ...(namespace && { namespace }),
53
+ labels: { ...commonLabels, "app.kubernetes.io/component": "iam" },
54
+ },
55
+ member: "allUsers",
56
+ role: "roles/cloudfunctions.invoker",
57
+ resourceRef: {
58
+ apiVersion: "cloudfunctions.cnrm.cloud.google.com/v1beta1",
59
+ kind: "CloudFunctionsFunction",
60
+ name,
61
+ },
62
+ }, defs?.invokerIam));
63
+ }
64
+ return result;
65
+ }, "CloudFunctionWithTrigger");
@@ -0,0 +1,71 @@
1
+ /**
2
+ * CloudRunServiceComposite composite — RunService + optional IAMPolicyMember for public access.
3
+ */
4
+ import { Composite, mergeDefaults } from "@intentius/chant";
5
+ import { CloudRunService as CloudRunServiceResource, IAMPolicyMember, } from "../generated/index.js";
6
+ /**
7
+ * Create a CloudRunService composite.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { CloudRunService } from "@intentius/chant-lexicon-gcp";
12
+ *
13
+ * const { service, publicIam } = CloudRunService({
14
+ * name: "my-api",
15
+ * image: "gcr.io/my-project/my-api:latest",
16
+ * publicAccess: true,
17
+ * });
18
+ * ```
19
+ */
20
+ export const CloudRunServiceComposite = Composite((props) => {
21
+ const { name, image, location, port = 8080, cpuLimit = "1000m", memoryLimit = "512Mi", maxInstanceRequestConcurrency = 80, minInstanceCount = 0, maxInstanceCount = 100, publicAccess = false, env, labels: extraLabels = {}, namespace, defaults: defs, } = props;
22
+ const commonLabels = {
23
+ "app.kubernetes.io/name": name,
24
+ "app.kubernetes.io/managed-by": "chant",
25
+ ...extraLabels,
26
+ };
27
+ const containers = [
28
+ {
29
+ image,
30
+ ports: [{ containerPort: port, name: "http1" }],
31
+ resources: {
32
+ limits: { cpu: cpuLimit, memory: memoryLimit },
33
+ },
34
+ ...(env && env.length > 0 && { env }),
35
+ },
36
+ ];
37
+ const service = new CloudRunServiceResource(mergeDefaults({
38
+ metadata: {
39
+ name,
40
+ ...(namespace && { namespace }),
41
+ labels: { ...commonLabels, "app.kubernetes.io/component": "service" },
42
+ },
43
+ ...(location && { location }),
44
+ template: {
45
+ maxInstanceRequestConcurrency,
46
+ scaling: {
47
+ minInstanceCount,
48
+ maxInstanceCount,
49
+ },
50
+ containers,
51
+ },
52
+ }, defs?.service));
53
+ const result = { service };
54
+ if (publicAccess) {
55
+ result.publicIam = new IAMPolicyMember(mergeDefaults({
56
+ metadata: {
57
+ name: `${name}-public`,
58
+ ...(namespace && { namespace }),
59
+ labels: { ...commonLabels, "app.kubernetes.io/component": "iam" },
60
+ },
61
+ member: "allUsers",
62
+ role: "roles/run.invoker",
63
+ resourceRef: {
64
+ apiVersion: "run.cnrm.cloud.google.com/v1beta1",
65
+ kind: "RunService",
66
+ name,
67
+ },
68
+ }, defs?.publicIam));
69
+ }
70
+ return result;
71
+ }, "CloudRunServiceComposite");
@@ -0,0 +1,85 @@
1
+ /**
2
+ * CloudSqlInstance composite — SQLInstance + SQLDatabase + SQLUser.
3
+ */
4
+ import { Composite, mergeDefaults } from "@intentius/chant";
5
+ import { SQLInstance, SQLDatabase, SQLUser } from "../generated/index.js";
6
+ /**
7
+ * Create a CloudSqlInstance composite.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { CloudSqlInstance } from "@intentius/chant-lexicon-gcp";
12
+ *
13
+ * const { instance, database, user } = CloudSqlInstance({
14
+ * name: "my-db",
15
+ * databaseVersion: "POSTGRES_15",
16
+ * tier: "db-custom-2-7680",
17
+ * });
18
+ * ```
19
+ */
20
+ export const CloudSqlInstance = Composite((props) => {
21
+ const { name, databaseVersion = "POSTGRES_15", tier = "db-f1-micro", region, databaseName = name, userName = "admin", diskSize = 10, diskAutoresize = true, backupEnabled = true, highAvailability = false, labels: extraLabels = {}, namespace, defaults: defs, } = props;
22
+ // K8s metadata name must be a valid DNS subdomain (no underscores).
23
+ // When databaseName differs from the instance name, prefix with instance name
24
+ // to guarantee uniqueness across instances sharing the same databaseName.
25
+ const sanitizedDbName = databaseName.replace(/_/g, "-");
26
+ const databaseK8sName = databaseName === name ? sanitizedDbName : `${name}-${sanitizedDbName}`;
27
+ const commonLabels = {
28
+ "app.kubernetes.io/name": name,
29
+ "app.kubernetes.io/managed-by": "chant",
30
+ ...extraLabels,
31
+ };
32
+ const settings = {
33
+ tier,
34
+ diskSize,
35
+ diskAutoresize,
36
+ ...(highAvailability && { availabilityType: "REGIONAL" }),
37
+ };
38
+ if (backupEnabled) {
39
+ settings.backupConfiguration = {
40
+ enabled: true,
41
+ startTime: "03:00",
42
+ };
43
+ }
44
+ const instance = new SQLInstance(mergeDefaults({
45
+ metadata: {
46
+ name,
47
+ ...(namespace && { namespace }),
48
+ labels: { ...commonLabels, "app.kubernetes.io/component": "database" },
49
+ },
50
+ databaseVersion,
51
+ ...(region && { region }),
52
+ settings,
53
+ }, defs?.instance));
54
+ const database = new SQLDatabase(mergeDefaults({
55
+ metadata: {
56
+ name: databaseK8sName,
57
+ ...(namespace && { namespace }),
58
+ labels: { ...commonLabels, "app.kubernetes.io/component": "database" },
59
+ },
60
+ instanceRef: { name },
61
+ // resourceID sets the actual Cloud SQL database name when the K8s-safe name differs
62
+ ...(databaseName !== sanitizedDbName && { resourceID: databaseName }),
63
+ }, defs?.database));
64
+ const user = new SQLUser(mergeDefaults({
65
+ metadata: {
66
+ // K8s name scoped to the instance for uniqueness (e.g. "mydb-admin").
67
+ // Without resourceID, Config Connector uses metadata.name as the actual
68
+ // Cloud SQL username — so the PG username IS the K8s resource name.
69
+ // Callers can override via defaults.user.resourceID if a shorter name is needed.
70
+ name: `${name}-${userName}`,
71
+ ...(namespace && { namespace }),
72
+ labels: { ...commonLabels, "app.kubernetes.io/component": "database" },
73
+ },
74
+ instanceRef: { name },
75
+ password: {
76
+ valueFrom: {
77
+ secretKeyRef: {
78
+ name: `${name}-db-password`,
79
+ key: "password",
80
+ },
81
+ },
82
+ },
83
+ }, defs?.user));
84
+ return { instance, database, user };
85
+ }, "CloudSqlInstance");
@@ -0,0 +1,64 @@
1
+ /**
2
+ * GcsBucket composite — StorageBucket with encryption, uniform access, and lifecycle.
3
+ */
4
+ import { Composite, mergeDefaults } from "@intentius/chant";
5
+ import { StorageBucket } from "../generated/index.js";
6
+ /**
7
+ * Create a GcsBucket composite.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { GcsBucket } from "@intentius/chant-lexicon-gcp";
12
+ *
13
+ * const { bucket } = GcsBucket({
14
+ * name: "my-data-bucket",
15
+ * location: "US",
16
+ * versioning: true,
17
+ * lifecycleDeleteAfterDays: 365,
18
+ * });
19
+ * ```
20
+ */
21
+ export const GcsBucket = Composite((props) => {
22
+ const { name, location = "US", storageClass = "STANDARD", uniformBucketLevelAccess = true, versioning = false, kmsKeyName, lifecycleDeleteAfterDays, lifecycleNearlineAfterDays, labels: extraLabels = {}, namespace, defaults: defs, } = props;
23
+ const commonLabels = {
24
+ "app.kubernetes.io/name": name,
25
+ "app.kubernetes.io/managed-by": "chant",
26
+ ...extraLabels,
27
+ };
28
+ const spec = {
29
+ location,
30
+ storageClass,
31
+ uniformBucketLevelAccess,
32
+ };
33
+ if (versioning) {
34
+ spec.versioning = { enabled: true };
35
+ }
36
+ if (kmsKeyName) {
37
+ spec.encryption = { kmsKeyRef: { external: kmsKeyName } };
38
+ }
39
+ const lifecycleRules = [];
40
+ if (lifecycleDeleteAfterDays) {
41
+ lifecycleRules.push({
42
+ action: { type: "Delete" },
43
+ condition: { age: lifecycleDeleteAfterDays },
44
+ });
45
+ }
46
+ if (lifecycleNearlineAfterDays) {
47
+ lifecycleRules.push({
48
+ action: { type: "SetStorageClass", storageClass: "NEARLINE" },
49
+ condition: { age: lifecycleNearlineAfterDays },
50
+ });
51
+ }
52
+ if (lifecycleRules.length > 0) {
53
+ spec.lifecycleRule = lifecycleRules;
54
+ }
55
+ const bucket = new StorageBucket(mergeDefaults({
56
+ metadata: {
57
+ name,
58
+ ...(namespace && { namespace }),
59
+ labels: { ...commonLabels, "app.kubernetes.io/component": "storage" },
60
+ },
61
+ ...spec,
62
+ }, defs?.bucket));
63
+ return { bucket };
64
+ }, "GcsBucket");
@@ -0,0 +1,113 @@
1
+ /**
2
+ * GkeCluster composite — ContainerCluster + ContainerNodePool.
3
+ *
4
+ * Creates a GKE cluster with a default node pool configured for
5
+ * workload identity and autoscaling.
6
+ */
7
+ import { Composite, mergeDefaults } from "@intentius/chant";
8
+ import { GKECluster, NodePool } from "../generated/index.js";
9
+ /**
10
+ * Create a GkeCluster composite — returns declarable instances for
11
+ * a ContainerCluster and ContainerNodePool.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { GkeCluster } from "@intentius/chant-lexicon-gcp";
16
+ *
17
+ * const { cluster, nodePool } = GkeCluster({
18
+ * name: "my-cluster",
19
+ * projectId: "my-project",
20
+ * location: "us-central1",
21
+ * maxNodeCount: 10,
22
+ * });
23
+ * ```
24
+ */
25
+ export const GkeCluster = Composite((props) => {
26
+ const { name, projectId, location, initialNodeCount = 1, machineType = "e2-medium", minNodeCount = 1, maxNodeCount = 5, workloadIdentity = true, diskSizeGb = 100, diskType = "pd-standard", network: networkName, subnetwork: subnetworkName, privateNodes = false, masterCidr, nodeLocations, releaseChannel = "REGULAR", labels: extraLabels = {}, namespace, defaults: defs, } = props;
27
+ const commonLabels = {
28
+ "app.kubernetes.io/name": name,
29
+ "app.kubernetes.io/managed-by": "chant",
30
+ ...extraLabels,
31
+ };
32
+ const clusterSpec = {
33
+ // GKE API requires initialNodeCount > 0 even when using a separate
34
+ // ContainerNodePool. Force pd-standard so the default pool doesn't
35
+ // consume SSD_TOTAL_GB quota (pd-balanced counts as SSD).
36
+ initialNodeCount: 1,
37
+ nodeConfig: {
38
+ machineType,
39
+ diskType: "pd-standard",
40
+ diskSizeGb: 50,
41
+ },
42
+ releaseChannel: { channel: releaseChannel },
43
+ ...(location && { location }),
44
+ ...(networkName && { networkRef: { name: networkName } }),
45
+ ...(subnetworkName && { subnetworkRef: { name: subnetworkName } }),
46
+ ...(nodeLocations && { nodeLocations }),
47
+ ...(privateNodes && {
48
+ privateClusterConfig: {
49
+ enablePrivateNodes: true,
50
+ // Keep master endpoint public so kubectl works from outside the VPC.
51
+ enablePrivateEndpoint: false,
52
+ ...(masterCidr && { masterIpv4CidrBlock: masterCidr }),
53
+ },
54
+ }),
55
+ };
56
+ if (workloadIdentity) {
57
+ clusterSpec.workloadIdentityConfig = {
58
+ workloadPool: `${projectId}.svc.id.goog`,
59
+ };
60
+ }
61
+ const cluster = new GKECluster(mergeDefaults({
62
+ metadata: {
63
+ name,
64
+ ...(namespace && { namespace }),
65
+ labels: { ...commonLabels, "app.kubernetes.io/component": "cluster" },
66
+ },
67
+ ...clusterSpec,
68
+ }, defs?.cluster));
69
+ const nodePoolName = `${name}-nodes`;
70
+ const nodePool = new NodePool(mergeDefaults({
71
+ metadata: {
72
+ name: nodePoolName,
73
+ ...(namespace && { namespace }),
74
+ labels: { ...commonLabels, "app.kubernetes.io/component": "node-pool" },
75
+ },
76
+ clusterRef: { name },
77
+ initialNodeCount,
78
+ autoscaling: {
79
+ minNodeCount,
80
+ maxNodeCount,
81
+ },
82
+ nodeConfig: {
83
+ machineType,
84
+ diskSizeGb,
85
+ diskType,
86
+ oauthScopes: ["https://www.googleapis.com/auth/cloud-platform"],
87
+ ...(workloadIdentity && {
88
+ workloadMetadataConfig: { mode: "GKE_METADATA" },
89
+ }),
90
+ },
91
+ management: {
92
+ autoRepair: true,
93
+ autoUpgrade: true,
94
+ },
95
+ ...(location && { location }),
96
+ }, defs?.nodePool));
97
+ // Adopt and scale the GKE-required default pool to 0.
98
+ // resourceID maps this K8s resource to the GCP pool named "default-pool".
99
+ // Config Connector retries until the workload pool has nodes, at which
100
+ // point GKE accepts the resize-to-zero.
101
+ const defaultPool = new NodePool(mergeDefaults({
102
+ metadata: {
103
+ name: `${name}-default-pool`,
104
+ ...(namespace && { namespace }),
105
+ labels: { ...commonLabels, "app.kubernetes.io/component": "default-pool" },
106
+ },
107
+ resourceID: "default-pool",
108
+ clusterRef: { name },
109
+ nodeCount: 0,
110
+ ...(location && { location }),
111
+ }, defs?.defaultPool));
112
+ return { cluster, nodePool, defaultPool };
113
+ }, "GkeCluster");
@@ -0,0 +1,137 @@
1
+ /**
2
+ * GkeCrdbRegion composite — GKE cluster + public DNS zone + per-region IAM for a CockroachDB region.
3
+ *
4
+ * Replaces the 2-file per-region GCP infra pattern (infra/cluster.ts + infra/dns.ts) with
5
+ * a single composite call. Handles the GKE cluster, the public DNS zone, and all per-region
6
+ * Workload Identity IAM bindings for both ExternalDNS and CockroachDB pods.
7
+ */
8
+ import { Composite } from "@intentius/chant";
9
+ import { GkeCluster } from "./gke-cluster.js";
10
+ import { DNSManagedZone, GCPServiceAccount, IAMPolicyMember } from "../generated/index.js";
11
+ /**
12
+ * Create a GkeCrdbRegion composite — returns all GCP resources for one CockroachDB region:
13
+ * GKE cluster, public DNS zone, per-region GSAs, and Workload Identity IAM bindings.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { GkeCrdbRegion } from "@intentius/chant-lexicon-gcp";
18
+ *
19
+ * export const east = GkeCrdbRegion({
20
+ * region: "us-east4",
21
+ * clusterName: "gke-crdb-east",
22
+ * network: "crdb-multi-region",
23
+ * subnetwork: "crdb-multi-region-east-nodes",
24
+ * domain: "east.crdb.example.com",
25
+ * project: GCP_PROJECT_ID,
26
+ * crdbNamespace: "crdb-east",
27
+ * masterCidr: "172.16.0.0/28",
28
+ * });
29
+ * ```
30
+ */
31
+ export const GkeCrdbRegion = Composite((props) => {
32
+ const { region, clusterName, network, subnetwork, domain, project, crdbNamespace, crdbK8sSa = "cockroachdb", masterCidr = "172.16.0.0/28", nodeConfig = {}, releaseChannel = "REGULAR", backupBucket, labels: extraLabels = {}, namespace, } = props;
33
+ const { machineType = "n2-standard-2", diskSizeGb = 100, nodeCount = 1, maxNodeCount = 3, } = nodeConfig;
34
+ const commonLabels = {
35
+ "app.kubernetes.io/name": clusterName,
36
+ "app.kubernetes.io/managed-by": "chant",
37
+ ...extraLabels,
38
+ };
39
+ const meta = (component, resourceName) => ({
40
+ name: resourceName,
41
+ ...(namespace && { namespace }),
42
+ labels: { ...commonLabels, "app.kubernetes.io/component": component },
43
+ });
44
+ // ── GKE Cluster ──────────────────────────────────────────────────────────────
45
+ const { cluster, nodePool, defaultPool } = GkeCluster({
46
+ name: clusterName,
47
+ projectId: project,
48
+ location: region,
49
+ machineType,
50
+ diskSizeGb,
51
+ initialNodeCount: nodeCount,
52
+ minNodeCount: nodeCount,
53
+ maxNodeCount,
54
+ network,
55
+ subnetwork,
56
+ workloadIdentity: true,
57
+ privateNodes: true,
58
+ masterCidr,
59
+ releaseChannel,
60
+ labels: extraLabels,
61
+ ...(namespace && { namespace }),
62
+ });
63
+ // ── Public DNS Zone ───────────────────────────────────────────────────────────
64
+ const dnsZoneName = `${clusterName}-zone`;
65
+ const dnsZone = new DNSManagedZone({
66
+ metadata: meta("dns", dnsZoneName),
67
+ dnsName: `${domain}.`,
68
+ description: `CockroachDB ${region} UI — managed by chant`,
69
+ });
70
+ // ── ExternalDNS Service Account ───────────────────────────────────────────────
71
+ const dnsGsaName = `${clusterName}-dns`;
72
+ const dnsGsa = new GCPServiceAccount({
73
+ metadata: meta("iam", dnsGsaName),
74
+ displayName: `CockroachDB ${region} ExternalDNS workload identity`,
75
+ });
76
+ const dnsWiBinding = new IAMPolicyMember({
77
+ metadata: meta("iam", `${dnsGsaName}-wi`),
78
+ member: `serviceAccount:${project}.svc.id.goog[kube-system/external-dns-sa]`,
79
+ role: "roles/iam.workloadIdentityUser",
80
+ resourceRef: {
81
+ apiVersion: "iam.cnrm.cloud.google.com/v1beta1",
82
+ kind: "IAMServiceAccount",
83
+ name: dnsGsaName,
84
+ },
85
+ });
86
+ const dnsAdminBinding = new IAMPolicyMember({
87
+ metadata: meta("iam", `${dnsGsaName}-admin`),
88
+ member: `serviceAccount:${dnsGsaName}@${project}.iam.gserviceaccount.com`,
89
+ role: "roles/dns.admin",
90
+ resourceRef: {
91
+ apiVersion: "resourcemanager.cnrm.cloud.google.com/v1beta1",
92
+ kind: "Project",
93
+ external: `projects/${project}`,
94
+ },
95
+ });
96
+ // ── CockroachDB Service Account ───────────────────────────────────────────────
97
+ const crdbGsaName = `${clusterName}-crdb`;
98
+ const crdbGsa = new GCPServiceAccount({
99
+ metadata: meta("iam", crdbGsaName),
100
+ displayName: `CockroachDB ${region} workload identity`,
101
+ });
102
+ const crdbWiBinding = new IAMPolicyMember({
103
+ metadata: meta("iam", `${crdbGsaName}-wi`),
104
+ member: `serviceAccount:${project}.svc.id.goog[${crdbNamespace}/${crdbK8sSa}]`,
105
+ role: "roles/iam.workloadIdentityUser",
106
+ resourceRef: {
107
+ apiVersion: "iam.cnrm.cloud.google.com/v1beta1",
108
+ kind: "IAMServiceAccount",
109
+ name: crdbGsaName,
110
+ },
111
+ });
112
+ const result = {
113
+ cluster,
114
+ nodePool,
115
+ defaultPool,
116
+ dnsZone,
117
+ dnsGsa,
118
+ dnsWiBinding,
119
+ dnsAdminBinding,
120
+ crdbGsa,
121
+ crdbWiBinding,
122
+ };
123
+ // Optional: GCS backup access for CRDB GSA
124
+ if (backupBucket) {
125
+ result.crdbBackupBinding = new IAMPolicyMember({
126
+ metadata: meta("iam", `${crdbGsaName}-backup`),
127
+ member: `serviceAccount:${crdbGsaName}@${project}.iam.gserviceaccount.com`,
128
+ role: "roles/storage.objectAdmin",
129
+ resourceRef: {
130
+ apiVersion: "storage.cnrm.cloud.google.com/v1beta1",
131
+ kind: "StorageBucket",
132
+ name: backupBucket,
133
+ },
134
+ });
135
+ }
136
+ return result;
137
+ }, "GkeCrdbRegion");
@@ -0,0 +1,74 @@
1
+ /**
2
+ * GpuNodePool composite — ContainerNodePool with GPU accelerators.
3
+ *
4
+ * Promoted from the hand-wired `gpuNodePool` in the ray-kuberay-gke example
5
+ * (examples/ray-kuberay-gke/src/infra/cluster.ts). Attaches to an existing
6
+ * GKE cluster (e.g. one created by `GkeCluster`) and adds a separate,
7
+ * scale-to-zero pool for GPU-tainted workloads.
8
+ *
9
+ * NOTE: GKE auto-installs the nvidia-device-plugin DaemonSet when a node
10
+ * pool has accelerators. Do NOT emit it as a K8s manifest — it will
11
+ * conflict with the GKE-managed version.
12
+ */
13
+ import { Composite, mergeDefaults } from "@intentius/chant";
14
+ import { NodePool } from "../generated/index.js";
15
+ const DEFAULT_TAINT = [
16
+ { key: "nvidia.com/gpu", value: "present", effect: "NO_SCHEDULE" },
17
+ ];
18
+ /**
19
+ * Create a GpuNodePool composite — a scale-to-zero ContainerNodePool with
20
+ * GPU accelerators, tainted so only pods with a matching toleration land there.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * import { GpuNodePool } from "@intentius/chant-lexicon-gcp";
25
+ *
26
+ * const { nodePool } = GpuNodePool({
27
+ * name: "ray-gke-gpu",
28
+ * clusterRef: { name: "ray-gke" },
29
+ * location: "us-central1",
30
+ * acceleratorType: "nvidia-tesla-t4",
31
+ * maxNodeCount: 4,
32
+ * });
33
+ * ```
34
+ */
35
+ export const GpuNodePool = Composite((props) => {
36
+ const { name, clusterRef, location, machineType = "n1-standard-8", acceleratorType = "nvidia-tesla-t4", acceleratorCount = 1, minNodeCount = 0, maxNodeCount = 4, diskSizeGb = 200, diskType = "pd-ssd", taint = DEFAULT_TAINT, workloadMetadata = true, gpuSharingConfig, gpuPartitionSize, labels: extraLabels = {}, namespace, defaults: defs, } = props;
37
+ const commonLabels = {
38
+ "app.kubernetes.io/name": name,
39
+ "app.kubernetes.io/managed-by": "chant",
40
+ ...extraLabels,
41
+ };
42
+ const guestAccelerator = {
43
+ count: acceleratorCount,
44
+ type: acceleratorType,
45
+ ...(gpuSharingConfig && { gpuSharingConfig }),
46
+ ...(gpuPartitionSize && { gpuPartitionSize }),
47
+ };
48
+ const nodePool = new NodePool(mergeDefaults({
49
+ metadata: {
50
+ name,
51
+ ...(namespace && { namespace }),
52
+ labels: { ...commonLabels, "app.kubernetes.io/component": "gpu-node-pool" },
53
+ },
54
+ clusterRef,
55
+ location,
56
+ initialNodeCount: 0,
57
+ autoscaling: {
58
+ minNodeCount,
59
+ maxNodeCount,
60
+ locationPolicy: "ANY",
61
+ },
62
+ nodeConfig: {
63
+ machineType,
64
+ diskSizeGb,
65
+ diskType,
66
+ guestAccelerator: [guestAccelerator],
67
+ ...(taint.length > 0 && { taint }),
68
+ ...(workloadMetadata && { workloadMetadataConfig: { mode: "GKE_METADATA" } }),
69
+ oauthScopes: ["https://www.googleapis.com/auth/cloud-platform"],
70
+ },
71
+ management: { autoRepair: true, autoUpgrade: true },
72
+ }, defs?.nodePool));
73
+ return { nodePool };
74
+ }, "GpuNodePool");
@@ -0,0 +1,15 @@
1
+ export { GovernanceFoundation, LocationRestriction, OrganizationAuditConfig } from "./landing-zone.js";
2
+ export { GkeCluster } from "./gke-cluster.js";
3
+ export { CloudRunServiceComposite } from "./cloud-run-service.js";
4
+ export { CloudSqlInstance } from "./cloud-sql-instance.js";
5
+ export { GcsBucket } from "./gcs-bucket.js";
6
+ export { VpcNetwork } from "./vpc-network.js";
7
+ export { PubSubPipeline } from "./pubsub-pipeline.js";
8
+ export { CloudFunctionWithTrigger } from "./cloud-function.js";
9
+ export { PrivateService } from "./private-service.js";
10
+ export { ManagedCertificate } from "./managed-certificate.js";
11
+ export { SecureProject } from "./secure-project.js";
12
+ export { MemorystoreRedis } from "./memorystore-redis.js";
13
+ export { MultiRegionVpc } from "./multi-region-vpc.js";
14
+ export { GkeCrdbRegion } from "./gke-crdb-region.js";
15
+ export { GpuNodePool } from "./gpu-node-pool.js";