@caelo-cms/provisioning 0.10.37 → 0.10.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/admin-domain.d.ts +21 -3
- package/dist/admin-domain.d.ts.map +1 -1
- package/dist/admin-domain.js +88 -16
- package/dist/admin-domain.js.map +1 -1
- package/dist/cert-wait.d.ts +84 -0
- package/dist/cert-wait.d.ts.map +1 -0
- package/dist/cert-wait.js +95 -0
- package/dist/cert-wait.js.map +1 -0
- package/dist/cli.js +146 -23
- package/dist/cli.js.map +1 -1
- package/dist/dns/groups.d.ts +36 -0
- package/dist/dns/groups.d.ts.map +1 -0
- package/dist/dns/groups.js +46 -0
- package/dist/dns/groups.js.map +1 -0
- package/dist/gcloud-components.d.ts +42 -0
- package/dist/gcloud-components.d.ts.map +1 -0
- package/dist/gcloud-components.js +53 -0
- package/dist/gcloud-components.js.map +1 -0
- package/dist/gcloud.d.ts +14 -0
- package/dist/gcloud.d.ts.map +1 -1
- package/dist/gcloud.js +18 -5
- package/dist/gcloud.js.map +1 -1
- package/dist/install-state.d.ts +8 -0
- package/dist/install-state.d.ts.map +1 -1
- package/dist/install-state.js +5 -0
- package/dist/install-state.js.map +1 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +19 -3
- package/dist/lifecycle.js.map +1 -1
- package/dist/redirects-emit.d.ts +0 -13
- package/dist/redirects-emit.d.ts.map +1 -1
- package/dist/redirects-emit.js +19 -0
- package/dist/redirects-emit.js.map +1 -1
- package/dist/regions.d.ts.map +1 -1
- package/dist/regions.js +4 -1
- package/dist/regions.js.map +1 -1
- package/dist/runtime-secrets.d.ts +13 -1
- package/dist/runtime-secrets.d.ts.map +1 -1
- package/dist/runtime-secrets.js +40 -4
- package/dist/runtime-secrets.js.map +1 -1
- package/dist/self-hosted-roles.d.ts.map +1 -1
- package/dist/self-hosted-roles.js +2 -0
- package/dist/self-hosted-roles.js.map +1 -1
- package/dist/stack-contract.d.ts +16 -2
- package/dist/stack-contract.d.ts.map +1 -1
- package/dist/stack-contract.js +24 -1
- package/dist/stack-contract.js.map +1 -1
- package/dist/wizard.d.ts +5 -19
- package/dist/wizard.d.ts.map +1 -1
- package/dist/wizard.js +45 -1
- package/dist/wizard.js.map +1 -1
- package/dist/wizards/gcp-pulumi.d.ts +2 -0
- package/dist/wizards/gcp-pulumi.d.ts.map +1 -1
- package/dist/wizards/gcp-pulumi.js +6 -0
- package/dist/wizards/gcp-pulumi.js.map +1 -1
- package/dist/wizards/gcp.d.ts.map +1 -1
- package/dist/wizards/gcp.js +129 -112
- package/dist/wizards/gcp.js.map +1 -1
- package/package.json +3 -3
- package/stacks/gcp/index.ts +20 -3
- package/stacks/gcp-firebase/index.ts +20 -5
- package/stacks/self-hosted/index.ts +3 -1
package/dist/admin-domain.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `cms-provision admin-domain enable` — serve a gcp-firebase admin at
|
|
3
|
-
* `admin.<domain>` instead of its `*.run.app` URL
|
|
3
|
+
* `admin.<domain>` instead of its `*.run.app` URL — and, the same way,
|
|
4
|
+
* `cms-provision staging-domain enable` (#650): serve the protected staging
|
|
5
|
+
* site at `staging.<domain>` from the gateway, which gates and proxies it.
|
|
4
6
|
*
|
|
5
7
|
* The gcp-firebase stack only creates that Cloud Run domain mapping behind
|
|
6
8
|
* `provisionAdminDomain=true`, off by default: Google refuses a mapping
|
|
@@ -44,11 +46,27 @@ export type AdminDomainResult = {
|
|
|
44
46
|
status: "failed";
|
|
45
47
|
error: string;
|
|
46
48
|
};
|
|
47
|
-
|
|
49
|
+
/** What `staging-domain enable` reports; same shape as the admin's. */
|
|
50
|
+
export type StagingDomainResult = AdminDomainResult;
|
|
51
|
+
interface DomainOpts {
|
|
48
52
|
projectId: string;
|
|
49
53
|
region: string;
|
|
50
54
|
domain: string;
|
|
51
55
|
run?: Run;
|
|
52
|
-
|
|
56
|
+
/** Progress lines (the one-time `beta` component install); defaults to stdout. */
|
|
57
|
+
log?: (message: string) => void;
|
|
58
|
+
}
|
|
59
|
+
export declare function enableAdminDomain(opts: DomainOpts): Promise<AdminDomainResult>;
|
|
60
|
+
/**
|
|
61
|
+
* #650 — map the install's staging host (its setting, default
|
|
62
|
+
* `staging.<domain>`; any FQDN) to the gateway, which serves the protected
|
|
63
|
+
* staging site. Cloud Run refuses domain-mapped requests while a service's
|
|
64
|
+
* ingress is internal-only, so the gateway's ingress is opened first (the
|
|
65
|
+
* stack declares the same since #650; installs from before keep the old
|
|
66
|
+
* value until this runs). Idempotent like the admin mapping.
|
|
67
|
+
*/
|
|
68
|
+
export declare function enableStagingDomain(opts: DomainOpts & {
|
|
69
|
+
stagingHost: string;
|
|
70
|
+
}): Promise<StagingDomainResult>;
|
|
53
71
|
export {};
|
|
54
72
|
//# sourceMappingURL=admin-domain.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-domain.d.ts","sourceRoot":"","sources":["../src/admin-domain.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"admin-domain.d.ts","sourceRoot":"","sources":["../src/admin-domain.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAA2B,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAGzE,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,cAAc,EAAE,CAAA;CAAE,GACnF;IAAE,MAAM,EAAE,oBAAoB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACxE;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAExC,uEAAuE;AACvE,MAAM,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AAepD,UAAU,UAAU;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,kFAAkF;IAClF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AA2CD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAMpF;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,UAAU,GAAG;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,GACzC,OAAO,CAAC,mBAAmB,CAAC,CAwC9B"}
|
package/dist/admin-domain.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MPL-2.0
|
|
2
2
|
/**
|
|
3
3
|
* `cms-provision admin-domain enable` — serve a gcp-firebase admin at
|
|
4
|
-
* `admin.<domain>` instead of its `*.run.app` URL
|
|
4
|
+
* `admin.<domain>` instead of its `*.run.app` URL — and, the same way,
|
|
5
|
+
* `cms-provision staging-domain enable` (#650): serve the protected staging
|
|
6
|
+
* site at `staging.<domain>` from the gateway, which gates and proxies it.
|
|
5
7
|
*
|
|
6
8
|
* The gcp-firebase stack only creates that Cloud Run domain mapping behind
|
|
7
9
|
* `provisionAdminDomain=true`, off by default: Google refuses a mapping
|
|
@@ -26,6 +28,7 @@
|
|
|
26
28
|
* from the start.
|
|
27
29
|
*/
|
|
28
30
|
import { gcloud as defaultGcloud } from "./gcloud.js";
|
|
31
|
+
import { ensureGcloudComponent } from "./gcloud-components.js";
|
|
29
32
|
function recordsOf(json, hostname) {
|
|
30
33
|
const parsed = JSON.parse(json);
|
|
31
34
|
return (parsed.status?.resourceRecords ?? []).map((r) => ({
|
|
@@ -34,36 +37,105 @@ function recordsOf(json, hostname) {
|
|
|
34
37
|
value: r.rrdata ?? "",
|
|
35
38
|
}));
|
|
36
39
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
function logOf(opts) {
|
|
41
|
+
return opts.log ?? ((message) => console.log(message));
|
|
42
|
+
}
|
|
43
|
+
/** The one deployed Cloud Run service of `slug` (Pulumi-suffixed name). */
|
|
44
|
+
async function findService(run, scope, slug) {
|
|
45
|
+
const prefix = `caelo-production-${slug}`;
|
|
41
46
|
const services = await run([
|
|
42
47
|
"run",
|
|
43
48
|
"services",
|
|
44
49
|
"list",
|
|
45
50
|
...scope,
|
|
46
|
-
|
|
51
|
+
`--filter=metadata.name~^${prefix}`,
|
|
47
52
|
"--format=value(metadata.name)",
|
|
48
53
|
]);
|
|
49
54
|
if (!services.ok) {
|
|
50
|
-
return {
|
|
55
|
+
return { ok: false, error: `list Cloud Run services: ${services.stderr.trim()}` };
|
|
51
56
|
}
|
|
52
57
|
const matches = services.stdout
|
|
53
58
|
.split("\n")
|
|
54
59
|
.map((s) => s.trim())
|
|
55
60
|
.filter(Boolean);
|
|
56
|
-
// Fail closed like the other
|
|
57
|
-
// failed deploy, picking one would bind the domain to the wrong revision.
|
|
61
|
+
// Fail closed like the other service lookups: with a leftover service from
|
|
62
|
+
// a failed deploy, picking one would bind the domain to the wrong revision.
|
|
58
63
|
const service = matches.length === 1 ? matches[0] : undefined;
|
|
59
64
|
if (!service) {
|
|
60
65
|
return {
|
|
61
|
-
|
|
66
|
+
ok: false,
|
|
62
67
|
error: matches.length === 0
|
|
63
|
-
?
|
|
64
|
-
: `expected exactly one
|
|
68
|
+
? `${slug} Cloud Run service not found: no ${prefix}* service`
|
|
69
|
+
: `expected exactly one ${prefix}* Cloud Run service, found ${matches.length} (${matches.join(", ")}); delete the stale one first`,
|
|
65
70
|
};
|
|
66
71
|
}
|
|
72
|
+
return { ok: true, service };
|
|
73
|
+
}
|
|
74
|
+
export async function enableAdminDomain(opts) {
|
|
75
|
+
const run = opts.run ?? defaultGcloud;
|
|
76
|
+
const scope = [`--region=${opts.region}`, `--project=${opts.projectId}`];
|
|
77
|
+
const found = await findService(run, scope, "admin");
|
|
78
|
+
if (!found.ok)
|
|
79
|
+
return { status: "failed", error: found.error };
|
|
80
|
+
return mapDomain(run, logOf(opts), scope, opts.domain, `admin.${opts.domain}`, found.service);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* #650 — map the install's staging host (its setting, default
|
|
84
|
+
* `staging.<domain>`; any FQDN) to the gateway, which serves the protected
|
|
85
|
+
* staging site. Cloud Run refuses domain-mapped requests while a service's
|
|
86
|
+
* ingress is internal-only, so the gateway's ingress is opened first (the
|
|
87
|
+
* stack declares the same since #650; installs from before keep the old
|
|
88
|
+
* value until this runs). Idempotent like the admin mapping.
|
|
89
|
+
*/
|
|
90
|
+
export async function enableStagingDomain(opts) {
|
|
91
|
+
const run = opts.run ?? defaultGcloud;
|
|
92
|
+
const scope = [`--region=${opts.region}`, `--project=${opts.projectId}`];
|
|
93
|
+
const found = await findService(run, scope, "gateway");
|
|
94
|
+
if (!found.ok)
|
|
95
|
+
return { status: "failed", error: found.error };
|
|
96
|
+
const ingress = await run([
|
|
97
|
+
"run",
|
|
98
|
+
"services",
|
|
99
|
+
"describe",
|
|
100
|
+
found.service,
|
|
101
|
+
...scope,
|
|
102
|
+
'--format=value(metadata.annotations["run.googleapis.com/ingress"])',
|
|
103
|
+
]);
|
|
104
|
+
if (!ingress.ok) {
|
|
105
|
+
return { status: "failed", error: `read the gateway's ingress: ${ingress.stderr.trim()}` };
|
|
106
|
+
}
|
|
107
|
+
if (ingress.stdout.trim() !== "all") {
|
|
108
|
+
const update = await run([
|
|
109
|
+
"run",
|
|
110
|
+
"services",
|
|
111
|
+
"update",
|
|
112
|
+
found.service,
|
|
113
|
+
...scope,
|
|
114
|
+
"--ingress=all",
|
|
115
|
+
"--quiet",
|
|
116
|
+
]);
|
|
117
|
+
if (!update.ok) {
|
|
118
|
+
return {
|
|
119
|
+
status: "failed",
|
|
120
|
+
error: `open the gateway's ingress for the domain mapping: ${update.stderr.trim()}`,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Search Console verification: the install domain covers its own
|
|
125
|
+
// subdomains; a host on another domain is verified itself.
|
|
126
|
+
const verifyDomain = opts.stagingHost === opts.domain || opts.stagingHost.endsWith(`.${opts.domain}`)
|
|
127
|
+
? opts.domain
|
|
128
|
+
: opts.stagingHost;
|
|
129
|
+
return mapDomain(run, logOf(opts), scope, verifyDomain, opts.stagingHost, found.service);
|
|
130
|
+
}
|
|
131
|
+
/** Steps 2–4 of the module doc for `hostname` → `service`. */
|
|
132
|
+
async function mapDomain(run, log, scope, domain, hostname, service) {
|
|
133
|
+
// Fully managed Cloud Run domain mappings exist only on the beta track: the
|
|
134
|
+
// GA `gcloud run domain-mappings` is Cloud Run for Anthos only. Install the
|
|
135
|
+
// component up front instead of letting gcloud ask for it mid-command.
|
|
136
|
+
const beta = await ensureGcloudComponent("beta", { run, log });
|
|
137
|
+
if (!beta.ok)
|
|
138
|
+
return { status: "failed", error: beta.error };
|
|
67
139
|
const describeArgs = [
|
|
68
140
|
"beta",
|
|
69
141
|
"run",
|
|
@@ -88,15 +160,15 @@ export async function enableAdminDomain(opts) {
|
|
|
88
160
|
return { status: "failed", error: `list verified domains: ${verified.stderr.trim()}` };
|
|
89
161
|
}
|
|
90
162
|
const verifiedIds = verified.stdout.split("\n").map((s) => s.trim());
|
|
91
|
-
if (!verifiedIds.includes(
|
|
92
|
-
const verify = await run(["domains", "verify",
|
|
163
|
+
if (!verifiedIds.includes(domain) && !verifiedIds.includes(hostname)) {
|
|
164
|
+
const verify = await run(["domains", "verify", domain]);
|
|
93
165
|
if (!verify.ok) {
|
|
94
166
|
return {
|
|
95
167
|
status: "failed",
|
|
96
|
-
error: `start domain verification for ${
|
|
168
|
+
error: `start domain verification for ${domain}: ${verify.stderr.trim()}`,
|
|
97
169
|
};
|
|
98
170
|
}
|
|
99
|
-
return { status: "needs-verification", hostname, verifyDomain:
|
|
171
|
+
return { status: "needs-verification", hostname, verifyDomain: domain };
|
|
100
172
|
}
|
|
101
173
|
const create = await run([
|
|
102
174
|
"beta",
|
package/dist/admin-domain.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-domain.js","sourceRoot":"","sources":["../src/admin-domain.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAEnC
|
|
1
|
+
{"version":3,"file":"admin-domain.js","sourceRoot":"","sources":["../src/admin-domain.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Waiting for a Google-managed TLS certificate (§11.C: the CLI polls certs
|
|
3
|
+
* itself instead of telling the operator to check back later).
|
|
4
|
+
*
|
|
5
|
+
* Two certificate sources, one wait loop:
|
|
6
|
+
* - the `gcp` load balancer's managed SSL certificates
|
|
7
|
+
* ({@link lbCertProbe}) — the installer waits for the admin host;
|
|
8
|
+
* - a Cloud Run domain mapping's certificate ({@link domainMappingProbe})
|
|
9
|
+
* — `admin-domain enable` / `staging-domain enable` on gcp-firebase.
|
|
10
|
+
*
|
|
11
|
+
* {@link waitForCert} is pure apart from its injected clock, sleep and
|
|
12
|
+
* probe, so the timeout and progress behaviour is unit-tested without
|
|
13
|
+
* gcloud or real time.
|
|
14
|
+
*/
|
|
15
|
+
import type { GcloudResult } from "./gcloud.js";
|
|
16
|
+
type Run = (args: string[]) => Promise<GcloudResult>;
|
|
17
|
+
/** One look at a certificate. */
|
|
18
|
+
export type CertProbe = {
|
|
19
|
+
readonly state: "ready";
|
|
20
|
+
} | {
|
|
21
|
+
readonly state: "pending";
|
|
22
|
+
readonly detail: string;
|
|
23
|
+
}
|
|
24
|
+
/** gcloud itself failed (auth, permissions) — waiting will not fix it. */
|
|
25
|
+
| {
|
|
26
|
+
readonly state: "error";
|
|
27
|
+
readonly error: string;
|
|
28
|
+
};
|
|
29
|
+
export type CertWaitResult = {
|
|
30
|
+
readonly ok: true;
|
|
31
|
+
} | {
|
|
32
|
+
readonly ok: false;
|
|
33
|
+
readonly reason: "timeout";
|
|
34
|
+
readonly lastDetail: string;
|
|
35
|
+
} | {
|
|
36
|
+
readonly ok: false;
|
|
37
|
+
readonly reason: "error";
|
|
38
|
+
readonly error: string;
|
|
39
|
+
};
|
|
40
|
+
export interface CertWaitOpts {
|
|
41
|
+
readonly probe: () => Promise<CertProbe>;
|
|
42
|
+
readonly timeoutMs: number;
|
|
43
|
+
readonly intervalMs: number;
|
|
44
|
+
/** Called whenever the probe's detail text changes (spinner message). */
|
|
45
|
+
readonly onUpdate?: (detail: string) => void;
|
|
46
|
+
readonly sleep?: (ms: number) => Promise<void>;
|
|
47
|
+
readonly now?: () => number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Poll `probe` until the certificate is ready, gcloud fails, or `timeoutMs`
|
|
51
|
+
* passes. The probe runs once more at the deadline so a certificate that
|
|
52
|
+
* flips during the last interval is not reported as a timeout.
|
|
53
|
+
*/
|
|
54
|
+
export declare function waitForCert(opts: CertWaitOpts): Promise<CertWaitResult>;
|
|
55
|
+
/**
|
|
56
|
+
* The certificate state of the Cloud Run domain mapping for `hostname`.
|
|
57
|
+
* Ready once the mapping's `Ready` condition is True (Google sets it after
|
|
58
|
+
* `CertificateProvisioned` and `DomainRoutable`); until then the detail is
|
|
59
|
+
* the first non-True condition's message, which says what Google waits for
|
|
60
|
+
* (usually the DNS record).
|
|
61
|
+
*/
|
|
62
|
+
export declare function domainMappingProbe(run: Run, target: {
|
|
63
|
+
readonly hostname: string;
|
|
64
|
+
readonly region: string;
|
|
65
|
+
readonly projectId: string;
|
|
66
|
+
}): Promise<CertProbe>;
|
|
67
|
+
/**
|
|
68
|
+
* Whether the `gcp` load balancer has an ACTIVE managed certificate that
|
|
69
|
+
* covers `hostname`. Any such certificate counts: installs from before the
|
|
70
|
+
* admin got its own certificate serve the admin from the combined one.
|
|
71
|
+
* A certificate is only served once its overall status is ACTIVE, so a
|
|
72
|
+
* combined certificate whose other domain still fails does not count.
|
|
73
|
+
*/
|
|
74
|
+
export declare function lbCertProbe(run: Run, target: {
|
|
75
|
+
readonly projectId: string;
|
|
76
|
+
readonly hostname: string;
|
|
77
|
+
}): Promise<CertProbe>;
|
|
78
|
+
/**
|
|
79
|
+
* How long the CLI waits for a certificate before handing the operator the
|
|
80
|
+
* status command. Google documents up to 60 min after DNS resolves.
|
|
81
|
+
*/
|
|
82
|
+
export declare const CERT_WAIT_TIMEOUT_MS: number;
|
|
83
|
+
export {};
|
|
84
|
+
//# sourceMappingURL=cert-wait.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cert-wait.d.ts","sourceRoot":"","sources":["../src/cert-wait.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAErD,iCAAiC;AACjC,MAAM,MAAM,SAAS,GACjB;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAC3B;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACxD,0EAA0E;GACxE;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;CAAE,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC/E;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CAiB7E;AASD;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,GAAG,EACR,MAAM,EAAE;IAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACzF,OAAO,CAAC,SAAS,CAAC,CAwBpB;AAOD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,GAAG,EACR,MAAM,EAAE;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAChE,OAAO,CAAC,SAAS,CAAC,CA+BpB;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,QAAiB,CAAC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Poll `probe` until the certificate is ready, gcloud fails, or `timeoutMs`
|
|
4
|
+
* passes. The probe runs once more at the deadline so a certificate that
|
|
5
|
+
* flips during the last interval is not reported as a timeout.
|
|
6
|
+
*/
|
|
7
|
+
export async function waitForCert(opts) {
|
|
8
|
+
const now = opts.now ?? Date.now;
|
|
9
|
+
const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
10
|
+
const deadline = now() + opts.timeoutMs;
|
|
11
|
+
let lastDetail = "";
|
|
12
|
+
for (;;) {
|
|
13
|
+
const p = await opts.probe();
|
|
14
|
+
if (p.state === "ready")
|
|
15
|
+
return { ok: true };
|
|
16
|
+
if (p.state === "error")
|
|
17
|
+
return { ok: false, reason: "error", error: p.error };
|
|
18
|
+
if (p.detail !== lastDetail) {
|
|
19
|
+
lastDetail = p.detail;
|
|
20
|
+
opts.onUpdate?.(p.detail);
|
|
21
|
+
}
|
|
22
|
+
const remaining = deadline - now();
|
|
23
|
+
if (remaining <= 0)
|
|
24
|
+
return { ok: false, reason: "timeout", lastDetail };
|
|
25
|
+
await sleep(Math.min(opts.intervalMs, remaining));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The certificate state of the Cloud Run domain mapping for `hostname`.
|
|
30
|
+
* Ready once the mapping's `Ready` condition is True (Google sets it after
|
|
31
|
+
* `CertificateProvisioned` and `DomainRoutable`); until then the detail is
|
|
32
|
+
* the first non-True condition's message, which says what Google waits for
|
|
33
|
+
* (usually the DNS record).
|
|
34
|
+
*/
|
|
35
|
+
export async function domainMappingProbe(run, target) {
|
|
36
|
+
const r = await run([
|
|
37
|
+
"beta",
|
|
38
|
+
"run",
|
|
39
|
+
"domain-mappings",
|
|
40
|
+
"describe",
|
|
41
|
+
`--domain=${target.hostname}`,
|
|
42
|
+
`--region=${target.region}`,
|
|
43
|
+
`--project=${target.projectId}`,
|
|
44
|
+
"--format=json",
|
|
45
|
+
]);
|
|
46
|
+
if (!r.ok)
|
|
47
|
+
return { state: "error", error: `describe the domain mapping: ${r.stderr.trim()}` };
|
|
48
|
+
const conditions = JSON.parse(r.stdout).status?.conditions ??
|
|
49
|
+
[];
|
|
50
|
+
const ready = conditions.find((c) => c.type === "Ready");
|
|
51
|
+
if (ready?.status === "True")
|
|
52
|
+
return { state: "ready" };
|
|
53
|
+
const blocking = conditions.find((c) => c.type === "CertificateProvisioned" && c.status !== "True") ??
|
|
54
|
+
conditions.find((c) => c.status !== "True");
|
|
55
|
+
const detail = blocking
|
|
56
|
+
? `${blocking.type}: ${blocking.message || blocking.reason || blocking.status || "pending"}`
|
|
57
|
+
: "Google has not reported the mapping's status yet";
|
|
58
|
+
return { state: "pending", detail };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Whether the `gcp` load balancer has an ACTIVE managed certificate that
|
|
62
|
+
* covers `hostname`. Any such certificate counts: installs from before the
|
|
63
|
+
* admin got its own certificate serve the admin from the combined one.
|
|
64
|
+
* A certificate is only served once its overall status is ACTIVE, so a
|
|
65
|
+
* combined certificate whose other domain still fails does not count.
|
|
66
|
+
*/
|
|
67
|
+
export async function lbCertProbe(run, target) {
|
|
68
|
+
const r = await run([
|
|
69
|
+
"compute",
|
|
70
|
+
"ssl-certificates",
|
|
71
|
+
"list",
|
|
72
|
+
"--global",
|
|
73
|
+
`--project=${target.projectId}`,
|
|
74
|
+
"--format=json",
|
|
75
|
+
]);
|
|
76
|
+
if (!r.ok)
|
|
77
|
+
return { state: "error", error: `list SSL certificates: ${r.stderr.trim()}` };
|
|
78
|
+
const covering = JSON.parse(r.stdout).filter((c) => c.managed?.domainStatus?.[target.hostname] !== undefined);
|
|
79
|
+
if (covering.some((c) => c.managed?.status === "ACTIVE" && c.managed.domainStatus?.[target.hostname] === "ACTIVE")) {
|
|
80
|
+
return { state: "ready" };
|
|
81
|
+
}
|
|
82
|
+
if (covering.length === 0) {
|
|
83
|
+
return { state: "pending", detail: `no managed certificate lists ${target.hostname} yet` };
|
|
84
|
+
}
|
|
85
|
+
const detail = covering
|
|
86
|
+
.map((c) => `${c.name ?? "certificate"}: ${target.hostname} ${c.managed?.domainStatus?.[target.hostname]}`)
|
|
87
|
+
.join("; ");
|
|
88
|
+
return { state: "pending", detail };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* How long the CLI waits for a certificate before handing the operator the
|
|
92
|
+
* status command. Google documents up to 60 min after DNS resolves.
|
|
93
|
+
*/
|
|
94
|
+
export const CERT_WAIT_TIMEOUT_MS = 60 * 60 * 1000;
|
|
95
|
+
//# sourceMappingURL=cert-wait.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cert-wait.js","sourceRoot":"","sources":["../src/cert-wait.ts"],"names":[],"mappings":"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"}
|