@intentius/chant-lexicon-gcp 0.124.37 → 0.124.39
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/api/read-client.d.ts +14 -1
- package/dist/api/read-client.d.ts.map +1 -1
- package/dist/api/read-client.js +25 -10
- package/dist/composites/catalog.d.ts.map +1 -1
- package/dist/composites/catalog.js +187 -0
- package/dist/composites/index.d.ts +4 -0
- package/dist/composites/index.d.ts.map +1 -1
- package/dist/composites/index.js +2 -0
- package/dist/composites/private-egress-network.d.ts +42 -0
- package/dist/composites/private-egress-network.d.ts.map +1 -0
- package/dist/composites/private-egress-network.js +48 -0
- package/dist/composites/public-cloud-run.d.ts +85 -0
- package/dist/composites/public-cloud-run.d.ts.map +1 -0
- package/dist/composites/public-cloud-run.js +144 -0
- package/dist/deep-observe.d.ts +5 -0
- package/dist/deep-observe.d.ts.map +1 -1
- package/dist/deep-observe.js +37 -3
- package/dist/describe-resources.d.ts +13 -0
- package/dist/describe-resources.d.ts.map +1 -1
- package/dist/describe-resources.js +19 -0
- package/dist/health.d.ts +26 -2
- package/dist/health.d.ts.map +1 -1
- package/dist/health.js +85 -6
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/integrity.json +3 -3
- package/dist/manifest.json +1 -1
- package/dist/op/activities/gcp-apply.d.ts +19 -0
- package/dist/op/activities/gcp-apply.d.ts.map +1 -1
- package/dist/op/activities/gcp-apply.js +16 -0
- package/dist/op/activities/gcp-compute.d.ts +9 -0
- package/dist/op/activities/gcp-compute.d.ts.map +1 -1
- package/dist/op/activities/gcp-compute.js +107 -11
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +6 -2
- package/dist/skills/chant-gcp.md +2 -0
- package/package.json +2 -2
- package/src/api/read-client.ts +30 -9
- package/src/composites/catalog.ts +187 -0
- package/src/composites/cloud-run-lb.test.ts +93 -0
- package/src/composites/index.ts +4 -0
- package/src/composites/private-egress-network.ts +82 -0
- package/src/composites/public-cloud-run.ts +245 -0
- package/src/deep-observe.test.ts +46 -0
- package/src/deep-observe.ts +41 -3
- package/src/describe-resources.ts +23 -1
- package/src/health.test.ts +65 -1
- package/src/health.ts +88 -11
- package/src/index.ts +2 -1
- package/src/op/activities/gcp-apply.ts +31 -1
- package/src/op/activities/gcp-compute-reconcile.test.ts +150 -0
- package/src/op/activities/gcp-compute.test.ts +4 -2
- package/src/op/activities/gcp-compute.ts +129 -11
- package/src/plugin.ts +6 -2
- package/src/project-config.test.ts +50 -3
- package/src/read-refs.test.ts +60 -0
- package/src/skills/chant-gcp.md +2 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PublicCloudRun composite: a Cloud Run service behind a global external
|
|
3
|
+
* Application Load Balancer, running as its own service account with Direct
|
|
4
|
+
* VPC egress into a subnet.
|
|
5
|
+
*/
|
|
6
|
+
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
7
|
+
import { BackendService, ComputeAddress, ForwardingRule, GCPServiceAccount, ManagedSSLCertificate, RegionNetworkEndpointGroup, TargetHTTPProxy, TargetHTTPSProxy, URLMap, } from "../generated/index.js";
|
|
8
|
+
import { GCP } from "../pseudo.js";
|
|
9
|
+
import { CloudRunServiceComposite } from "./cloud-run-service.js";
|
|
10
|
+
/**
|
|
11
|
+
* Create a PublicCloudRun composite.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { PrivateEgressNetwork, PublicCloudRun } from "@intentius/chant-lexicon-gcp";
|
|
16
|
+
*
|
|
17
|
+
* const network = PrivateEgressNetwork({ name: "web", region: "us-central1", subnetCidr: "10.10.0.0/24" });
|
|
18
|
+
* const web = PublicCloudRun({
|
|
19
|
+
* name: "web",
|
|
20
|
+
* projectId: "my-project",
|
|
21
|
+
* region: "us-central1",
|
|
22
|
+
* vpc: network.vpc,
|
|
23
|
+
* subnet: network.subnet,
|
|
24
|
+
* image: "us-docker.pkg.dev/my-project/web/site:1",
|
|
25
|
+
* });
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export const PublicCloudRun = Composite((props) => {
|
|
29
|
+
const { name, image, region, projectId, vpc, subnet, vpcEgress = "PRIVATE_RANGES_ONLY", port = 8080, frontendPort = 80, minInstanceCount = 0, maxInstanceCount = 100, env, serviceAccount, domains, securityPolicy, labels: extraLabels = {}, namespace, defaults: defs, } = props;
|
|
30
|
+
const commonLabels = {
|
|
31
|
+
"app.kubernetes.io/name": name,
|
|
32
|
+
"app.kubernetes.io/managed-by": "chant",
|
|
33
|
+
...extraLabels,
|
|
34
|
+
};
|
|
35
|
+
const meta = (suffix, component) => ({
|
|
36
|
+
name: `${name}-${suffix}`,
|
|
37
|
+
...(namespace && { namespace }),
|
|
38
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": component },
|
|
39
|
+
});
|
|
40
|
+
const result = {};
|
|
41
|
+
if (!serviceAccount) {
|
|
42
|
+
result.runtime = new GCPServiceAccount(mergeDefaults({
|
|
43
|
+
metadata: meta("run", "service-account"),
|
|
44
|
+
displayName: `${name} Cloud Run runtime`,
|
|
45
|
+
}, defs?.runtime));
|
|
46
|
+
}
|
|
47
|
+
const run = CloudRunServiceComposite({
|
|
48
|
+
name: `${name}-site`,
|
|
49
|
+
image,
|
|
50
|
+
projectId,
|
|
51
|
+
location: region,
|
|
52
|
+
port,
|
|
53
|
+
minInstanceCount,
|
|
54
|
+
maxInstanceCount,
|
|
55
|
+
env,
|
|
56
|
+
publicAccess: true,
|
|
57
|
+
serviceAccount: serviceAccount ?? `${name}-run`,
|
|
58
|
+
labels: extraLabels,
|
|
59
|
+
namespace,
|
|
60
|
+
defaults: {
|
|
61
|
+
service: mergeDefaults({
|
|
62
|
+
template: {
|
|
63
|
+
vpcAccess: {
|
|
64
|
+
egress: vpcEgress,
|
|
65
|
+
networkInterfaces: [{ networkRef: { name: vpc.name }, subnetworkRef: { name: subnet.name } }],
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
}, defs?.service),
|
|
69
|
+
publicIam: defs?.publicAccess,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
result.service = run.service;
|
|
73
|
+
result.publicAccess = run.publicIam;
|
|
74
|
+
const neg = new RegionNetworkEndpointGroup(mergeDefaults({
|
|
75
|
+
metadata: meta("neg", "neg"),
|
|
76
|
+
region,
|
|
77
|
+
networkEndpointType: "SERVERLESS",
|
|
78
|
+
cloudRun: { serviceRef: { name: run.service.name } },
|
|
79
|
+
}, defs?.neg));
|
|
80
|
+
// A backend service over a serverless NEG takes no health check: Cloud Run
|
|
81
|
+
// reports its own readiness.
|
|
82
|
+
const backend = new BackendService(mergeDefaults({
|
|
83
|
+
metadata: meta("backend", "backend"),
|
|
84
|
+
location: "global",
|
|
85
|
+
loadBalancingScheme: "EXTERNAL_MANAGED",
|
|
86
|
+
protocol: "HTTP",
|
|
87
|
+
backend: [{ group: { networkEndpointGroupRef: { name: neg.name } } }],
|
|
88
|
+
...(securityPolicy && { securityPolicyRef: { name: securityPolicy } }),
|
|
89
|
+
}, defs?.backend));
|
|
90
|
+
const urlMap = new URLMap(mergeDefaults({
|
|
91
|
+
metadata: meta("map", "url-map"),
|
|
92
|
+
location: "global",
|
|
93
|
+
defaultService: { backendServiceRef: { name: backend.name } },
|
|
94
|
+
}, defs?.urlMap));
|
|
95
|
+
const address = new ComputeAddress(mergeDefaults({
|
|
96
|
+
metadata: meta("ip", "address"),
|
|
97
|
+
location: "global",
|
|
98
|
+
}, defs?.address));
|
|
99
|
+
Object.assign(result, { neg, backend, urlMap, address });
|
|
100
|
+
// With domains, HTTPS serves the URL map and HTTP serves a redirect to it.
|
|
101
|
+
let httpMapName = urlMap.name;
|
|
102
|
+
if (domains && domains.length > 0) {
|
|
103
|
+
const certificate = new ManagedSSLCertificate(mergeDefaults({
|
|
104
|
+
metadata: meta("cert", "certificate"),
|
|
105
|
+
projectRef: { external: projectId ?? GCP.ProjectId },
|
|
106
|
+
managed: { domains },
|
|
107
|
+
}, defs?.certificate));
|
|
108
|
+
const httpsProxy = new TargetHTTPSProxy(mergeDefaults({
|
|
109
|
+
metadata: meta("https-proxy", "proxy"),
|
|
110
|
+
location: "global",
|
|
111
|
+
urlMapRef: { name: urlMap.name },
|
|
112
|
+
sslCertificates: [{ name: certificate.name }],
|
|
113
|
+
}, defs?.httpsProxy));
|
|
114
|
+
const httpsRule = new ForwardingRule(mergeDefaults({
|
|
115
|
+
metadata: meta("https-rule", "forwarding-rule"),
|
|
116
|
+
location: "global",
|
|
117
|
+
loadBalancingScheme: "EXTERNAL_MANAGED",
|
|
118
|
+
portRange: "443",
|
|
119
|
+
ipAddress: { addressRef: { name: address.name } },
|
|
120
|
+
target: { targetHTTPSProxyRef: { name: httpsProxy.name } },
|
|
121
|
+
}, defs?.httpsRule));
|
|
122
|
+
const redirectMap = new URLMap(mergeDefaults({
|
|
123
|
+
metadata: meta("redirect", "url-map"),
|
|
124
|
+
location: "global",
|
|
125
|
+
defaultUrlRedirect: { httpsRedirect: true, stripQuery: false },
|
|
126
|
+
}, defs?.redirectMap));
|
|
127
|
+
httpMapName = redirectMap.name;
|
|
128
|
+
Object.assign(result, { certificate, httpsProxy, httpsRule, redirectMap });
|
|
129
|
+
}
|
|
130
|
+
result.proxy = new TargetHTTPProxy(mergeDefaults({
|
|
131
|
+
metadata: meta("proxy", "proxy"),
|
|
132
|
+
location: "global",
|
|
133
|
+
urlMapRef: { name: httpMapName },
|
|
134
|
+
}, defs?.proxy));
|
|
135
|
+
result.rule = new ForwardingRule(mergeDefaults({
|
|
136
|
+
metadata: meta("rule", "forwarding-rule"),
|
|
137
|
+
location: "global",
|
|
138
|
+
loadBalancingScheme: "EXTERNAL_MANAGED",
|
|
139
|
+
portRange: String(frontendPort),
|
|
140
|
+
ipAddress: { addressRef: { name: address.name } },
|
|
141
|
+
target: { targetHTTPProxyRef: { name: result.proxy.name } },
|
|
142
|
+
}, defs?.rule));
|
|
143
|
+
return result;
|
|
144
|
+
}, "PublicCloudRun");
|
package/dist/deep-observe.d.ts
CHANGED
|
@@ -82,6 +82,11 @@ export declare function restToCnrmShape(body: Record<string, unknown>): Record<s
|
|
|
82
82
|
interface RefineContext {
|
|
83
83
|
project: string;
|
|
84
84
|
restName?: string;
|
|
85
|
+
/** A forwarding rule's declared `ipAddress.addressRef` and that address's live IP (#4238). */
|
|
86
|
+
address?: {
|
|
87
|
+
ip: string;
|
|
88
|
+
ref: unknown;
|
|
89
|
+
};
|
|
85
90
|
}
|
|
86
91
|
/**
|
|
87
92
|
* A REST payload as a CNRM-shaped property tree, in the declared side's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deep-observe.d.ts","sourceRoot":"","sources":["../src/deep-observe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAEH,OAAO,KAAK,EACV,qBAAqB,EAGtB,MAAM,0BAA0B,CAAC;AAKlC,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAajE,OAAO,EAAE,yBAAyB,EAAE,CAAC;AAErC,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWtF;AAUD;6EAC6E;AAC7E,UAAU,aAAa;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"deep-observe.d.ts","sourceRoot":"","sources":["../src/deep-observe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAEH,OAAO,KAAK,EACV,qBAAqB,EAGtB,MAAM,0BAA0B,CAAC;AAKlC,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAajE,OAAO,EAAE,yBAAyB,EAAE,CAAC;AAErC,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWtF;AAUD;6EAC6E;AAC7E,UAAU,aAAa;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8FAA8F;IAC9F,OAAO,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;CACxC;AAgPD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASnH;AA6BD;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA0F5G"}
|
package/dist/deep-observe.js
CHANGED
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
*/
|
|
56
56
|
import { deepObservation, normalizeDeepProperties } from "@intentius/chant/deep-observation";
|
|
57
57
|
import { hasOwnershipMarker } from "@intentius/chant/ownership";
|
|
58
|
-
import { deriveGVK, manifestProjectAnnotations, readTargets, resolveReadProject } from "./describe-resources.js";
|
|
58
|
+
import { deriveGVK, manifestProjectAnnotations, readManifest, readTargets, resolveReadProject } from "./describe-resources.js";
|
|
59
59
|
import { getResource, mapperForKind, GcpReadError, isNotFound } from "./api/read-client.js";
|
|
60
60
|
import { gcpDeepNormalizationHooks } from "./deep-observe-hooks.js";
|
|
61
61
|
/** The labels the applier stamps — see describe-resources.ts. */
|
|
@@ -299,8 +299,14 @@ const CNRM_REFINERS = {
|
|
|
299
299
|
delete tree.gatewayAddress;
|
|
300
300
|
delete tree.fingerprint;
|
|
301
301
|
},
|
|
302
|
-
ComputeForwardingRule(tree) {
|
|
302
|
+
ComputeForwardingRule(tree, ctx) {
|
|
303
303
|
computeLocation(tree);
|
|
304
|
+
// Compute returns the IP; CNRM writes `ipAddress: { addressRef }` or `{ ip }`.
|
|
305
|
+
// The IP is the declared address's own when the read found it so (#4238).
|
|
306
|
+
if (typeof tree.IPAddress === "string") {
|
|
307
|
+
tree.ipAddress = ctx.address && ctx.address.ip === tree.IPAddress ? { addressRef: ctx.address.ref } : { ip: tree.IPAddress };
|
|
308
|
+
delete tree.IPAddress;
|
|
309
|
+
}
|
|
304
310
|
if (tree.IPProtocol !== undefined) {
|
|
305
311
|
tree.ipProtocol = tree.IPProtocol;
|
|
306
312
|
delete tree.IPProtocol;
|
|
@@ -352,6 +358,31 @@ export function toCnrmTree(kind, body, ctx) {
|
|
|
352
358
|
CNRM_REFINERS[kind]?.(tree, { ...ctx, restName });
|
|
353
359
|
return tree;
|
|
354
360
|
}
|
|
361
|
+
/**
|
|
362
|
+
* The live IP of the address a forwarding rule declares in
|
|
363
|
+
* `ipAddress.addressRef`, read with the address's own declaration when the
|
|
364
|
+
* manifest holds it, so the rule's `IPAddress` can be matched to the ref
|
|
365
|
+
* rather than read as drift (#4238). Undefined when there is no ref or the
|
|
366
|
+
* read fails; the rule then shows the IP as it is.
|
|
367
|
+
*/
|
|
368
|
+
async function declaredAddressIp(client, props, manifest) {
|
|
369
|
+
const spec = props.spec ?? props;
|
|
370
|
+
const ref = spec.ipAddress?.addressRef;
|
|
371
|
+
if (!ref)
|
|
372
|
+
return undefined;
|
|
373
|
+
const raw = typeof ref.name === "string" ? ref.name : typeof ref.external === "string" ? ref.external : undefined;
|
|
374
|
+
if (!raw)
|
|
375
|
+
return undefined;
|
|
376
|
+
const name = raw.slice(raw.lastIndexOf("/") + 1);
|
|
377
|
+
const declared = manifest.find((r) => r.kind === "ComputeAddress" && r.metadata?.name === name);
|
|
378
|
+
try {
|
|
379
|
+
const body = await getResource(client, "ComputeAddress", name, declared?.spec ?? { location: spec.location });
|
|
380
|
+
return typeof body.address === "string" ? { ip: body.address, ref } : undefined;
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
return undefined;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
355
386
|
/**
|
|
356
387
|
* Read the live property tree for each declared entity over the applier's
|
|
357
388
|
* REST transport, normalized into the declared CNRM shape (see the module
|
|
@@ -365,6 +396,7 @@ export async function observeResourcesDeepGcp(options) {
|
|
|
365
396
|
const endpoint = process.env.GCP_ENDPOINT_URL;
|
|
366
397
|
const manifestProjects = manifestProjectAnnotations(options.buildOutput);
|
|
367
398
|
const targets = readTargets(options.entities);
|
|
399
|
+
const manifest = readManifest(options.entities, targets);
|
|
368
400
|
const reads = [...options.entities].map(async ([entityName, { entityType }]) => {
|
|
369
401
|
const gvk = deriveGVK(entityType);
|
|
370
402
|
if (!gvk || !mapperForKind(gvk.kind)) {
|
|
@@ -384,6 +416,7 @@ export async function observeResourcesDeepGcp(options) {
|
|
|
384
416
|
client = {
|
|
385
417
|
project: resolveReadProject(gvk.kind, name, metadata, manifestProjects, props),
|
|
386
418
|
...(endpoint ? { endpoint } : {}),
|
|
419
|
+
manifest,
|
|
387
420
|
};
|
|
388
421
|
}
|
|
389
422
|
catch (err) {
|
|
@@ -397,6 +430,7 @@ export async function observeResourcesDeepGcp(options) {
|
|
|
397
430
|
try {
|
|
398
431
|
const obj = await getResource(client, gvk.kind, name, props);
|
|
399
432
|
const labels = obj.labels;
|
|
433
|
+
const address = gvk.kind === "ComputeForwardingRule" ? await declaredAddressIp(client, props, manifest) : undefined;
|
|
400
434
|
// owned filter: withhold what does not carry chant's marker. Withheld is
|
|
401
435
|
// not absent (#1089). Where the payload has no labels at all there is
|
|
402
436
|
// nothing to filter on, so the resource passes through — the same
|
|
@@ -412,7 +446,7 @@ export async function observeResourcesDeepGcp(options) {
|
|
|
412
446
|
resources[entityName] = {
|
|
413
447
|
type: entityType,
|
|
414
448
|
physicalId: obj.id ?? obj.selfLink ?? obj.name,
|
|
415
|
-
properties: normalizeDeepProperties(toCnrmTree(gvk.kind, obj, { project: client.project }), {
|
|
449
|
+
properties: normalizeDeepProperties(toCnrmTree(gvk.kind, obj, { project: client.project, ...(address ? { address } : {}) }), {
|
|
416
450
|
entityType,
|
|
417
451
|
side: "live",
|
|
418
452
|
// The static table is the whole prune here — there is no per-resource
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
* dropped.
|
|
37
37
|
*/
|
|
38
38
|
import type { ObservationResult } from "@intentius/chant/lexicon";
|
|
39
|
+
import { type GcpResource } from "./op/activities/gcp-apply.js";
|
|
39
40
|
/** The parts of a GCP REST payload this reader looks at. Every field is
|
|
40
41
|
* optional because they vary by kind — a bucket has `id` and `labels`, a
|
|
41
42
|
* Pub/Sub topic has neither. */
|
|
@@ -105,6 +106,18 @@ export declare function readTargets(entities: Map<string, {
|
|
|
105
106
|
name: string;
|
|
106
107
|
props: Record<string, unknown>;
|
|
107
108
|
}>;
|
|
109
|
+
/**
|
|
110
|
+
* The declared resources as the applier's manifest holds them (kind, CNRM
|
|
111
|
+
* name, spec), for a read that needs another declared resource: an
|
|
112
|
+
* IAMPolicyMember on a RunService takes the service's region from it (#4251).
|
|
113
|
+
*/
|
|
114
|
+
export declare function readManifest(entities: Map<string, {
|
|
115
|
+
entityType: string;
|
|
116
|
+
props: Record<string, unknown>;
|
|
117
|
+
}>, targets: Map<string, {
|
|
118
|
+
name: string;
|
|
119
|
+
props: Record<string, unknown>;
|
|
120
|
+
}>): GcpResource[];
|
|
108
121
|
/**
|
|
109
122
|
* Status from a REST payload.
|
|
110
123
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"describe-resources.d.ts","sourceRoot":"","sources":["../src/describe-resources.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAsC,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"describe-resources.d.ts","sourceRoot":"","sources":["../src/describe-resources.ts"],"names":[],"mappings":"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"}
|
|
@@ -137,6 +137,23 @@ export function readTargets(entities) {
|
|
|
137
137
|
}
|
|
138
138
|
return out;
|
|
139
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* The declared resources as the applier's manifest holds them (kind, CNRM
|
|
142
|
+
* name, spec), for a read that needs another declared resource: an
|
|
143
|
+
* IAMPolicyMember on a RunService takes the service's region from it (#4251).
|
|
144
|
+
*/
|
|
145
|
+
export function readManifest(entities, targets) {
|
|
146
|
+
const out = [];
|
|
147
|
+
for (const [logical, { entityType }] of entities) {
|
|
148
|
+
const gvk = deriveGVK(entityType);
|
|
149
|
+
const target = targets.get(logical);
|
|
150
|
+
if (!gvk || !target)
|
|
151
|
+
continue;
|
|
152
|
+
const spec = target.props.spec ?? target.props;
|
|
153
|
+
out.push({ kind: gvk.kind, metadata: { name: target.name }, spec });
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
140
157
|
function pruneUndefined(obj) {
|
|
141
158
|
const out = {};
|
|
142
159
|
for (const [k, v] of Object.entries(obj)) {
|
|
@@ -185,6 +202,7 @@ export async function describeResources(options) {
|
|
|
185
202
|
let warnedOwnership = false;
|
|
186
203
|
const manifestProjects = manifestProjectAnnotations(options.buildOutput);
|
|
187
204
|
const targets = readTargets(options.entities);
|
|
205
|
+
const manifest = readManifest(options.entities, targets);
|
|
188
206
|
const reads = [...options.entities].map(async ([entityName, { entityType }]) => {
|
|
189
207
|
const gvk = deriveGVK(entityType);
|
|
190
208
|
if (!gvk) {
|
|
@@ -212,6 +230,7 @@ export async function describeResources(options) {
|
|
|
212
230
|
client = {
|
|
213
231
|
project: resolveReadProject(gvk.kind, name, metadata, manifestProjects, props),
|
|
214
232
|
...(endpoint ? { endpoint } : {}),
|
|
233
|
+
manifest,
|
|
215
234
|
};
|
|
216
235
|
}
|
|
217
236
|
catch (err) {
|
package/dist/health.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Runtime health for GCP (#4177): Cloud Run services
|
|
2
|
+
* Runtime health for GCP (#4177): Cloud Run services; and (#4239) backend
|
|
3
|
+
* services, from `getHealth` on each backend group, and IAM policy members,
|
|
4
|
+
* healthy when the member holds the role in the target's policy.
|
|
3
5
|
*
|
|
4
6
|
* A Cloud Run v2 service carries its `Ready` condition as `terminalCondition`
|
|
5
7
|
* (`CONDITION_SUCCEEDED`, `CONDITION_FAILED`, pending or reconciling). The v1
|
|
@@ -10,7 +12,7 @@
|
|
|
10
12
|
*/
|
|
11
13
|
import type { HealthEntry, HealthReadOptions, HealthReadResult } from "@intentius/chant/lexicon";
|
|
12
14
|
import { type GcpReadHttp } from "./api/read-client.js";
|
|
13
|
-
export declare const GCP_HEALTH_TYPES: readonly ["GCP::Run::Service"];
|
|
15
|
+
export declare const GCP_HEALTH_TYPES: readonly ["GCP::Run::Service", "GCP::Compute::BackendService", "GCP::Iam::PolicyMember"];
|
|
14
16
|
export interface GcpHealthOptions extends HealthReadOptions {
|
|
15
17
|
http?: GcpReadHttp;
|
|
16
18
|
now?: () => Date;
|
|
@@ -37,6 +39,28 @@ export interface CloudRunServiceState {
|
|
|
37
39
|
}
|
|
38
40
|
/** The `Ready` condition's verdict. No condition at all is `unknown`. */
|
|
39
41
|
export declare function cloudRunEntry(body: CloudRunServiceState, observedAt: string): HealthEntry;
|
|
42
|
+
/** One backend group's `getHealth` answer: `healthStatus[].healthState` per endpoint. */
|
|
43
|
+
export interface BackendGroupHealth {
|
|
44
|
+
group: string;
|
|
45
|
+
healthStatus?: Array<{
|
|
46
|
+
healthState?: string;
|
|
47
|
+
}>;
|
|
48
|
+
/** Set when the call failed; the group then counts as unknown. */
|
|
49
|
+
error?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A backend service's verdict from its groups: any endpoint `UNHEALTHY` is
|
|
53
|
+
* unhealthy; every endpoint `HEALTHY`, with at least one, is healthy; anything
|
|
54
|
+
* else (no backends, a group that reports no status, as a serverless NEG
|
|
55
|
+
* does, a failed call) is unknown.
|
|
56
|
+
*/
|
|
57
|
+
export declare function backendServiceEntry(groups: readonly BackendGroupHealth[], observedAt: string): HealthEntry;
|
|
58
|
+
/** A binding the read found in its target's policy. A missing one is `absent`, never here. */
|
|
59
|
+
export declare function policyMemberEntry(binding: {
|
|
60
|
+
role?: string;
|
|
61
|
+
member?: string;
|
|
62
|
+
resource?: string;
|
|
63
|
+
}, observedAt: string): HealthEntry;
|
|
40
64
|
export declare function observeHealthGcp(options: GcpHealthOptions): Promise<HealthReadResult>;
|
|
41
65
|
export {};
|
|
42
66
|
//# sourceMappingURL=health.d.ts.map
|
package/dist/health.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,gBAAgB,EAAoB,MAAM,0BAA0B,CAAC;AACnH,OAAO,EAAkD,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrG,eAAO,MAAM,gBAAgB,YAAI,mBAAmB,EAAE,8BAA8B,EAAE,wBAAwB,CAAU,CAAC;AAEzH,MAAM,WAAW,gBAAiB,SAAQ,iBAAiB;IACzD,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,UAAU,SAAS;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,gEAAgE;AAChE,MAAM,WAAW,oBAAoB;IACnC,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACrD;AAOD,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,IAAI,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,GAAG,WAAW,CAqBzF;AAED,yFAAyF;AACzF,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,WAAW,CAkB1G;AAED,8FAA8F;AAC9F,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,UAAU,EAAE,MAAM,GAAG,WAAW,CAOjI;AA6BD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAqD3F"}
|
package/dist/health.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Runtime health for GCP (#4177): Cloud Run services
|
|
2
|
+
* Runtime health for GCP (#4177): Cloud Run services; and (#4239) backend
|
|
3
|
+
* services, from `getHealth` on each backend group, and IAM policy members,
|
|
4
|
+
* healthy when the member holds the role in the target's policy.
|
|
3
5
|
*
|
|
4
6
|
* A Cloud Run v2 service carries its `Ready` condition as `terminalCondition`
|
|
5
7
|
* (`CONDITION_SUCCEEDED`, `CONDITION_FAILED`, pending or reconciling). The v1
|
|
@@ -8,9 +10,9 @@
|
|
|
8
10
|
* project resolution and endpoint rule as `describe-resources.ts`, so
|
|
9
11
|
* `GCP_ENDPOINT_URL` (floci-gcp) answers.
|
|
10
12
|
*/
|
|
11
|
-
import { getResource, GcpReadError, isNotFound } from "./api/read-client.js";
|
|
12
|
-
import { deriveGVK, manifestProjectAnnotations, readTargets, resolveReadProject } from "./describe-resources.js";
|
|
13
|
-
export const GCP_HEALTH_TYPES = ["GCP::Run::Service"];
|
|
13
|
+
import { getResource, GcpReadError, isNotFound, readUrl } from "./api/read-client.js";
|
|
14
|
+
import { deriveGVK, manifestProjectAnnotations, readManifest, readTargets, resolveReadProject } from "./describe-resources.js";
|
|
15
|
+
export const GCP_HEALTH_TYPES = ["GCP::Run::Service", "GCP::Compute::BackendService", "GCP::Iam::PolicyMember"];
|
|
14
16
|
function readyCondition(body) {
|
|
15
17
|
if (body.terminalCondition && (body.terminalCondition.type ?? "Ready") === "Ready")
|
|
16
18
|
return body.terminalCondition;
|
|
@@ -39,6 +41,72 @@ export function cloudRunEntry(body, observedAt) {
|
|
|
39
41
|
...(ready.lastTransitionTime ? { checkedAt: ready.lastTransitionTime } : {}),
|
|
40
42
|
};
|
|
41
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* A backend service's verdict from its groups: any endpoint `UNHEALTHY` is
|
|
46
|
+
* unhealthy; every endpoint `HEALTHY`, with at least one, is healthy; anything
|
|
47
|
+
* else (no backends, a group that reports no status, as a serverless NEG
|
|
48
|
+
* does, a failed call) is unknown.
|
|
49
|
+
*/
|
|
50
|
+
export function backendServiceEntry(groups, observedAt) {
|
|
51
|
+
const type = "GCP::Compute::BackendService";
|
|
52
|
+
if (groups.length === 0)
|
|
53
|
+
return { type, state: "unknown", detail: "no backends", observedAt };
|
|
54
|
+
let healthy = 0;
|
|
55
|
+
let unhealthy = 0;
|
|
56
|
+
let unknown = 0;
|
|
57
|
+
for (const g of groups) {
|
|
58
|
+
const states = g.error ? [] : (g.healthStatus ?? []).map((h) => (h.healthState ?? "").toUpperCase());
|
|
59
|
+
if (states.length === 0)
|
|
60
|
+
unknown++;
|
|
61
|
+
else if (states.some((st) => st === "UNHEALTHY"))
|
|
62
|
+
unhealthy++;
|
|
63
|
+
else if (states.every((st) => st === "HEALTHY"))
|
|
64
|
+
healthy++;
|
|
65
|
+
else
|
|
66
|
+
unknown++;
|
|
67
|
+
}
|
|
68
|
+
const state = unhealthy > 0 ? "unhealthy" : healthy === groups.length ? "healthy" : "unknown";
|
|
69
|
+
const parts = [`${healthy} of ${groups.length} backend${groups.length === 1 ? "" : "s"} healthy`];
|
|
70
|
+
if (unhealthy)
|
|
71
|
+
parts.push(`${unhealthy} unhealthy`);
|
|
72
|
+
if (unknown)
|
|
73
|
+
parts.push(`${unknown} with no health status`);
|
|
74
|
+
return { type, state, detail: parts.join(", "), observedAt };
|
|
75
|
+
}
|
|
76
|
+
/** A binding the read found in its target's policy. A missing one is `absent`, never here. */
|
|
77
|
+
export function policyMemberEntry(binding, observedAt) {
|
|
78
|
+
return {
|
|
79
|
+
type: "GCP::Iam::PolicyMember",
|
|
80
|
+
state: "healthy",
|
|
81
|
+
detail: `${binding.member ?? "member"} holds ${binding.role ?? "the role"}${binding.resource ? ` on ${binding.resource}` : ""}`,
|
|
82
|
+
observedAt,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const defaultReadHttp = async (method, url, body) => {
|
|
86
|
+
const res = await fetch(url, {
|
|
87
|
+
method,
|
|
88
|
+
...(body === undefined ? {} : { headers: { "content-type": "application/json" }, body: JSON.stringify(body) }),
|
|
89
|
+
});
|
|
90
|
+
return { status: res.status, text: await res.text() };
|
|
91
|
+
};
|
|
92
|
+
/** `getHealth` for each of a backend service's groups, at the service's own read URL. */
|
|
93
|
+
async function backendGroupsHealth(url, body, http) {
|
|
94
|
+
const backends = Array.isArray(body.backends) ? body.backends : [];
|
|
95
|
+
return Promise.all(backends
|
|
96
|
+
.map((b) => b.group)
|
|
97
|
+
.filter((g) => typeof g === "string")
|
|
98
|
+
.map(async (group) => {
|
|
99
|
+
try {
|
|
100
|
+
const res = await http("POST", `${url}/getHealth`, { group });
|
|
101
|
+
if (res.status < 200 || res.status >= 300)
|
|
102
|
+
return { group, error: `getHealth ${res.status}` };
|
|
103
|
+
return { group, ...JSON.parse(res.text) };
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
return { group, error: err instanceof Error ? err.message : String(err) };
|
|
107
|
+
}
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
42
110
|
export async function observeHealthGcp(options) {
|
|
43
111
|
const observedAt = (options.now?.() ?? new Date()).toISOString();
|
|
44
112
|
const endpoint = process.env.GCP_ENDPOINT_URL;
|
|
@@ -47,6 +115,7 @@ export async function observeHealthGcp(options) {
|
|
|
47
115
|
const unobserved = {};
|
|
48
116
|
const absent = [];
|
|
49
117
|
const targets = readTargets(options.entities);
|
|
118
|
+
const manifest = readManifest(options.entities, targets);
|
|
50
119
|
await Promise.all([...options.entities].map(async ([entityName, { entityType }]) => {
|
|
51
120
|
const gvk = deriveGVK(entityType);
|
|
52
121
|
const { name, props } = targets.get(entityName);
|
|
@@ -64,8 +133,18 @@ export async function observeHealthGcp(options) {
|
|
|
64
133
|
return;
|
|
65
134
|
}
|
|
66
135
|
try {
|
|
67
|
-
const
|
|
68
|
-
|
|
136
|
+
const client = { project, ...(endpoint ? { endpoint } : {}), ...(options.http ? { http: options.http } : {}), manifest };
|
|
137
|
+
const body = await getResource(client, gvk.kind, name, props);
|
|
138
|
+
if (gvk.kind === "ComputeBackendService") {
|
|
139
|
+
const groups = await backendGroupsHealth(readUrl(client, gvk.kind, name, props), body, options.http ?? defaultReadHttp);
|
|
140
|
+
entities[entityName] = backendServiceEntry(groups, observedAt);
|
|
141
|
+
}
|
|
142
|
+
else if (gvk.kind === "IAMPolicyMember") {
|
|
143
|
+
entities[entityName] = policyMemberEntry(body, observedAt);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
entities[entityName] = cloudRunEntry(body, observedAt);
|
|
147
|
+
}
|
|
69
148
|
}
|
|
70
149
|
catch (err) {
|
|
71
150
|
if (isNotFound(err)) {
|
package/dist/index.d.ts
CHANGED
|
@@ -7,8 +7,8 @@ export { GCP, ProjectId, Region, Zone } from "./pseudo.js";
|
|
|
7
7
|
export { GcpAnnotations } from "./variables.js";
|
|
8
8
|
export { LexiconOutput, output, isLexiconOutput } from "@intentius/chant/lexicon-output";
|
|
9
9
|
export * from "./generated/index.js";
|
|
10
|
-
export { GkeCluster, CloudRunServiceComposite, CloudSqlInstance, GcsBucket, VpcNetwork, PubSubPipeline, CloudFunctionWithTrigger, PrivateService, ManagedCertificate, SecureProject, MemorystoreRedis, MultiRegionVpc, GkeCrdbRegion, GpuNodePool, GovernanceFoundation, LocationRestriction, OrganizationAuditConfig, } from "./composites/index.js";
|
|
11
|
-
export type { GkeClusterProps, CloudRunServiceProps, CloudSqlInstanceProps, GcsBucketProps, VpcNetworkProps, VpcSubnet, PubSubPipelineProps, CloudFunctionWithTriggerProps, PrivateServiceProps, ManagedCertificateProps, SecureProjectProps, MemorystoreRedisProps, MultiRegionVpcConfig, MultiRegionVpcRegion, GkeCrdbRegionConfig, GkeCrdbRegionNodeConfig, GpuNodePoolProps, GpuNodePoolTaint, GovernanceFoundationProps, LocationRestrictionProps, OrganizationAuditConfigProps, } from "./composites/index.js";
|
|
10
|
+
export { GkeCluster, CloudRunServiceComposite, CloudSqlInstance, GcsBucket, VpcNetwork, PubSubPipeline, CloudFunctionWithTrigger, PrivateService, ManagedCertificate, SecureProject, MemorystoreRedis, MultiRegionVpc, GkeCrdbRegion, GpuNodePool, PrivateEgressNetwork, PublicCloudRun, GovernanceFoundation, LocationRestriction, OrganizationAuditConfig, } from "./composites/index.js";
|
|
11
|
+
export type { GkeClusterProps, CloudRunServiceProps, CloudSqlInstanceProps, GcsBucketProps, VpcNetworkProps, VpcSubnet, PubSubPipelineProps, CloudFunctionWithTriggerProps, PrivateServiceProps, ManagedCertificateProps, SecureProjectProps, MemorystoreRedisProps, MultiRegionVpcConfig, MultiRegionVpcRegion, GkeCrdbRegionConfig, GkeCrdbRegionNodeConfig, GpuNodePoolProps, GpuNodePoolTaint, PrivateEgressNetworkProps, PublicCloudRunProps, GovernanceFoundationProps, LocationRestrictionProps, OrganizationAuditConfigProps, } from "./composites/index.js";
|
|
12
12
|
export { landingZoneConfig, resourceLocationRestriction, DISABLE_SA_KEY_CREATION, SKIP_DEFAULT_NETWORK, AUDIT_ALL_SERVICES, FOUNDATION_FOLDERS, } from "./governance.js";
|
|
13
13
|
export type { GcpGovernanceConfig, LandingZoneConfigProps, FolderConfig, OrgPolicyConfig, ProjectConfig } from "./governance.js";
|
|
14
14
|
export { StorageRoles, ComputeRoles, ContainerRoles, IAMRoles, SQLRoles, RunRoles, PubSubRoles } from "./actions/index.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG9E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG7C,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGrC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC5G,OAAO,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAGrF,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAGxD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7C,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAIzF,cAAc,mBAAmB,CAAC;AAGlC,OAAO,EACL,UAAU,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,SAAS,EAAE,UAAU,EAC7E,cAAc,EAAE,wBAAwB,EAAE,cAAc,EAAE,kBAAkB,EAAE,aAAa,EAC3F,gBAAgB,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG9E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG7C,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGrC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC5G,OAAO,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAGrF,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAGxD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7C,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAIzF,cAAc,mBAAmB,CAAC;AAGlC,OAAO,EACL,UAAU,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,SAAS,EAAE,UAAU,EAC7E,cAAc,EAAE,wBAAwB,EAAE,cAAc,EAAE,kBAAkB,EAAE,aAAa,EAC3F,gBAAgB,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,oBAAoB,EAAE,cAAc,EAClG,oBAAoB,EAAE,mBAAmB,EAAE,uBAAuB,GACnE,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,EACd,eAAe,EAAE,SAAS,EAC1B,mBAAmB,EACnB,6BAA6B,EAC7B,mBAAmB,EACnB,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EAAE,oBAAoB,EAC1C,mBAAmB,EAAE,uBAAuB,EAC5C,gBAAgB,EAAE,gBAAgB,EAClC,yBAAyB,EAAE,mBAAmB,EAC9C,yBAAyB,EAAE,wBAAwB,EAAE,4BAA4B,GAClF,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EACL,iBAAiB,EAAE,2BAA2B,EAC9C,uBAAuB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,kBAAkB,GACtF,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG9H,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGxH,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC1G,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGrI,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvE,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@ export { LexiconOutput, output, isLexiconOutput } from "@intentius/chant/lexicon
|
|
|
21
21
|
// After running `npm run generate`, this re-exports all Config Connector resource classes
|
|
22
22
|
export * from "./generated/index.js";
|
|
23
23
|
// Composites
|
|
24
|
-
export { GkeCluster, CloudRunServiceComposite, CloudSqlInstance, GcsBucket, VpcNetwork, PubSubPipeline, CloudFunctionWithTrigger, PrivateService, ManagedCertificate, SecureProject, MemorystoreRedis, MultiRegionVpc, GkeCrdbRegion, GpuNodePool, GovernanceFoundation, LocationRestriction, OrganizationAuditConfig, } from "./composites/index.js";
|
|
24
|
+
export { GkeCluster, CloudRunServiceComposite, CloudSqlInstance, GcsBucket, VpcNetwork, PubSubPipeline, CloudFunctionWithTrigger, PrivateService, ManagedCertificate, SecureProject, MemorystoreRedis, MultiRegionVpc, GkeCrdbRegion, GpuNodePool, PrivateEgressNetwork, PublicCloudRun, GovernanceFoundation, LocationRestriction, OrganizationAuditConfig, } from "./composites/index.js";
|
|
25
25
|
// GCP governance authoring: the desired-state config an external governance
|
|
26
26
|
// reconciler applies, and the typed landing-zone authoring layer.
|
|
27
27
|
export { landingZoneConfig, resourceLocationRestriction, DISABLE_SA_KEY_CREATION, SKIP_DEFAULT_NETWORK, AUDIT_ALL_SERVICES, FOUNDATION_FOLDERS, } from "./governance.js";
|
package/dist/integrity.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "sha256",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
4
|
+
"manifest.json": "f3591792043dc8b5c86d1c30c694b09225546ef08cd7a2c9856718ea094d6259",
|
|
5
5
|
"meta.json": "75643660010c044c6f465bef2688a864ab30cc96fd9b68111969749748ac64ca",
|
|
6
6
|
"types/index.d.ts": "da1ebc6bcf83e1a018a773b59714194aeeb74ae1d5c1252b737b7e730ca98bd5",
|
|
7
7
|
"rules/hardcoded-project.ts": "6d5ae9efa74d73800eebe1a0a0d43c619ee0fdebe3347195df93fcbe63b34f0d",
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
"rules/wgc501.ts": "bf99d8dc97537687fdfe9a8d5eb420172bf3279a4147311037f9c1d1f5fd4c85",
|
|
36
36
|
"rules/wgc502.ts": "6460a028f73ef31a66653954e67142079130112b70fa01a79f80464968a1b9f6",
|
|
37
37
|
"rules/wgc503.ts": "44dc51efbf9f9384b61a4e19b173b4c182557143cb59fbaf4da087e70a38f916",
|
|
38
|
-
"skills/chant-gcp.md": "
|
|
38
|
+
"skills/chant-gcp.md": "da90cf5982451652bd0f0ad51563c248379824a77bd49c9ecbadbb37a82a29e1",
|
|
39
39
|
"skills/chant-gcp-security.md": "39a1c97b7425ed43b081257132449d11ce9d12f2d4755fc30d8b14bbc38f60bd",
|
|
40
40
|
"skills/chant-gcp-patterns.md": "4c6809fc7c37fa1879379ad4c0e2d114dec9497bc6eb9d1bca4e79fddea4f509",
|
|
41
41
|
"skills/chant-gcp-gke.md": "be277019da9a722c851e47cd2dfb9c9536668948c3535fb20db7697e934c4e2b"
|
|
42
42
|
},
|
|
43
|
-
"composite": "
|
|
43
|
+
"composite": "73e7ca62da8ef9beafa48e58b549248bd5b24abd37f1a4bb180de513b7319acc"
|
|
44
44
|
}
|
package/dist/manifest.json
CHANGED
|
@@ -86,7 +86,25 @@ export interface ApplyPlan {
|
|
|
86
86
|
url: string;
|
|
87
87
|
body: unknown;
|
|
88
88
|
};
|
|
89
|
+
/**
|
|
90
|
+
* In place of `update`, for a resource whose update depends on the live body
|
|
91
|
+
* (#4238): compute updates carry the live `fingerprint`, and some fields only
|
|
92
|
+
* change through a setter (`setTarget`, `setLabels`). Returns the requests to
|
|
93
|
+
* send, none when the live resource already matches, or `replace` naming what
|
|
94
|
+
* differs on a field that can't change in place.
|
|
95
|
+
*/
|
|
96
|
+
reconcile?(live: unknown, http: GcpHttp, signal?: AbortSignal): Promise<ReconcileStep>;
|
|
89
97
|
}
|
|
98
|
+
/** What {@link ApplyPlan.reconcile} decided for an existing resource. */
|
|
99
|
+
export type ReconcileStep = {
|
|
100
|
+
requests: Array<{
|
|
101
|
+
method: "POST" | "PATCH" | "PUT";
|
|
102
|
+
url: string;
|
|
103
|
+
body: unknown;
|
|
104
|
+
}>;
|
|
105
|
+
} | {
|
|
106
|
+
replace: string;
|
|
107
|
+
};
|
|
90
108
|
/**
|
|
91
109
|
* Handles an async create whose response is a long-running operation. Present
|
|
92
110
|
* only on mappers for resources that provision asynchronously (Cloud Run, GKE,
|
|
@@ -280,6 +298,7 @@ export declare function applyResource(mapper: ResourceMapper, resource: GcpResou
|
|
|
280
298
|
name: string;
|
|
281
299
|
created: boolean;
|
|
282
300
|
updated: boolean;
|
|
301
|
+
replaceRequired?: string;
|
|
283
302
|
}>;
|
|
284
303
|
/**
|
|
285
304
|
* Poll a long-running operation until it reports done (or errors / times out).
|