@microagi/alchemy-gcp 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/README.md +54 -2
- package/lib/Container/Cluster.d.ts +25 -0
- package/lib/Container/Cluster.d.ts.map +1 -1
- package/lib/Container/Cluster.js.map +1 -1
- package/lib/Providers.d.ts.map +1 -1
- package/lib/Providers.js +5 -1
- package/lib/Providers.js.map +1 -1
- package/lib/Run/IamMember.d.ts +70 -0
- package/lib/Run/IamMember.d.ts.map +1 -0
- package/lib/Run/IamMember.js +65 -0
- package/lib/Run/IamMember.js.map +1 -0
- package/lib/Run/IamSync.d.ts +80 -0
- package/lib/Run/IamSync.d.ts.map +1 -0
- package/lib/Run/IamSync.js +73 -0
- package/lib/Run/IamSync.js.map +1 -0
- package/lib/Run/Job.d.ts +167 -0
- package/lib/Run/Job.d.ts.map +1 -0
- package/lib/Run/Job.js +199 -0
- package/lib/Run/Job.js.map +1 -0
- package/lib/Run/Operations.d.ts +47 -0
- package/lib/Run/Operations.d.ts.map +1 -0
- package/lib/Run/Operations.js +46 -0
- package/lib/Run/Operations.js.map +1 -0
- package/lib/Run/Service.d.ts +193 -0
- package/lib/Run/Service.d.ts.map +1 -0
- package/lib/Run/Service.js +247 -0
- package/lib/Run/Service.js.map +1 -0
- package/lib/Run/Validation.d.ts +54 -0
- package/lib/Run/Validation.d.ts.map +1 -0
- package/lib/Run/Validation.js +129 -0
- package/lib/Run/Validation.js.map +1 -0
- package/lib/Run/index.d.ts +51 -0
- package/lib/Run/index.d.ts.map +1 -0
- package/lib/Run/index.js +4 -0
- package/lib/Run/index.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/package.json +5 -4
- package/src/Container/Cluster.ts +25 -0
- package/src/Providers.ts +6 -0
- package/src/Run/IamMember.ts +79 -0
- package/src/Run/IamSync.ts +134 -0
- package/src/Run/Job.ts +453 -0
- package/src/Run/Operations.ts +77 -0
- package/src/Run/Service.ts +541 -0
- package/src/Run/Validation.ts +153 -0
- package/src/Run/index.ts +52 -0
- package/src/index.ts +1 -0
package/lib/Run/Job.d.ts
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import * as run from "@distilled.cloud/gcp/run-v2";
|
|
2
|
+
import { Resource } from "alchemy";
|
|
3
|
+
import * as Provider from "alchemy/Provider";
|
|
4
|
+
import type * as GCP from "../Providers.ts";
|
|
5
|
+
import { type RunIamBindingContract } from "./IamSync.ts";
|
|
6
|
+
/**
|
|
7
|
+
* A Cloud Run v2 Job — a managed batch workload. A Job holds an
|
|
8
|
+
* `ExecutionTemplate` (parallelism + a `TaskTemplate` containing
|
|
9
|
+
* containers); invoking the Job via `runProjectsLocationsJobs` creates
|
|
10
|
+
* an immutable Execution that runs the configured number of tasks to
|
|
11
|
+
* completion.
|
|
12
|
+
*
|
|
13
|
+
* **Declarative vs imperative.** This resource models the Job
|
|
14
|
+
* *definition* — its template, parallelism, task count, IAM. The act
|
|
15
|
+
* of *running* the Job is event-shaped (does not fit the
|
|
16
|
+
* converge-to-desired-state model) and is left to user-side code:
|
|
17
|
+
*
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import * as run from "@distilled.cloud/gcp/run-v2";
|
|
20
|
+
* const job = yield* GCP.Job("Nightly", { ... });
|
|
21
|
+
* const runJob = yield* run.runProjectsLocationsJobs;
|
|
22
|
+
* yield* runJob({
|
|
23
|
+
* name: `projects/${job.project}/locations/${job.location}/jobs/${job.name}`,
|
|
24
|
+
* });
|
|
25
|
+
* // returns an LRO; poll if you want to wait for completion
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* **Lifecycle.** observe → ensure (create, retrying the API-enable
|
|
29
|
+
* race) → sync (patch full body if anything changed; Job's patch has
|
|
30
|
+
* no `updateMask` — server diffs the body itself) → sync IAM bindings
|
|
31
|
+
* → return.
|
|
32
|
+
*
|
|
33
|
+
* **Replace triggers.** Only identity fields (project, location, name)
|
|
34
|
+
* force replacement. Everything else is in-place via `patch`. New
|
|
35
|
+
* Executions are created independently by `runProjectsLocationsJobs`.
|
|
36
|
+
*
|
|
37
|
+
* **Optimistic concurrency.** Delete passes through the observed
|
|
38
|
+
* `etag`; patch passes etag in the body so concurrent edits surface
|
|
39
|
+
* as `Conflict` instead of silently overwriting.
|
|
40
|
+
*
|
|
41
|
+
* **Adoption.** Label-gated, same as {@link import("./Service.ts").Service}.
|
|
42
|
+
*
|
|
43
|
+
* **IAM.** Use {@link import("./IamMember.ts").jobIamMember} to bind
|
|
44
|
+
* `(role, member)` grants — typically `roles/run.invoker` on the
|
|
45
|
+
* service account that triggers the job.
|
|
46
|
+
*
|
|
47
|
+
* @section Creating a Cloud Run Job
|
|
48
|
+
* @example Single-shot batch job
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const job = yield* GCP.Job("ProcessBatch", {
|
|
51
|
+
* project: project.projectId,
|
|
52
|
+
* location: "europe-west4",
|
|
53
|
+
* template: {
|
|
54
|
+
* taskCount: 1,
|
|
55
|
+
* template: {
|
|
56
|
+
* maxRetries: 3,
|
|
57
|
+
* containers: [{
|
|
58
|
+
* image: "europe-west4-docker.pkg.dev/proj/repo/worker:latest",
|
|
59
|
+
* }],
|
|
60
|
+
* },
|
|
61
|
+
* },
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @example Parallel job with custom service account and GPU
|
|
66
|
+
* ```typescript
|
|
67
|
+
* const train = yield* GCP.Job("Train", {
|
|
68
|
+
* project: project.projectId,
|
|
69
|
+
* location: "europe-west4",
|
|
70
|
+
* launchStage: "BETA",
|
|
71
|
+
* template: {
|
|
72
|
+
* taskCount: 8,
|
|
73
|
+
* parallelism: 8,
|
|
74
|
+
* template: {
|
|
75
|
+
* serviceAccount: sa.email,
|
|
76
|
+
* maxRetries: 0,
|
|
77
|
+
* timeout: "21600s",
|
|
78
|
+
* containers: [{
|
|
79
|
+
* image: "europe-west4-docker.pkg.dev/proj/repo/train:v2",
|
|
80
|
+
* resources: { limits: { cpu: "4", memory: "16Gi", "nvidia.com/gpu": "1" } },
|
|
81
|
+
* }],
|
|
82
|
+
* nodeSelector: { accelerator: "nvidia-l4" },
|
|
83
|
+
* },
|
|
84
|
+
* },
|
|
85
|
+
* });
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export type JobProps = {
|
|
89
|
+
/** GCP project ID hosting the Job. Immutable — replace if changed. */
|
|
90
|
+
project: string;
|
|
91
|
+
/** Cloud Run region. Immutable — replace if changed. */
|
|
92
|
+
location: string;
|
|
93
|
+
/**
|
|
94
|
+
* Job name. Defaults to `createPhysicalName({ id, lowercase: true,
|
|
95
|
+
* maxLength: 49 })`. Lowercase letters/digits/hyphens; must begin
|
|
96
|
+
* with a letter and not end with a hyphen; **fewer than 50 characters**.
|
|
97
|
+
* Immutable — replace if changed.
|
|
98
|
+
*/
|
|
99
|
+
name?: string;
|
|
100
|
+
/** User-visible description. Mutable via `patch`. */
|
|
101
|
+
description?: string;
|
|
102
|
+
/**
|
|
103
|
+
* Resource labels. Alchemy internal labels are merged on top
|
|
104
|
+
* automatically. Cloud Run rejects reserved namespaces (same as
|
|
105
|
+
* Service). Mutable via `patch`.
|
|
106
|
+
*/
|
|
107
|
+
labels?: Record<string, string>;
|
|
108
|
+
/** Free-form annotations. Mutable via `patch`. */
|
|
109
|
+
annotations?: Record<string, string>;
|
|
110
|
+
/**
|
|
111
|
+
* Launch stage — `BETA` (or higher) required for preview features
|
|
112
|
+
* (GPU node selectors, Direct VPC). Mutable via `patch`.
|
|
113
|
+
*/
|
|
114
|
+
launchStage?: "ALPHA" | "BETA" | "GA" | "EARLY_ACCESS" | "PRELAUNCH" | "DEPRECATED";
|
|
115
|
+
/** Binary Authorization policy. Mutable via `patch`. */
|
|
116
|
+
binaryAuthorization?: run.GoogleCloudRunV2BinaryAuthorization;
|
|
117
|
+
/**
|
|
118
|
+
* Token-suffix used to compose Execution names when the Job is
|
|
119
|
+
* started via the GCP UI or `gcloud run jobs execute`. Required to
|
|
120
|
+
* keep distinct from Job name + 63 chars. Mutable.
|
|
121
|
+
*/
|
|
122
|
+
startExecutionToken?: string;
|
|
123
|
+
/** Same as `startExecutionToken` but used on run completion. Mutable. */
|
|
124
|
+
runExecutionToken?: string;
|
|
125
|
+
/**
|
|
126
|
+
* The Execution template — describes parallelism, task count, and
|
|
127
|
+
* the inner `TaskTemplate` (containers, volumes, retry policy).
|
|
128
|
+
* **Required at create.** Mutable via `patch`.
|
|
129
|
+
*/
|
|
130
|
+
template: run.GoogleCloudRunV2ExecutionTemplate;
|
|
131
|
+
};
|
|
132
|
+
export type JobAttributes = {
|
|
133
|
+
/** Job name (bare). */
|
|
134
|
+
name: string;
|
|
135
|
+
/** Server-assigned UID. */
|
|
136
|
+
uid: string;
|
|
137
|
+
/** Fully-qualified resource name. */
|
|
138
|
+
resourceName: string;
|
|
139
|
+
/** GCP project ID. */
|
|
140
|
+
project: string;
|
|
141
|
+
/** Region. */
|
|
142
|
+
location: string;
|
|
143
|
+
/** Monotonically increasing generation, bumped on every patch. */
|
|
144
|
+
generation: string | undefined;
|
|
145
|
+
/** Generation reflected in the latest reconciled state. */
|
|
146
|
+
observedGeneration: string | undefined;
|
|
147
|
+
/** Overall readiness condition. */
|
|
148
|
+
terminalCondition: run.GoogleCloudRunV2Condition | undefined;
|
|
149
|
+
/** Number of Executions created for this Job. */
|
|
150
|
+
executionCount: number | undefined;
|
|
151
|
+
/** Reference to the most recently created Execution, if any. */
|
|
152
|
+
latestCreatedExecution: run.GoogleCloudRunV2ExecutionReference | undefined;
|
|
153
|
+
/** True while Cloud Run is reconciling toward the desired state. */
|
|
154
|
+
reconciling: boolean | undefined;
|
|
155
|
+
/** Optimistic-concurrency etag. */
|
|
156
|
+
etag: string | undefined;
|
|
157
|
+
/** Labels currently set, including internals. */
|
|
158
|
+
labels: Record<string, string>;
|
|
159
|
+
/** Creation time. */
|
|
160
|
+
createTime: string | undefined;
|
|
161
|
+
/** Last-modified time. */
|
|
162
|
+
updateTime: string | undefined;
|
|
163
|
+
};
|
|
164
|
+
export type Job = Resource<"GCP.Job", JobProps, JobAttributes, RunIamBindingContract, GCP.Providers>;
|
|
165
|
+
export declare const Job: import("alchemy").ResourceClass<Job>;
|
|
166
|
+
export declare const JobProvider: () => import("effect/Layer").Layer<Provider.Provider<Job>, never, import("effect/unstable/http/HttpClient").HttpClient | import("alchemy").Stage | import("alchemy").Stack | import("@distilled.cloud/gcp").Credentials>;
|
|
167
|
+
//# sourceMappingURL=Job.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Job.d.ts","sourceRoot":"","sources":["../../src/Run/Job.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,6BAA6B,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAKnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAK7C,OAAO,KAAK,KAAK,GAAG,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAe,KAAK,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAUvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiFG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC;;;OAGG;IACH,WAAW,CAAC,EACR,OAAO,GACP,MAAM,GACN,IAAI,GACJ,cAAc,GACd,WAAW,GACX,YAAY,CAAC;IACjB,wDAAwD;IACxD,mBAAmB,CAAC,EAAE,GAAG,CAAC,mCAAmC,CAAC;IAC9D;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,yEAAyE;IACzE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,EAAE,GAAG,CAAC,iCAAiC,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,qCAAqC;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,2DAA2D;IAC3D,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,mCAAmC;IACnC,iBAAiB,EAAE,GAAG,CAAC,yBAAyB,GAAG,SAAS,CAAC;IAC7D,iDAAiD;IACjD,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,gEAAgE;IAChE,sBAAsB,EAAE,GAAG,CAAC,kCAAkC,GAAG,SAAS,CAAC;IAC3E,oEAAoE;IACpE,WAAW,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,mCAAmC;IACnC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,qBAAqB;IACrB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,0BAA0B;IAC1B,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,GAAG,GAAG,QAAQ,CACxB,SAAS,EACT,QAAQ,EACR,aAAa,EACb,qBAAqB,EACrB,GAAG,CAAC,SAAS,CACd,CAAC;AACF,eAAO,MAAM,GAAG,sCAA2B,CAAC;AAgG5C,eAAO,MAAM,WAAW,0NAgKrB,CAAC"}
|
package/lib/Run/Job.js
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import * as run from "@distilled.cloud/gcp/run-v2";
|
|
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 { diffTags } from "alchemy/Tags";
|
|
8
|
+
import * as Duration from "effect/Duration";
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as Schedule from "effect/Schedule";
|
|
11
|
+
import { gcpInternalLabels, hasAlchemyLabels } from "../Tags.js";
|
|
12
|
+
import { makeSyncIam } from "./IamSync.js";
|
|
13
|
+
import { makeAwaitOperation } from "./Operations.js";
|
|
14
|
+
import { reshapeBadRequest, validateAnnotations, validateContainers, validateLabels, validateRunName, } from "./Validation.js";
|
|
15
|
+
export const Job = Resource("GCP.Job");
|
|
16
|
+
const fqName = (project, location, name) => `projects/${project}/locations/${location}/jobs/${name}`;
|
|
17
|
+
const toJobBody = (news, desiredLabels) => ({
|
|
18
|
+
labels: desiredLabels,
|
|
19
|
+
...(news.annotations ? { annotations: news.annotations } : {}),
|
|
20
|
+
...(news.launchStage ? { launchStage: news.launchStage } : {}),
|
|
21
|
+
...(news.binaryAuthorization
|
|
22
|
+
? { binaryAuthorization: news.binaryAuthorization }
|
|
23
|
+
: {}),
|
|
24
|
+
...(news.startExecutionToken
|
|
25
|
+
? { startExecutionToken: news.startExecutionToken }
|
|
26
|
+
: {}),
|
|
27
|
+
...(news.runExecutionToken
|
|
28
|
+
? { runExecutionToken: news.runExecutionToken }
|
|
29
|
+
: {}),
|
|
30
|
+
template: news.template,
|
|
31
|
+
});
|
|
32
|
+
const toAttributes = (j, parent) => ({
|
|
33
|
+
name: parent.name,
|
|
34
|
+
uid: j.uid ?? "",
|
|
35
|
+
resourceName: j.name ?? fqName(parent.project, parent.location, parent.name),
|
|
36
|
+
project: parent.project,
|
|
37
|
+
location: parent.location,
|
|
38
|
+
generation: j.generation,
|
|
39
|
+
observedGeneration: j.observedGeneration,
|
|
40
|
+
terminalCondition: j.terminalCondition,
|
|
41
|
+
executionCount: j.executionCount,
|
|
42
|
+
latestCreatedExecution: j.latestCreatedExecution,
|
|
43
|
+
reconciling: j.reconciling,
|
|
44
|
+
etag: j.etag,
|
|
45
|
+
labels: { ...(j.labels ?? {}) },
|
|
46
|
+
createTime: j.createTime,
|
|
47
|
+
updateTime: j.updateTime,
|
|
48
|
+
});
|
|
49
|
+
/**
|
|
50
|
+
* Decide whether anything mutable on the Job changed since the last
|
|
51
|
+
* reconcile. Job's `patch` has no `updateMask` parameter — the server
|
|
52
|
+
* diffs the full body — so we just emit a single "changed / unchanged"
|
|
53
|
+
* verdict and re-send the whole body if it differs.
|
|
54
|
+
*
|
|
55
|
+
* Labels go through `diffTags` (consistent with every other GCP
|
|
56
|
+
* resource here); everything else is a `deepEqual` on the relevant
|
|
57
|
+
* field. The `template` deep-equal is the load-bearing check —
|
|
58
|
+
* Cloud Run injects server-side defaults into `template.template`
|
|
59
|
+
* (e.g. `maxRetries: 3` when omitted), so the observed template may
|
|
60
|
+
* have keys we never sent. Deep-equal on the OBSERVED side ⊆ NEWS
|
|
61
|
+
* side is too strict; we rely on the user re-sending equivalent
|
|
62
|
+
* inputs across reconciles so observed==news after the first patch.
|
|
63
|
+
*/
|
|
64
|
+
const jobMutated = (observed, news, desiredLabels) => {
|
|
65
|
+
const labelDiff = diffTags({ ...(observed.labels ?? {}) }, desiredLabels);
|
|
66
|
+
if (labelDiff.removed.length > 0 || labelDiff.upsert.length > 0)
|
|
67
|
+
return true;
|
|
68
|
+
if (!deepEqual(observed.annotations ?? {}, news.annotations ?? {}))
|
|
69
|
+
return true;
|
|
70
|
+
if (news.launchStage !== undefined && observed.launchStage !== news.launchStage) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
if (news.binaryAuthorization &&
|
|
74
|
+
!deepEqual(observed.binaryAuthorization, news.binaryAuthorization)) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
if (news.startExecutionToken !== undefined &&
|
|
78
|
+
observed.startExecutionToken !== news.startExecutionToken) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
if (news.runExecutionToken !== undefined &&
|
|
82
|
+
observed.runExecutionToken !== news.runExecutionToken) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
if (!deepEqual(observed.template, news.template))
|
|
86
|
+
return true;
|
|
87
|
+
return false;
|
|
88
|
+
};
|
|
89
|
+
export const JobProvider = () => Provider.effect(Job, Effect.gen(function* () {
|
|
90
|
+
const getJob = yield* run.getProjectsLocationsJobs;
|
|
91
|
+
const createJob = yield* run.createProjectsLocationsJobs;
|
|
92
|
+
const patchJob = yield* run.patchProjectsLocationsJobs;
|
|
93
|
+
const deleteJob = yield* run.deleteProjectsLocationsJobs;
|
|
94
|
+
const getOperation = yield* run.getProjectsLocationsOperations;
|
|
95
|
+
const getIamPolicy = yield* run.getIamPolicyProjectsLocationsJobs;
|
|
96
|
+
const setIamPolicy = yield* run.setIamPolicyProjectsLocationsJobs;
|
|
97
|
+
const awaitOperation = makeAwaitOperation(getOperation);
|
|
98
|
+
const syncIam = makeSyncIam({ getIamPolicy, setIamPolicy });
|
|
99
|
+
const observe = (project, location, name) => getJob({ name: fqName(project, location, name) }).pipe(Effect.catchTag("NotFound", () => Effect.succeed(undefined)), Effect.catchTag("Forbidden", () => Effect.succeed(undefined)));
|
|
100
|
+
const syncMutable = Effect.fn(function* (args) {
|
|
101
|
+
if (!jobMutated(args.observed, args.news, args.desiredLabels))
|
|
102
|
+
return;
|
|
103
|
+
const bodyWithEtag = {
|
|
104
|
+
...toJobBody(args.news, args.desiredLabels),
|
|
105
|
+
...(args.observed.etag ? { etag: args.observed.etag } : {}),
|
|
106
|
+
};
|
|
107
|
+
const op = yield* patchJob({
|
|
108
|
+
name: args.name,
|
|
109
|
+
body: bodyWithEtag,
|
|
110
|
+
}).pipe(Effect.catchTag("BadRequest", reshapeBadRequest("Job", "patch")));
|
|
111
|
+
if (op.name)
|
|
112
|
+
yield* awaitOperation(op.name, args.session);
|
|
113
|
+
});
|
|
114
|
+
return {
|
|
115
|
+
stables: ["name", "uid", "resourceName", "project", "location"],
|
|
116
|
+
diff: Effect.fn(function* ({ news, olds = {} }) {
|
|
117
|
+
if (!isResolved(news))
|
|
118
|
+
return undefined;
|
|
119
|
+
if (somePropsAreDifferent(olds, news, [
|
|
120
|
+
"project",
|
|
121
|
+
"location",
|
|
122
|
+
"name",
|
|
123
|
+
])) {
|
|
124
|
+
return { action: "replace" };
|
|
125
|
+
}
|
|
126
|
+
return undefined;
|
|
127
|
+
}),
|
|
128
|
+
reconcile: Effect.fn(function* ({ id, news, session, bindings }) {
|
|
129
|
+
const internalLabels = yield* gcpInternalLabels(id);
|
|
130
|
+
const desiredName = news.name ??
|
|
131
|
+
(yield* createPhysicalName({ id, maxLength: 49 })).toLowerCase();
|
|
132
|
+
yield* validateRunName("Job", desiredName);
|
|
133
|
+
yield* validateLabels(news.labels);
|
|
134
|
+
yield* validateAnnotations(news.annotations);
|
|
135
|
+
// Job container constraint lives one level deeper (inside the
|
|
136
|
+
// ExecutionTemplate's TaskTemplate).
|
|
137
|
+
yield* validateContainers("Job", news.template.template?.containers);
|
|
138
|
+
const parent = `projects/${news.project}/locations/${news.location}`;
|
|
139
|
+
const name = fqName(news.project, news.location, desiredName);
|
|
140
|
+
const desiredLabels = {
|
|
141
|
+
...(news.labels ?? {}),
|
|
142
|
+
...internalLabels,
|
|
143
|
+
};
|
|
144
|
+
let observed = yield* observe(news.project, news.location, desiredName);
|
|
145
|
+
if (!observed) {
|
|
146
|
+
const op = yield* createJob({
|
|
147
|
+
parent,
|
|
148
|
+
jobId: desiredName,
|
|
149
|
+
body: toJobBody(news, desiredLabels),
|
|
150
|
+
}).pipe(Effect.retry({
|
|
151
|
+
while: (e) => e?._tag === "Forbidden" &&
|
|
152
|
+
/enabled this API recently|has not been used/i.test(e.message ?? ""),
|
|
153
|
+
schedule: Schedule.spaced(Duration.seconds(15)).pipe(Schedule.both(Schedule.recurs(20)), Schedule.tapOutput(() => session.note("Waiting for Cloud Run API enablement to propagate…"))),
|
|
154
|
+
}), Effect.catchTag("Conflict", () => Effect.succeed(undefined)), Effect.catchTag("BadRequest", reshapeBadRequest("Job", "create")));
|
|
155
|
+
if (op?.name)
|
|
156
|
+
yield* awaitOperation(op.name, session);
|
|
157
|
+
observed = yield* getJob({ name });
|
|
158
|
+
}
|
|
159
|
+
yield* syncMutable({
|
|
160
|
+
name,
|
|
161
|
+
observed,
|
|
162
|
+
news,
|
|
163
|
+
desiredLabels,
|
|
164
|
+
session,
|
|
165
|
+
});
|
|
166
|
+
yield* syncIam({ resource: name, bindings });
|
|
167
|
+
const final = yield* getJob({ name });
|
|
168
|
+
return toAttributes(final, {
|
|
169
|
+
project: news.project,
|
|
170
|
+
location: news.location,
|
|
171
|
+
name: desiredName,
|
|
172
|
+
});
|
|
173
|
+
}),
|
|
174
|
+
delete: Effect.fn(function* ({ output, session }) {
|
|
175
|
+
const name = fqName(output.project, output.location, output.name);
|
|
176
|
+
yield* deleteJob({
|
|
177
|
+
name,
|
|
178
|
+
...(output.etag ? { etag: output.etag } : {}),
|
|
179
|
+
}).pipe(Effect.flatMap((op) => op.name ? awaitOperation(op.name, session) : Effect.succeed(op)), Effect.catchTag("NotFound", () => Effect.void));
|
|
180
|
+
}),
|
|
181
|
+
read: Effect.fn(function* ({ id, output, olds }) {
|
|
182
|
+
const project = output?.project ?? olds?.project;
|
|
183
|
+
const location = output?.location ?? olds?.location;
|
|
184
|
+
if (!project || !location)
|
|
185
|
+
return undefined;
|
|
186
|
+
const name = output?.name ??
|
|
187
|
+
olds?.name ??
|
|
188
|
+
(yield* createPhysicalName({ id, maxLength: 49 })).toLowerCase();
|
|
189
|
+
const observed = yield* observe(project, location, name);
|
|
190
|
+
if (!observed)
|
|
191
|
+
return undefined;
|
|
192
|
+
const attrs = toAttributes(observed, { project, location, name });
|
|
193
|
+
return (yield* hasAlchemyLabels(id, observed.labels))
|
|
194
|
+
? attrs
|
|
195
|
+
: Unowned(attrs);
|
|
196
|
+
}),
|
|
197
|
+
};
|
|
198
|
+
}));
|
|
199
|
+
//# sourceMappingURL=Job.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Job.js","sourceRoot":"","sources":["../../src/Run/Job.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ConfigError } from "@distilled.cloud/gcp";
|
|
2
|
+
import * as run from "@distilled.cloud/gcp/run-v2";
|
|
3
|
+
import type { ScopedPlanStatusSession } from "alchemy/Cli/Cli";
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
/**
|
|
6
|
+
* Resolved callable signature of `run.getProjectsLocationsOperations`.
|
|
7
|
+
*
|
|
8
|
+
* `run.getProjectsLocationsOperations` is itself an
|
|
9
|
+
* `Effect<callable, never, Credentials | HttpClient>`, so `Effect.Success`
|
|
10
|
+
* extracts the callable type — what you get back from
|
|
11
|
+
* `yield* run.getProjectsLocationsOperations`. Using a derived alias
|
|
12
|
+
* keeps the helper aligned with the SDK without us hand-writing the
|
|
13
|
+
* input/output/error union, which would drift if the patch set changes.
|
|
14
|
+
*/
|
|
15
|
+
type GetOperations = Effect.Success<typeof run.getProjectsLocationsOperations>;
|
|
16
|
+
/**
|
|
17
|
+
* Build the Cloud Run long-running-operation polling helper.
|
|
18
|
+
*
|
|
19
|
+
* Cloud Run `Operation`s use the standard `GoogleLongrunningOperation`
|
|
20
|
+
* shape — doneness is `.done === true` (NOT `.status === "DONE"` like
|
|
21
|
+
* the GKE Container API). Verified at
|
|
22
|
+
* `vendor/distilled/packages/gcp/src/services/run-v2.ts:2880–2900`.
|
|
23
|
+
*
|
|
24
|
+
* Operation names returned by run-v2 (`createProjectsLocationsServices`,
|
|
25
|
+
* `patchProjectsLocationsServices`, `deleteProjectsLocationsServices`)
|
|
26
|
+
* are already fully qualified
|
|
27
|
+
* (`projects/{p}/locations/{l}/operations/{id}`), so callers pass them
|
|
28
|
+
* straight through to `getProjectsLocationsOperations` — no `qualifyOp`
|
|
29
|
+
* dance needed (unlike Container, which returns bare ids).
|
|
30
|
+
*
|
|
31
|
+
* Schedule: exponential 1s → 1.5× growth, capped per-poll at 10s via
|
|
32
|
+
* `Schedule.either`, then a hard count cap of 60 retries via
|
|
33
|
+
* `Schedule.both(Schedule.recurs(60))` → ~10 min wall ceiling. Cloud
|
|
34
|
+
* Run create/patch typically completes in seconds to a couple minutes,
|
|
35
|
+
* with the long pole being container image pulls.
|
|
36
|
+
*
|
|
37
|
+
* The helper is a factory — the caller resolves
|
|
38
|
+
* `run.getProjectsLocationsOperations` once at provider construction
|
|
39
|
+
* (see `Container/Operations.ts` for the same idiom) and passes the
|
|
40
|
+
* resulting callable here, so we never re-resolve services on each
|
|
41
|
+
* await.
|
|
42
|
+
*/
|
|
43
|
+
export declare const makeAwaitOperation: (getOperations: GetOperations) => (operationName: string, session: ScopedPlanStatusSession) => Effect.Effect<run.GoogleLongrunningOperation, ConfigError | run.GetProjectsLocationsOperationsError | {
|
|
44
|
+
_tag: "OperationPending";
|
|
45
|
+
}, never>;
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=Operations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Operations.d.ts","sourceRoot":"","sources":["../../src/Run/Operations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,GAAG,MAAM,6BAA6B,CAAC;AACnD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE/D,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC;;;;;;;;;GASG;AACH,KAAK,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,GAAG,CAAC,8BAA8B,CAAC,CAAC;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,kBAAkB,GAAI,eAAe,aAAa;;SA8B3D,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ConfigError } from "@distilled.cloud/gcp";
|
|
2
|
+
import * as Duration from "effect/Duration";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Schedule from "effect/Schedule";
|
|
5
|
+
/**
|
|
6
|
+
* Build the Cloud Run long-running-operation polling helper.
|
|
7
|
+
*
|
|
8
|
+
* Cloud Run `Operation`s use the standard `GoogleLongrunningOperation`
|
|
9
|
+
* shape — doneness is `.done === true` (NOT `.status === "DONE"` like
|
|
10
|
+
* the GKE Container API). Verified at
|
|
11
|
+
* `vendor/distilled/packages/gcp/src/services/run-v2.ts:2880–2900`.
|
|
12
|
+
*
|
|
13
|
+
* Operation names returned by run-v2 (`createProjectsLocationsServices`,
|
|
14
|
+
* `patchProjectsLocationsServices`, `deleteProjectsLocationsServices`)
|
|
15
|
+
* are already fully qualified
|
|
16
|
+
* (`projects/{p}/locations/{l}/operations/{id}`), so callers pass them
|
|
17
|
+
* straight through to `getProjectsLocationsOperations` — no `qualifyOp`
|
|
18
|
+
* dance needed (unlike Container, which returns bare ids).
|
|
19
|
+
*
|
|
20
|
+
* Schedule: exponential 1s → 1.5× growth, capped per-poll at 10s via
|
|
21
|
+
* `Schedule.either`, then a hard count cap of 60 retries via
|
|
22
|
+
* `Schedule.both(Schedule.recurs(60))` → ~10 min wall ceiling. Cloud
|
|
23
|
+
* Run create/patch typically completes in seconds to a couple minutes,
|
|
24
|
+
* with the long pole being container image pulls.
|
|
25
|
+
*
|
|
26
|
+
* The helper is a factory — the caller resolves
|
|
27
|
+
* `run.getProjectsLocationsOperations` once at provider construction
|
|
28
|
+
* (see `Container/Operations.ts` for the same idiom) and passes the
|
|
29
|
+
* resulting callable here, so we never re-resolve services on each
|
|
30
|
+
* await.
|
|
31
|
+
*/
|
|
32
|
+
export const makeAwaitOperation = (getOperations) => Effect.fn(function* (operationName, session) {
|
|
33
|
+
const op = yield* getOperations({ name: operationName }).pipe(Effect.flatMap((current) => current.done === true
|
|
34
|
+
? Effect.succeed(current)
|
|
35
|
+
: Effect.fail({ _tag: "OperationPending" })), Effect.retry({
|
|
36
|
+
while: (e) => e?._tag === "OperationPending",
|
|
37
|
+
schedule: Schedule.exponential(Duration.seconds(1), 1.5).pipe(Schedule.either(Schedule.spaced(Duration.seconds(10))), Schedule.both(Schedule.recurs(60)), Schedule.tapOutput(() => session.note(`Waiting for Cloud Run operation ${operationName}…`))),
|
|
38
|
+
}));
|
|
39
|
+
if (op.error) {
|
|
40
|
+
return yield* new ConfigError({
|
|
41
|
+
message: `Cloud Run operation ${operationName} failed: ${op.error.message ?? JSON.stringify(op.error)}`,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return op;
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=Operations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Operations.js","sourceRoot":"","sources":["../../src/Run/Operations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGnD,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAc5C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,aAA4B,EAAE,EAAE,CACjE,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EACjB,aAAqB,EACrB,OAAgC;IAEhC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC,IAAI,CAC3D,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CACzB,OAAO,CAAC,IAAI,KAAK,IAAI;QACnB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;QACzB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,kBAA2B,EAAE,CAAC,CACvD,EACD,MAAM,CAAC,KAAK,CAAC;QACX,KAAK,EAAE,CAAC,CAAoB,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,kBAAkB;QAC/D,QAAQ,EAAE,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAC3D,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EACtD,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAClC,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,CACtB,OAAO,CAAC,IAAI,CAAC,mCAAmC,aAAa,GAAG,CAAC,CAClE,CACF;KACF,CAAC,CACH,CAAC;IACF,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,OAAO,KAAK,CAAC,CAAC,IAAI,WAAW,CAAC;YAC5B,OAAO,EAAE,uBAAuB,aAAa,YAC3C,EAAE,CAAC,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAC7C,EAAE;SACH,CAAC,CAAC;IACL,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC,CAAC"}
|