@microagi/alchemy-gcp 0.1.2
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/LICENSE +201 -0
- package/README.md +88 -0
- package/lib/Auth/AuthProvider.d.ts +48 -0
- package/lib/Auth/AuthProvider.d.ts.map +1 -0
- package/lib/Auth/AuthProvider.js +84 -0
- package/lib/Auth/AuthProvider.js.map +1 -0
- package/lib/Auth/Credentials.d.ts +28 -0
- package/lib/Auth/Credentials.d.ts.map +1 -0
- package/lib/Auth/Credentials.js +41 -0
- package/lib/Auth/Credentials.js.map +1 -0
- package/lib/CloudResourceManager/Project.d.ts +143 -0
- package/lib/CloudResourceManager/Project.d.ts.map +1 -0
- package/lib/CloudResourceManager/Project.js +272 -0
- package/lib/CloudResourceManager/Project.js.map +1 -0
- package/lib/CloudResourceManager/index.d.ts +3 -0
- package/lib/CloudResourceManager/index.d.ts.map +1 -0
- package/lib/CloudResourceManager/index.js +2 -0
- package/lib/CloudResourceManager/index.js.map +1 -0
- package/lib/Compute/GlobalAddress.d.ts +101 -0
- package/lib/Compute/GlobalAddress.d.ts.map +1 -0
- package/lib/Compute/GlobalAddress.js +134 -0
- package/lib/Compute/GlobalAddress.js.map +1 -0
- package/lib/Compute/Network.d.ts +114 -0
- package/lib/Compute/Network.d.ts.map +1 -0
- package/lib/Compute/Network.js +145 -0
- package/lib/Compute/Network.js.map +1 -0
- package/lib/Compute/Operations.d.ts +34 -0
- package/lib/Compute/Operations.d.ts.map +1 -0
- package/lib/Compute/Operations.js +62 -0
- package/lib/Compute/Operations.js.map +1 -0
- package/lib/Compute/SharedVpcHost.d.ts +44 -0
- package/lib/Compute/SharedVpcHost.d.ts.map +1 -0
- package/lib/Compute/SharedVpcHost.js +71 -0
- package/lib/Compute/SharedVpcHost.js.map +1 -0
- package/lib/Compute/SharedVpcServiceProject.d.ts +46 -0
- package/lib/Compute/SharedVpcServiceProject.d.ts.map +1 -0
- package/lib/Compute/SharedVpcServiceProject.js +96 -0
- package/lib/Compute/SharedVpcServiceProject.js.map +1 -0
- package/lib/Compute/Subnetwork.d.ts +108 -0
- package/lib/Compute/Subnetwork.d.ts.map +1 -0
- package/lib/Compute/Subnetwork.js +201 -0
- package/lib/Compute/Subnetwork.js.map +1 -0
- package/lib/Compute/index.d.ts +6 -0
- package/lib/Compute/index.d.ts.map +1 -0
- package/lib/Compute/index.js +6 -0
- package/lib/Compute/index.js.map +1 -0
- package/lib/Container/Cluster.d.ts +216 -0
- package/lib/Container/Cluster.d.ts.map +1 -0
- package/lib/Container/Cluster.js +326 -0
- package/lib/Container/Cluster.js.map +1 -0
- package/lib/Container/NodePool.d.ts +214 -0
- package/lib/Container/NodePool.d.ts.map +1 -0
- package/lib/Container/NodePool.js +344 -0
- package/lib/Container/NodePool.js.map +1 -0
- package/lib/Container/Operations.d.ts +50 -0
- package/lib/Container/Operations.d.ts.map +1 -0
- package/lib/Container/Operations.js +51 -0
- package/lib/Container/Operations.js.map +1 -0
- package/lib/Container/index.d.ts +5 -0
- package/lib/Container/index.d.ts.map +1 -0
- package/lib/Container/index.js +3 -0
- package/lib/Container/index.js.map +1 -0
- package/lib/Parallelstore/Instance.d.ts +119 -0
- package/lib/Parallelstore/Instance.d.ts.map +1 -0
- package/lib/Parallelstore/Instance.js +180 -0
- package/lib/Parallelstore/Instance.js.map +1 -0
- package/lib/Parallelstore/index.d.ts +2 -0
- package/lib/Parallelstore/index.d.ts.map +1 -0
- package/lib/Parallelstore/index.js +2 -0
- package/lib/Parallelstore/index.js.map +1 -0
- package/lib/Providers.d.ts +24 -0
- package/lib/Providers.d.ts.map +1 -0
- package/lib/Providers.js +51 -0
- package/lib/Providers.js.map +1 -0
- package/lib/ServiceNetworking/PsaConnection.d.ts +84 -0
- package/lib/ServiceNetworking/PsaConnection.d.ts.map +1 -0
- package/lib/ServiceNetworking/PsaConnection.js +130 -0
- package/lib/ServiceNetworking/PsaConnection.js.map +1 -0
- package/lib/ServiceNetworking/index.d.ts +2 -0
- package/lib/ServiceNetworking/index.d.ts.map +1 -0
- package/lib/ServiceNetworking/index.js +2 -0
- package/lib/ServiceNetworking/index.js.map +1 -0
- package/lib/ServiceUsage/ApiEnable.d.ts +78 -0
- package/lib/ServiceUsage/ApiEnable.d.ts.map +1 -0
- package/lib/ServiceUsage/ApiEnable.js +132 -0
- package/lib/ServiceUsage/ApiEnable.js.map +1 -0
- package/lib/ServiceUsage/index.d.ts +3 -0
- package/lib/ServiceUsage/index.d.ts.map +1 -0
- package/lib/ServiceUsage/index.js +2 -0
- package/lib/ServiceUsage/index.js.map +1 -0
- package/lib/Tags.d.ts +57 -0
- package/lib/Tags.d.ts.map +1 -0
- package/lib/Tags.js +106 -0
- package/lib/Tags.js.map +1 -0
- package/lib/index.d.ts +11 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +10 -0
- package/lib/index.js.map +1 -0
- package/package.json +70 -0
- package/src/Auth/AuthProvider.ts +180 -0
- package/src/Auth/Credentials.ts +69 -0
- package/src/CloudResourceManager/Project.ts +517 -0
- package/src/CloudResourceManager/index.ts +2 -0
- package/src/Compute/GlobalAddress.ts +283 -0
- package/src/Compute/Network.ts +306 -0
- package/src/Compute/Operations.ts +108 -0
- package/src/Compute/SharedVpcHost.ts +141 -0
- package/src/Compute/SharedVpcServiceProject.ts +185 -0
- package/src/Compute/Subnetwork.ts +375 -0
- package/src/Compute/index.ts +5 -0
- package/src/Container/Cluster.ts +599 -0
- package/src/Container/NodePool.ts +620 -0
- package/src/Container/Operations.ts +88 -0
- package/src/Container/index.ts +8 -0
- package/src/Parallelstore/Instance.ts +371 -0
- package/src/Parallelstore/index.ts +1 -0
- package/src/Providers.ts +84 -0
- package/src/ServiceNetworking/PsaConnection.ts +269 -0
- package/src/ServiceNetworking/index.ts +1 -0
- package/src/ServiceUsage/ApiEnable.ts +267 -0
- package/src/ServiceUsage/index.ts +2 -0
- package/src/Tags.ts +130 -0
- package/src/index.ts +16 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../../src/CloudResourceManager/Project.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAKnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAM7C,OAAO,KAAK,KAAK,GAAG,MAAM,iBAAiB,CAAC;AAE5C;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC,MAAM,MAAM,YAAY,GAAG;IACzB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,MAAM,EAAE,aAAa,CAAC;IACtB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,cAAc,CAAC,EAAE,kBAAkB,CAAC;CACrC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,MAAM,EAAE,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,MAAM,OAAO,GAAG,QAAQ,CAC5B,aAAa,EACb,YAAY,EACZ;IACE,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,aAAa,EAAE,GAAG,MAAM,EAAE,CAAC;IAC3B,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B;;;;OAIG;IACH,cAAc,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAC/C;;;;;OAKG;IACH,cAAc,EAAE,OAAO,CAAC;CACzB,EACD,KAAK,EACL,GAAG,CAAC,SAAS,CACd,CAAC;AAEF,eAAO,MAAM,OAAO,0CAAmC,CAAC;AAwCxD,eAAO,MAAM,eAAe,8NA6TzB,CAAC"}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { ConfigError } from "@distilled.cloud/gcp";
|
|
2
|
+
import * as billing from "@distilled.cloud/gcp/cloudbilling-v1";
|
|
3
|
+
import * as crm from "@distilled.cloud/gcp/cloudresourcemanager-v3";
|
|
4
|
+
import { Resource } from "alchemy";
|
|
5
|
+
import { Unowned } from "alchemy/AdoptPolicy";
|
|
6
|
+
import { isResolved } from "alchemy/Diff";
|
|
7
|
+
import { createPhysicalName } from "alchemy/PhysicalName";
|
|
8
|
+
import * as Provider from "alchemy/Provider";
|
|
9
|
+
import { diffTags } from "alchemy/Tags";
|
|
10
|
+
import * as Duration from "effect/Duration";
|
|
11
|
+
import * as Effect from "effect/Effect";
|
|
12
|
+
import * as Schedule from "effect/Schedule";
|
|
13
|
+
import { gcpInternalLabels, hasAlchemyLabels } from "../Tags.js";
|
|
14
|
+
export const Project = Resource("GCP.Project");
|
|
15
|
+
const parentToString = (parent) => parent.type === "folder" ? `folders/${parent.id}` : `organizations/${parent.id}`;
|
|
16
|
+
const createProjectId = (id, override) => Effect.gen(function* () {
|
|
17
|
+
if (override)
|
|
18
|
+
return override;
|
|
19
|
+
// GCP project IDs: 6-30 chars, lowercase letters/digits/hyphens,
|
|
20
|
+
// must start with a letter. `createPhysicalName` already prepends
|
|
21
|
+
// the stack name (which conventionally starts with a letter), so
|
|
22
|
+
// the first-letter rule is satisfied by construction.
|
|
23
|
+
return (yield* createPhysicalName({ id, maxLength: 30 })).toLowerCase();
|
|
24
|
+
});
|
|
25
|
+
const toAttributes = (p, billingInfo) => ({
|
|
26
|
+
projectId: p.projectId,
|
|
27
|
+
// GCP returns the project number as a digit-only string. The cast
|
|
28
|
+
// safely narrows from `string` to `` `${number}` `` — server-side
|
|
29
|
+
// contract guarantees the shape (the empty-string fallback is a
|
|
30
|
+
// belt-and-braces guard for malformed responses; downstream code
|
|
31
|
+
// observes a project state of "ACTIVE" before consuming this).
|
|
32
|
+
projectNumber: (p.name?.replace(/^projects\//, "") ?? "0"),
|
|
33
|
+
name: p.name ?? `projects/${p.projectId}`,
|
|
34
|
+
displayName: p.displayName,
|
|
35
|
+
state: p.state ?? "ACTIVE",
|
|
36
|
+
parent: p.parent ?? "",
|
|
37
|
+
createTime: p.createTime,
|
|
38
|
+
labels: { ...(p.labels ?? {}) },
|
|
39
|
+
// GCP returns `billingAccountName` as a plain string but its format
|
|
40
|
+
// is always `billingAccounts/{id}` — narrow at the boundary.
|
|
41
|
+
billingAccount: (billingInfo?.billingAccountName || undefined),
|
|
42
|
+
billingEnabled: billingInfo?.billingEnabled ?? false,
|
|
43
|
+
});
|
|
44
|
+
export const ProjectProvider = () => Provider.effect(Project, Effect.gen(function* () {
|
|
45
|
+
// Acquire SDK clients ONCE — Credentials and HttpClient are
|
|
46
|
+
// resolved at provider construction, not on every reconcile.
|
|
47
|
+
const getProjects = yield* crm.getProjects;
|
|
48
|
+
const createProjects = yield* crm.createProjects;
|
|
49
|
+
const patchProjects = yield* crm.patchProjects;
|
|
50
|
+
const deleteProjects = yield* crm.deleteProjects;
|
|
51
|
+
const getOperations = yield* crm.getOperations;
|
|
52
|
+
const getBillingInfo = yield* billing.getBillingInfoProjects;
|
|
53
|
+
const updateBillingInfo = yield* billing.updateBillingInfoProjects;
|
|
54
|
+
const awaitOperation = Effect.fn(function* (operationName, session) {
|
|
55
|
+
const op = yield* getOperations({ name: operationName }).pipe(Effect.flatMap((current) => current.done === true
|
|
56
|
+
? Effect.succeed(current)
|
|
57
|
+
: Effect.fail({ _tag: "OperationPending" })), Effect.retry({
|
|
58
|
+
while: (e) => e?._tag === "OperationPending",
|
|
59
|
+
schedule: Schedule.exponential(Duration.seconds(1), 1.5).pipe(Schedule.both(Schedule.recurs(60)), Schedule.tapOutput(() => session.note(`Waiting for GCP operation ${operationName}…`))),
|
|
60
|
+
}));
|
|
61
|
+
if (op.error) {
|
|
62
|
+
return yield* new ConfigError({
|
|
63
|
+
message: `GCP operation ${operationName} failed: ${op.error.message ?? JSON.stringify(op.error)}`,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return op;
|
|
67
|
+
});
|
|
68
|
+
const observeProject = (projectId) => getProjects({ name: `projects/${projectId}` }).pipe(
|
|
69
|
+
// GCP returns 403 Forbidden (not 404) when a project ID is
|
|
70
|
+
// unknown or invisible to the caller — a deliberate choice to
|
|
71
|
+
// avoid leaking project-ID existence across tenants. From this
|
|
72
|
+
// provider's perspective both shapes mean "not present", so
|
|
73
|
+
// observation should treat them identically.
|
|
74
|
+
Effect.catchTag("NotFound", () => Effect.succeed(undefined)), Effect.catchTag("Forbidden", () => Effect.succeed(undefined)),
|
|
75
|
+
// A project marked for deletion is still readable but in
|
|
76
|
+
// `DELETE_REQUESTED` state. Treat as missing so the create
|
|
77
|
+
// path runs; if the projectId is still reserved server-side
|
|
78
|
+
// the create will fail with Conflict and surface a real
|
|
79
|
+
// error.
|
|
80
|
+
Effect.map((p) => p && p.state && p.state !== "ACTIVE" ? undefined : p));
|
|
81
|
+
const requireProject = (projectId, context) => observeProject(projectId).pipe(Effect.flatMap((p) => p
|
|
82
|
+
? Effect.succeed(p)
|
|
83
|
+
: Effect.fail(new ConfigError({
|
|
84
|
+
message: `Project ${projectId} ${context}.`,
|
|
85
|
+
}))));
|
|
86
|
+
// Read current billing association. Returns `undefined` when the
|
|
87
|
+
// project is unknown to billing (NotFound) or invisible to the
|
|
88
|
+
// caller (Forbidden) — same 403→missing collapse as the project
|
|
89
|
+
// observe path.
|
|
90
|
+
const observeBilling = (projectId) => getBillingInfo({ name: `projects/${projectId}` }).pipe(Effect.catchTag("NotFound", () => Effect.succeed(undefined)), Effect.catchTag("Forbidden", () => Effect.succeed(undefined)));
|
|
91
|
+
// Attach / detach a billing account on the project. Pass empty
|
|
92
|
+
// string to detach (GCP's documented contract — see the long
|
|
93
|
+
// disclaimer on `updateBillingInfoProjects` warning that this
|
|
94
|
+
// disables paid services on the project). Synchronous PUT, no
|
|
95
|
+
// LRO involved.
|
|
96
|
+
const syncBilling = Effect.fn(function* (projectId, observed, desired) {
|
|
97
|
+
const observedAccount = observed?.billingAccountName ?? "";
|
|
98
|
+
const desiredAccount = desired ?? "";
|
|
99
|
+
if (observedAccount === desiredAccount) {
|
|
100
|
+
return observed;
|
|
101
|
+
}
|
|
102
|
+
return yield* updateBillingInfo({
|
|
103
|
+
name: `projects/${projectId}`,
|
|
104
|
+
body: { billingAccountName: desiredAccount },
|
|
105
|
+
}).pipe(
|
|
106
|
+
// Surface the most common BadRequest mode — the billing
|
|
107
|
+
// account's per-account project-attach quota — with a
|
|
108
|
+
// remediation pointer. Soft-deleted projects continue to
|
|
109
|
+
// hold quota for 30 days, so the typical fix is a quota
|
|
110
|
+
// increase rather than waiting it out. Other 400s
|
|
111
|
+
// (malformed account name, closed account, permission
|
|
112
|
+
// mismatch) propagate untouched so the underlying API
|
|
113
|
+
// message is preserved.
|
|
114
|
+
// Surface the most common BadRequest mode with a clear
|
|
115
|
+
// remediation pointer, and re-shape every BadRequest into
|
|
116
|
+
// ConfigError so callers see one error class regardless of
|
|
117
|
+
// the underlying GCP-side detail. The two patterns:
|
|
118
|
+
//
|
|
119
|
+
// 1. Billing-account project-attach quota exhausted —
|
|
120
|
+
// every soft-deleted project still holds quota for
|
|
121
|
+
// 30 days. Real fix is a quota increase request.
|
|
122
|
+
// 2. Other 400s (malformed account name, closed
|
|
123
|
+
// account, IAM mismatch on `billing.resourceAssociations.create`)
|
|
124
|
+
// — surface the underlying GCP message.
|
|
125
|
+
Effect.catchTag("BadRequest", (e) => {
|
|
126
|
+
// GCP returns the high-level message in `e.message` and
|
|
127
|
+
// stuffs the structured detail (e.g. `QuotaFailure`) into
|
|
128
|
+
// the response body's `details[]` array — which distilled
|
|
129
|
+
// doesn't surface (only `message` is parsed in
|
|
130
|
+
// `vendor/distilled/packages/gcp/src/client/api.ts:32-35`).
|
|
131
|
+
//
|
|
132
|
+
// The single most common 4xx on `updateBillingInfo` is
|
|
133
|
+
// FAILED_PRECONDITION ("Precondition check failed.") for
|
|
134
|
+
// the billing account's per-account project-attach quota.
|
|
135
|
+
// Each successful attach — including soft-deleted projects
|
|
136
|
+
// within their 30-day retention window — counts toward
|
|
137
|
+
// this quota. There is no way to detect this case with
|
|
138
|
+
// certainty from the surfaced error, so we always include
|
|
139
|
+
// the quota-remediation hint alongside the underlying
|
|
140
|
+
// message; users who hit a different 400 will still see
|
|
141
|
+
// GCP's real reason in the prefix.
|
|
142
|
+
const underlying = e.message ?? "unknown 400 from cloudbilling.updateBillingInfo";
|
|
143
|
+
const isLikelyQuota = /precondition|FAILED_PRECONDITION/i.test(underlying);
|
|
144
|
+
const hint = isLikelyQuota
|
|
145
|
+
? " This is most often the billing account's project-attach quota — request an increase at https://support.google.com/code/contact/billing_quota_increase, or use a different billing account."
|
|
146
|
+
: "";
|
|
147
|
+
return Effect.fail(new ConfigError({
|
|
148
|
+
message: `Cannot attach billing account ${desiredAccount} to project ${projectId}: ${underlying}.${hint}`,
|
|
149
|
+
}));
|
|
150
|
+
}));
|
|
151
|
+
});
|
|
152
|
+
const syncMutable = Effect.fn(function* (observed, desired, session) {
|
|
153
|
+
const observedLabels = { ...(observed.labels ?? {}) };
|
|
154
|
+
const updateMaskFields = [];
|
|
155
|
+
if (desired.displayName !== observed.displayName) {
|
|
156
|
+
updateMaskFields.push("display_name");
|
|
157
|
+
}
|
|
158
|
+
const labelDiff = diffTags(observedLabels, desired.labels);
|
|
159
|
+
if (labelDiff.removed.length > 0 || labelDiff.upsert.length > 0) {
|
|
160
|
+
updateMaskFields.push("labels");
|
|
161
|
+
}
|
|
162
|
+
if (updateMaskFields.length === 0)
|
|
163
|
+
return observed;
|
|
164
|
+
const op = yield* patchProjects({
|
|
165
|
+
name: observed.name,
|
|
166
|
+
updateMask: updateMaskFields.join(","),
|
|
167
|
+
body: {
|
|
168
|
+
displayName: desired.displayName,
|
|
169
|
+
labels: desired.labels,
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
if (op.name)
|
|
173
|
+
yield* awaitOperation(op.name, session);
|
|
174
|
+
return yield* requireProject(observed.projectId, "disappeared after patch");
|
|
175
|
+
});
|
|
176
|
+
return {
|
|
177
|
+
stables: ["projectId", "projectNumber", "name"],
|
|
178
|
+
diff: Effect.fn(function* ({ id, news, olds = {}, output }) {
|
|
179
|
+
if (!isResolved(news))
|
|
180
|
+
return undefined;
|
|
181
|
+
const desiredId = yield* createProjectId(id, news.projectId);
|
|
182
|
+
const currentId = output?.projectId ??
|
|
183
|
+
(yield* createProjectId(id, olds.projectId));
|
|
184
|
+
const desiredParent = parentToString(news.parent);
|
|
185
|
+
const observedParent = output?.parent ??
|
|
186
|
+
(olds.parent ? parentToString(olds.parent) : desiredParent);
|
|
187
|
+
if (desiredId !== currentId || observedParent !== desiredParent) {
|
|
188
|
+
return { action: "replace" };
|
|
189
|
+
}
|
|
190
|
+
}),
|
|
191
|
+
reconcile: Effect.fn(function* ({ id, news, session }) {
|
|
192
|
+
const projectId = yield* createProjectId(id, news.projectId);
|
|
193
|
+
const parent = parentToString(news.parent);
|
|
194
|
+
const internalLabels = yield* gcpInternalLabels(id);
|
|
195
|
+
const desiredLabels = {
|
|
196
|
+
...(news.labels ?? {}),
|
|
197
|
+
...internalLabels, // alchemy keys reserved — overwrite user values
|
|
198
|
+
};
|
|
199
|
+
// 1. Observe — cloud state is authoritative; `output`/`olds`
|
|
200
|
+
// are caches and may be stale or missing.
|
|
201
|
+
let observed = yield* observeProject(projectId);
|
|
202
|
+
// 2. Ensure — create if missing. `createProjects` returns an
|
|
203
|
+
// LRO; poll until done. `Conflict` covers two cases: a
|
|
204
|
+
// peer reconciler raced us, or a prior reconcile created
|
|
205
|
+
// the project but state-persistence failed. In both, the
|
|
206
|
+
// project exists — re-observe and converge.
|
|
207
|
+
if (!observed) {
|
|
208
|
+
const operation = yield* createProjects({
|
|
209
|
+
body: {
|
|
210
|
+
projectId,
|
|
211
|
+
parent,
|
|
212
|
+
displayName: news.displayName,
|
|
213
|
+
labels: desiredLabels,
|
|
214
|
+
},
|
|
215
|
+
}).pipe(Effect.catchTag("Conflict", () => Effect.succeed(undefined)));
|
|
216
|
+
if (operation?.name)
|
|
217
|
+
yield* awaitOperation(operation.name, session);
|
|
218
|
+
observed = yield* requireProject(projectId, "did not appear after create");
|
|
219
|
+
}
|
|
220
|
+
// 3. Sync — displayName + labels are mutable. Diff against
|
|
221
|
+
// OBSERVED state (not `olds`) so adoption converges
|
|
222
|
+
// correctly: if a foreign label set is on the project,
|
|
223
|
+
// the patch will replace it with our desired set
|
|
224
|
+
// (including alchemy internals).
|
|
225
|
+
const synced = yield* syncMutable(observed, {
|
|
226
|
+
displayName: news.displayName ?? observed.displayName,
|
|
227
|
+
labels: desiredLabels,
|
|
228
|
+
}, session);
|
|
229
|
+
// 4. Sync billing association. Done after the project patch
|
|
230
|
+
// so the project resource is fully present before we
|
|
231
|
+
// attach billing (CRM project create is the LRO; billing
|
|
232
|
+
// update is synchronous).
|
|
233
|
+
const observedBilling = yield* observeBilling(synced.projectId);
|
|
234
|
+
const finalBilling = yield* syncBilling(synced.projectId, observedBilling, news.billingAccount);
|
|
235
|
+
return toAttributes(synced, finalBilling);
|
|
236
|
+
}),
|
|
237
|
+
delete: Effect.fn(function* ({ output, session }) {
|
|
238
|
+
yield* deleteProjects({ name: `projects/${output.projectId}` }).pipe(Effect.flatMap((op) => op.name ? awaitOperation(op.name, session) : Effect.succeed(op)),
|
|
239
|
+
// Already gone.
|
|
240
|
+
Effect.catchTag("NotFound", () => Effect.void),
|
|
241
|
+
// GCP returns 400 with "Project ... is already in
|
|
242
|
+
// DELETE_REQUESTED" when delete is invoked on an already-
|
|
243
|
+
// soft-deleted project. Treat that as idempotent success.
|
|
244
|
+
// TODO(distilled): tag this state via patch — see finding 12.
|
|
245
|
+
// The GCP `matchError` (vendor/distilled/packages/gcp/src/client/api.ts)
|
|
246
|
+
// currently dispatches purely on HTTP status and ignores the
|
|
247
|
+
// `message.includes` matcher in the patch JSON, so a per-operation
|
|
248
|
+
// patch alone can't disambiguate this case from a real 400 without
|
|
249
|
+
// also extending `matchError` to consult the matchers.
|
|
250
|
+
Effect.catchTag("BadRequest", (e) => /already.*delet|DELETE_REQUESTED/i.test(e.message ?? "")
|
|
251
|
+
? Effect.void
|
|
252
|
+
: Effect.fail(e)));
|
|
253
|
+
}),
|
|
254
|
+
read: Effect.fn(function* ({ id, output, olds }) {
|
|
255
|
+
const projectId = output?.projectId ??
|
|
256
|
+
(yield* createProjectId(id, olds?.projectId));
|
|
257
|
+
const observed = yield* observeProject(projectId);
|
|
258
|
+
if (!observed)
|
|
259
|
+
return undefined;
|
|
260
|
+
const observedBilling = yield* observeBilling(projectId);
|
|
261
|
+
const attrs = toAttributes(observed, observedBilling);
|
|
262
|
+
// Adoption gate: a project without our internal labels was
|
|
263
|
+
// created outside this stack/stage/id. The engine surfaces
|
|
264
|
+
// `Unowned(attrs)` to the user as "exists but is not ours" —
|
|
265
|
+
// adoption requires `--adopt` (or `adopt(true)`).
|
|
266
|
+
return (yield* hasAlchemyLabels(id, observed.labels))
|
|
267
|
+
? attrs
|
|
268
|
+
: Unowned(attrs);
|
|
269
|
+
}),
|
|
270
|
+
};
|
|
271
|
+
}));
|
|
272
|
+
//# sourceMappingURL=Project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Project.js","sourceRoot":"","sources":["../../src/CloudResourceManager/Project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/CloudResourceManager/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACxD,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/CloudResourceManager/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Resource } from "alchemy";
|
|
2
|
+
import * as Provider from "alchemy/Provider";
|
|
3
|
+
import type * as GCP from "../Providers.ts";
|
|
4
|
+
/**
|
|
5
|
+
* A global compute Address. The intended use here is **Private Services
|
|
6
|
+
* Access (PSA)** — reserving an internal IP range that
|
|
7
|
+
* `servicenetworking.services.connections.create` consumes to peer
|
|
8
|
+
* Google's service-producer VPC into the host VPC. That requires the
|
|
9
|
+
* specific shape `addressType=INTERNAL`, `purpose=VPC_PEERING`,
|
|
10
|
+
* `network=<vpc selfLink>`, plus an explicit `prefixLength`.
|
|
11
|
+
*
|
|
12
|
+
* Other purposes (`PRIVATE_SERVICE_CONNECT`, `GCE_ENDPOINT`, regional
|
|
13
|
+
* external addresses) are not modelled in this resource — add them in
|
|
14
|
+
* separate resources if/when needed.
|
|
15
|
+
*
|
|
16
|
+
* Adoption uses the labels field (Address carries `labels` +
|
|
17
|
+
* `labelFingerprint`).
|
|
18
|
+
*
|
|
19
|
+
* @section Reserving a PSA range
|
|
20
|
+
* @example /20 reserved for `servicenetworking.googleapis.com`
|
|
21
|
+
* ```typescript
|
|
22
|
+
* const psaRange = yield* GCP.GlobalAddress("PsaRange", {
|
|
23
|
+
* project: hostProject.projectId,
|
|
24
|
+
* network: vpc.selfLink,
|
|
25
|
+
* purpose: "VPC_PEERING",
|
|
26
|
+
* addressType: "INTERNAL",
|
|
27
|
+
* prefixLength: 20,
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export type GlobalAddressProps = {
|
|
32
|
+
/** GCP project ID hosting the address. Immutable — replace if changed. */
|
|
33
|
+
project: string;
|
|
34
|
+
/**
|
|
35
|
+
* Address name. Defaults to `createPhysicalName({ id, lowercase: true,
|
|
36
|
+
* maxLength: 63 })`. Immutable — replace if changed.
|
|
37
|
+
*/
|
|
38
|
+
name?: string;
|
|
39
|
+
/** Description (free-form). */
|
|
40
|
+
description?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Internal vs external. Defaults to `INTERNAL` (the only value that
|
|
43
|
+
* makes sense for a PSA reservation). Immutable — replace.
|
|
44
|
+
*/
|
|
45
|
+
addressType?: "INTERNAL" | "EXTERNAL";
|
|
46
|
+
/**
|
|
47
|
+
* Address purpose. For PSA use `VPC_PEERING`. Immutable — replace.
|
|
48
|
+
*/
|
|
49
|
+
purpose?: "VPC_PEERING" | "GCE_ENDPOINT" | "PRIVATE_SERVICE_CONNECT" | "DNS_RESOLVER";
|
|
50
|
+
/**
|
|
51
|
+
* URL of the VPC the address belongs to (PSA requires this).
|
|
52
|
+
* Immutable — replace.
|
|
53
|
+
*/
|
|
54
|
+
network?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Prefix length for a range allocation (PSA always allocates a
|
|
57
|
+
* range, not a single address). Required for `purpose=VPC_PEERING`.
|
|
58
|
+
* Immutable — replace.
|
|
59
|
+
*/
|
|
60
|
+
prefixLength?: number;
|
|
61
|
+
/**
|
|
62
|
+
* Explicit address (or first address of the range) to reserve. If
|
|
63
|
+
* omitted, GCP picks one inside the VPC's available space.
|
|
64
|
+
* Immutable — replace.
|
|
65
|
+
*/
|
|
66
|
+
address?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Resource labels. Alchemy internal labels (`alchemy_app`,
|
|
69
|
+
* `alchemy_stage`, `alchemy_id`) are merged on top automatically and
|
|
70
|
+
* are reserved. Mutable via `setLabels`.
|
|
71
|
+
*/
|
|
72
|
+
labels?: Record<string, string>;
|
|
73
|
+
};
|
|
74
|
+
export type GlobalAddressAttributes = {
|
|
75
|
+
/** Address name. */
|
|
76
|
+
name: string;
|
|
77
|
+
/** GCP project ID, threaded through from props for delete/read. */
|
|
78
|
+
project: string;
|
|
79
|
+
/** Server-defined URL. */
|
|
80
|
+
selfLink: string;
|
|
81
|
+
/** Server-assigned numeric id. */
|
|
82
|
+
id: string;
|
|
83
|
+
/** The reserved IP (or first IP of the range). */
|
|
84
|
+
address: string;
|
|
85
|
+
/** Prefix length, when reserving a range. */
|
|
86
|
+
prefixLength: number | undefined;
|
|
87
|
+
/** Address type. */
|
|
88
|
+
addressType: string | undefined;
|
|
89
|
+
/** Purpose. */
|
|
90
|
+
purpose: string | undefined;
|
|
91
|
+
/** VPC URL. */
|
|
92
|
+
network: string | undefined;
|
|
93
|
+
/** Status: `RESERVING`, `RESERVED`, `IN_USE`. */
|
|
94
|
+
status: string | undefined;
|
|
95
|
+
/** Labels currently set, including the alchemy internals. */
|
|
96
|
+
labels: Record<string, string>;
|
|
97
|
+
};
|
|
98
|
+
export type GlobalAddress = Resource<"GCP.GlobalAddress", GlobalAddressProps, GlobalAddressAttributes, never, GCP.Providers>;
|
|
99
|
+
export declare const GlobalAddress: import("alchemy").ResourceClass<GlobalAddress>;
|
|
100
|
+
export declare const GlobalAddressProvider: () => import("effect/Layer").Layer<Provider.Provider<GlobalAddress>, never, import("effect/unstable/http/HttpClient").HttpClient | import("alchemy").Stage | import("alchemy").Stack | import("@distilled.cloud/gcp").Credentials>;
|
|
101
|
+
//# sourceMappingURL=GlobalAddress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GlobalAddress.d.ts","sourceRoot":"","sources":["../../src/Compute/GlobalAddress.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAKnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,KAAK,KAAK,GAAG,MAAM,iBAAiB,CAAC;AAG5C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+BAA+B;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;IACtC;;OAEG;IACH,OAAO,CAAC,EACJ,aAAa,GACb,cAAc,GACd,yBAAyB,GACzB,cAAc,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,oBAAoB;IACpB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,eAAe;IACf,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,eAAe;IACf,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,iDAAiD;IACjD,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,QAAQ,CAClC,mBAAmB,EACnB,kBAAkB,EAClB,uBAAuB,EACvB,KAAK,EACL,GAAG,CAAC,SAAS,CACd,CAAC;AACF,eAAO,MAAM,aAAa,gDAA+C,CAAC;AAmB1E,eAAO,MAAM,qBAAqB,oOAgJ/B,CAAC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import * as compute from "@distilled.cloud/gcp/compute-v1";
|
|
2
|
+
import { Resource } from "alchemy";
|
|
3
|
+
import { Unowned } from "alchemy/AdoptPolicy";
|
|
4
|
+
import { deepEqual, isResolved, somePropsAreDifferent } from "alchemy/Diff";
|
|
5
|
+
import { createPhysicalName } from "alchemy/PhysicalName";
|
|
6
|
+
import * as Provider from "alchemy/Provider";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import { gcpInternalLabels, hasAlchemyLabels } from "../Tags.js";
|
|
9
|
+
import { makeAwaitGlobalOperation } from "./Operations.js";
|
|
10
|
+
export const GlobalAddress = Resource("GCP.GlobalAddress");
|
|
11
|
+
const toGlobalAddressAttributes = (a, parent) => ({
|
|
12
|
+
name: a.name ?? "",
|
|
13
|
+
project: parent.project,
|
|
14
|
+
selfLink: a.selfLink ?? "",
|
|
15
|
+
id: a.id ?? "",
|
|
16
|
+
address: a.address ?? "",
|
|
17
|
+
prefixLength: a.prefixLength,
|
|
18
|
+
addressType: a.addressType,
|
|
19
|
+
purpose: a.purpose,
|
|
20
|
+
network: a.network,
|
|
21
|
+
status: a.status,
|
|
22
|
+
labels: { ...(a.labels ?? {}) },
|
|
23
|
+
});
|
|
24
|
+
export const GlobalAddressProvider = () => Provider.effect(GlobalAddress, Effect.gen(function* () {
|
|
25
|
+
const getGlobalAddresses = yield* compute.getGlobalAddresses;
|
|
26
|
+
const insertGlobalAddresses = yield* compute.insertGlobalAddresses;
|
|
27
|
+
const deleteGlobalAddresses = yield* compute.deleteGlobalAddresses;
|
|
28
|
+
const setLabelsGlobalAddresses = yield* compute.setLabelsGlobalAddresses;
|
|
29
|
+
const getGlobalOperations = yield* compute.getGlobalOperations;
|
|
30
|
+
const awaitOp = makeAwaitGlobalOperation(getGlobalOperations);
|
|
31
|
+
const observe = (project, name) => getGlobalAddresses({ project, address: name }).pipe(Effect.catchTag("NotFound", () => Effect.succeed(undefined)), Effect.catchTag("Forbidden", () => Effect.succeed(undefined)));
|
|
32
|
+
const syncLabels = Effect.fn(function* (args) {
|
|
33
|
+
if (deepEqual(args.observed.labels ?? {}, args.desired))
|
|
34
|
+
return;
|
|
35
|
+
const op = yield* setLabelsGlobalAddresses({
|
|
36
|
+
project: args.project,
|
|
37
|
+
resource: args.observed.name ?? "",
|
|
38
|
+
body: {
|
|
39
|
+
labels: args.desired,
|
|
40
|
+
labelFingerprint: args.observed.labelFingerprint,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
if (op.name)
|
|
44
|
+
yield* awaitOp(args.project, op.name, args.session);
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
stables: ["name", "project", "selfLink", "id", "address"],
|
|
48
|
+
diff: Effect.fn(function* ({ news, olds = {} }) {
|
|
49
|
+
if (!isResolved(news))
|
|
50
|
+
return undefined;
|
|
51
|
+
if (somePropsAreDifferent(olds, news, [
|
|
52
|
+
"project",
|
|
53
|
+
"name",
|
|
54
|
+
"addressType",
|
|
55
|
+
"purpose",
|
|
56
|
+
"network",
|
|
57
|
+
"prefixLength",
|
|
58
|
+
"address",
|
|
59
|
+
])) {
|
|
60
|
+
return { action: "replace" };
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
}),
|
|
64
|
+
reconcile: Effect.fn(function* ({ id, news, session }) {
|
|
65
|
+
const internalLabels = yield* gcpInternalLabels(id);
|
|
66
|
+
const desiredName = news.name ??
|
|
67
|
+
(yield* createPhysicalName({ id, maxLength: 63 })).toLowerCase();
|
|
68
|
+
const desiredLabels = {
|
|
69
|
+
...(news.labels ?? {}),
|
|
70
|
+
...internalLabels,
|
|
71
|
+
};
|
|
72
|
+
let observed = yield* observe(news.project, desiredName);
|
|
73
|
+
if (!observed) {
|
|
74
|
+
const body = {
|
|
75
|
+
name: desiredName,
|
|
76
|
+
...(news.description ? { description: news.description } : {}),
|
|
77
|
+
addressType: news.addressType ?? "INTERNAL",
|
|
78
|
+
...(news.purpose ? { purpose: news.purpose } : {}),
|
|
79
|
+
...(news.network ? { network: news.network } : {}),
|
|
80
|
+
...(news.prefixLength !== undefined
|
|
81
|
+
? { prefixLength: news.prefixLength }
|
|
82
|
+
: {}),
|
|
83
|
+
...(news.address ? { address: news.address } : {}),
|
|
84
|
+
labels: desiredLabels,
|
|
85
|
+
};
|
|
86
|
+
const op = yield* insertGlobalAddresses({
|
|
87
|
+
project: news.project,
|
|
88
|
+
body,
|
|
89
|
+
}).pipe(Effect.catchTag("Conflict", () => Effect.succeed(undefined)));
|
|
90
|
+
if (op?.name)
|
|
91
|
+
yield* awaitOp(news.project, op.name, session);
|
|
92
|
+
observed = yield* getGlobalAddresses({
|
|
93
|
+
project: news.project,
|
|
94
|
+
address: desiredName,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
yield* syncLabels({
|
|
98
|
+
project: news.project,
|
|
99
|
+
observed,
|
|
100
|
+
desired: desiredLabels,
|
|
101
|
+
session,
|
|
102
|
+
});
|
|
103
|
+
const final = yield* getGlobalAddresses({
|
|
104
|
+
project: news.project,
|
|
105
|
+
address: desiredName,
|
|
106
|
+
});
|
|
107
|
+
return toGlobalAddressAttributes(final, { project: news.project });
|
|
108
|
+
}),
|
|
109
|
+
delete: Effect.fn(function* ({ output, session }) {
|
|
110
|
+
yield* deleteGlobalAddresses({
|
|
111
|
+
project: output.project,
|
|
112
|
+
address: output.name,
|
|
113
|
+
}).pipe(Effect.flatMap((op) => op.name
|
|
114
|
+
? awaitOp(output.project, op.name, session)
|
|
115
|
+
: Effect.succeed(op)), Effect.catchTag("NotFound", () => Effect.void));
|
|
116
|
+
}),
|
|
117
|
+
read: Effect.fn(function* ({ id, output, olds }) {
|
|
118
|
+
const project = output?.project ?? olds?.project;
|
|
119
|
+
if (!project)
|
|
120
|
+
return undefined;
|
|
121
|
+
const name = output?.name ??
|
|
122
|
+
olds?.name ??
|
|
123
|
+
(yield* createPhysicalName({ id, maxLength: 63 })).toLowerCase();
|
|
124
|
+
const observed = yield* observe(project, name);
|
|
125
|
+
if (!observed)
|
|
126
|
+
return undefined;
|
|
127
|
+
const attrs = toGlobalAddressAttributes(observed, { project });
|
|
128
|
+
return (yield* hasAlchemyLabels(id, observed.labels))
|
|
129
|
+
? attrs
|
|
130
|
+
: Unowned(attrs);
|
|
131
|
+
}),
|
|
132
|
+
};
|
|
133
|
+
}));
|
|
134
|
+
//# sourceMappingURL=GlobalAddress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GlobalAddress.js","sourceRoot":"","sources":["../../src/Compute/GlobalAddress.ts"],"names":[],"mappings":"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"}
|