alchemy 2.0.0-beta.64 → 2.0.0-beta.65
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/lib/AWS/EC2/InternetGateway.d.ts.map +1 -1
- package/lib/AWS/EC2/InternetGateway.js +8 -3
- package/lib/AWS/EC2/InternetGateway.js.map +1 -1
- package/lib/AWS/EC2/LingeringEnis.d.ts +26 -0
- package/lib/AWS/EC2/LingeringEnis.d.ts.map +1 -0
- package/lib/AWS/EC2/LingeringEnis.js +128 -0
- package/lib/AWS/EC2/LingeringEnis.js.map +1 -0
- package/lib/AWS/EC2/SecurityGroup.d.ts.map +1 -1
- package/lib/AWS/EC2/SecurityGroup.js +14 -14
- package/lib/AWS/EC2/SecurityGroup.js.map +1 -1
- package/lib/AWS/EC2/Subnet.d.ts.map +1 -1
- package/lib/AWS/EC2/Subnet.js +13 -21
- package/lib/AWS/EC2/Subnet.js.map +1 -1
- package/lib/AWS/ECR/Image.d.ts +1 -0
- package/lib/AWS/ECR/Image.d.ts.map +1 -1
- package/lib/AWS/EKS/Addon.d.ts.map +1 -1
- package/lib/AWS/EKS/Addon.js +15 -3
- package/lib/AWS/EKS/Addon.js.map +1 -1
- package/lib/AWS/EKS/Deployment.d.ts +10 -1
- package/lib/AWS/EKS/Deployment.d.ts.map +1 -1
- package/lib/AWS/EKS/Deployment.js +10 -4
- package/lib/AWS/EKS/Deployment.js.map +1 -1
- package/lib/AWS/EKS/HyperPod.d.ts +57 -0
- package/lib/AWS/EKS/HyperPod.d.ts.map +1 -0
- package/lib/AWS/EKS/HyperPod.js +46 -0
- package/lib/AWS/EKS/HyperPod.js.map +1 -0
- package/lib/AWS/EKS/Job.d.ts +10 -1
- package/lib/AWS/EKS/Job.d.ts.map +1 -1
- package/lib/AWS/EKS/Job.js +16 -6
- package/lib/AWS/EKS/Job.js.map +1 -1
- package/lib/AWS/EKS/internal/client.d.ts +4 -3
- package/lib/AWS/EKS/internal/client.d.ts.map +1 -1
- package/lib/AWS/EKS/internal/client.js +33 -2
- package/lib/AWS/EKS/internal/client.js.map +1 -1
- package/lib/AWS/Lambda/Function.d.ts.map +1 -1
- package/lib/AWS/Lambda/Function.js +1 -1
- package/lib/AWS/Lambda/Function.js.map +1 -1
- package/lib/AWS/Providers.d.ts.map +1 -1
- package/lib/AWS/Providers.js +4 -1
- package/lib/AWS/Providers.js.map +1 -1
- package/lib/AWS/SageMaker/Cluster.d.ts +327 -0
- package/lib/AWS/SageMaker/Cluster.d.ts.map +1 -0
- package/lib/AWS/SageMaker/Cluster.js +469 -0
- package/lib/AWS/SageMaker/Cluster.js.map +1 -0
- package/lib/AWS/SageMaker/ClusterSchedulerConfig.d.ts +96 -0
- package/lib/AWS/SageMaker/ClusterSchedulerConfig.d.ts.map +1 -0
- package/lib/AWS/SageMaker/ClusterSchedulerConfig.js +270 -0
- package/lib/AWS/SageMaker/ClusterSchedulerConfig.js.map +1 -0
- package/lib/AWS/SageMaker/ComputeQuota.d.ts +106 -0
- package/lib/AWS/SageMaker/ComputeQuota.d.ts.map +1 -0
- package/lib/AWS/SageMaker/ComputeQuota.js +268 -0
- package/lib/AWS/SageMaker/ComputeQuota.js.map +1 -0
- package/lib/AWS/SageMaker/index.d.ts +3 -0
- package/lib/AWS/SageMaker/index.d.ts.map +1 -1
- package/lib/AWS/SageMaker/index.js +3 -0
- package/lib/AWS/SageMaker/index.js.map +1 -1
- package/lib/Bundle/PurePlugin.d.ts +29 -7
- package/lib/Bundle/PurePlugin.d.ts.map +1 -1
- package/lib/Bundle/PurePlugin.js +56 -33
- package/lib/Bundle/PurePlugin.js.map +1 -1
- package/lib/Cli/commands/nuke.d.ts.map +1 -1
- package/lib/Cli/commands/nuke.js +231 -37
- package/lib/Cli/commands/nuke.js.map +1 -1
- package/lib/Cloudflare/StateStore/Api.d.ts +1 -1
- package/lib/Cloudflare/Workers/Assets.d.ts +26 -8
- package/lib/Cloudflare/Workers/Assets.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Assets.js +46 -1
- package/lib/Cloudflare/Workers/Assets.js.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts +2 -2
- package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js +39 -6
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js.map +1 -1
- package/lib/Cloudflare/Workers/Worker.d.ts +7 -5
- package/lib/Cloudflare/Workers/Worker.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Worker.js +0 -1
- package/lib/Cloudflare/Workers/Worker.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBinding.d.ts +2 -2
- package/lib/Cloudflare/Workers/WorkerBundle.d.ts +20 -1
- package/lib/Cloudflare/Workers/WorkerBundle.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBundle.js +11 -0
- package/lib/Cloudflare/Workers/WorkerBundle.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerProvider.js +10 -4
- package/lib/Cloudflare/Workers/WorkerProvider.js.map +1 -1
- package/lib/Cloudflare/Workflows/WorkflowBridge.d.ts +2 -1
- package/lib/Cloudflare/Workflows/WorkflowBridge.d.ts.map +1 -1
- package/lib/Cloudflare/Workflows/WorkflowBridge.js +5 -5
- package/lib/Cloudflare/Workflows/WorkflowBridge.js.map +1 -1
- package/lib/Cloudflare/Workflows/index.d.ts +1 -1
- package/lib/Cloudflare/Workflows/index.d.ts.map +1 -1
- package/lib/Cloudflare/Workflows/index.js +1 -1
- package/lib/Cloudflare/Workflows/index.js.map +1 -1
- package/lib/Docker/Container.d.ts +26 -0
- package/lib/Docker/Container.d.ts.map +1 -1
- package/lib/Docker/Container.js +20 -1
- package/lib/Docker/Container.js.map +1 -1
- package/lib/Docker/Docker.d.ts +2 -0
- package/lib/Docker/Docker.d.ts.map +1 -1
- package/lib/Docker/Docker.js.map +1 -1
- package/lib/Output.d.ts +4 -1
- package/lib/Output.d.ts.map +1 -1
- package/lib/Output.js.map +1 -1
- package/lib/Provider.d.ts +20 -0
- package/lib/Provider.d.ts.map +1 -1
- package/lib/Provider.js.map +1 -1
- package/lib/Random.d.ts +1 -1
- package/lib/Random.d.ts.map +1 -1
- package/lib/Resource.d.ts +14 -1
- package/lib/Resource.d.ts.map +1 -1
- package/lib/Resource.js.map +1 -1
- package/lib/SQL/D1.d.ts +1 -1
- package/lib/SQL/D1.js +1 -1
- package/lib/SQL/Postgres.d.ts +1 -1
- package/lib/SQL/Postgres.js +1 -1
- package/lib/State/HttpStateApi.d.ts +11 -11
- package/lib/Test/Alchemy.d.ts +1 -1
- package/lib/Test/Alchemy.js +1 -1
- package/lib/Test/Vitest.d.ts +58 -0
- package/lib/Test/Vitest.d.ts.map +1 -0
- package/lib/Test/Vitest.js +114 -0
- package/lib/Test/Vitest.js.map +1 -0
- package/lib/Util/proxy-chain.d.ts +5 -0
- package/lib/Util/proxy-chain.d.ts.map +1 -1
- package/lib/Util/proxy-chain.js +52 -4
- package/lib/Util/proxy-chain.js.map +1 -1
- package/package.json +23 -15
- package/src/AWS/EC2/InternetGateway.ts +8 -3
- package/src/AWS/EC2/LingeringEnis.ts +169 -0
- package/src/AWS/EC2/SecurityGroup.ts +24 -28
- package/src/AWS/EC2/Subnet.ts +23 -34
- package/src/AWS/EKS/Addon.ts +17 -4
- package/src/AWS/EKS/Deployment.ts +26 -5
- package/src/AWS/EKS/HyperPod.ts +97 -0
- package/src/AWS/EKS/Job.ts +32 -7
- package/src/AWS/EKS/internal/client.ts +40 -3
- package/src/AWS/Lambda/Function.ts +5 -3
- package/src/AWS/Providers.ts +6 -0
- package/src/AWS/SageMaker/Cluster.ts +775 -0
- package/src/AWS/SageMaker/ClusterSchedulerConfig.ts +430 -0
- package/src/AWS/SageMaker/ComputeQuota.ts +426 -0
- package/src/AWS/SageMaker/index.ts +3 -0
- package/src/Bundle/PurePlugin.ts +92 -39
- package/src/Cli/commands/nuke.ts +295 -56
- package/src/Cloudflare/Workers/Assets.ts +53 -1
- package/src/Cloudflare/Workers/LocalWorkerProvider.ts +46 -7
- package/src/Cloudflare/Workers/Worker.ts +7 -5
- package/src/Cloudflare/Workers/WorkerBundle.ts +31 -1
- package/src/Cloudflare/Workers/WorkerProvider.ts +18 -4
- package/src/Cloudflare/Workflows/WorkflowBridge.ts +5 -5
- package/src/Cloudflare/Workflows/index.ts +1 -1
- package/src/Docker/Container.ts +30 -1
- package/src/Docker/Docker.ts +2 -0
- package/src/Output.ts +19 -11
- package/src/Provider.ts +20 -0
- package/src/Resource.ts +18 -1
- package/src/SQL/D1.ts +1 -1
- package/src/SQL/Postgres.ts +1 -1
- package/src/Test/Alchemy.ts +1 -1
- package/src/Test/Vitest.ts +244 -0
- package/src/Util/proxy-chain.ts +73 -4
- package/lib/SQL/index.d.ts +0 -4
- package/lib/SQL/index.d.ts.map +0 -1
- package/lib/SQL/index.js +0 -4
- package/lib/SQL/index.js.map +0 -1
- package/src/SQL/index.ts +0 -3
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import * as sagemaker from "@distilled.cloud/aws/sagemaker";
|
|
2
|
+
import * as Data from "effect/Data";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Schedule from "effect/Schedule";
|
|
5
|
+
import * as EffectStream from "effect/Stream";
|
|
6
|
+
import { Unowned } from "../../AdoptPolicy.js";
|
|
7
|
+
import { isResolved } from "../../Diff.js";
|
|
8
|
+
import { createPhysicalName } from "../../PhysicalName.js";
|
|
9
|
+
import * as Provider from "../../Provider.js";
|
|
10
|
+
import { Resource } from "../../Resource.js";
|
|
11
|
+
import { createInternalTags, diffTags, hasAlchemyTags, } from "../../Tags.js";
|
|
12
|
+
/**
|
|
13
|
+
* A SageMaker HyperPod cluster policy (task governance) — configures how an
|
|
14
|
+
* EKS-orchestrated HyperPod cluster prioritizes tasks and allocates idle
|
|
15
|
+
* compute across teams via priority classes and fair-share weights.
|
|
16
|
+
* @resource
|
|
17
|
+
* @section Creating Cluster Policies
|
|
18
|
+
* @example Priority Classes with Fair-Share
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import * as AWS from "alchemy/AWS";
|
|
21
|
+
*
|
|
22
|
+
* const policy = yield* AWS.SageMaker.ClusterSchedulerConfig("Scheduler", {
|
|
23
|
+
* clusterArn: hyperpod.clusterArn,
|
|
24
|
+
* schedulerConfig: {
|
|
25
|
+
* PriorityClasses: [
|
|
26
|
+
* { Name: "inference", Weight: 100 },
|
|
27
|
+
* { Name: "training", Weight: 75 },
|
|
28
|
+
* ],
|
|
29
|
+
* FairShare: "Enabled",
|
|
30
|
+
* },
|
|
31
|
+
* description: "Prioritize inference over training",
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export const ClusterSchedulerConfig = Resource("AWS.SageMaker.ClusterSchedulerConfig");
|
|
36
|
+
const createConfigName = (id, props) => props.name
|
|
37
|
+
? Effect.succeed(props.name)
|
|
38
|
+
: createPhysicalName({ id, maxLength: 63 });
|
|
39
|
+
const describeConfigOrUndefined = (configId) => sagemaker
|
|
40
|
+
.describeClusterSchedulerConfig({ ClusterSchedulerConfigId: configId })
|
|
41
|
+
.pipe(Effect.catchTag("ResourceNotFound", () => Effect.succeed(undefined)));
|
|
42
|
+
/**
|
|
43
|
+
* Look a cluster policy up by exact name — used when state was lost (read
|
|
44
|
+
* without output) or a create raced.
|
|
45
|
+
*/
|
|
46
|
+
const findConfigByName = Effect.fn(function* (name) {
|
|
47
|
+
const summaries = yield* sagemaker.listClusterSchedulerConfigs
|
|
48
|
+
.pages({ NameContains: name })
|
|
49
|
+
.pipe(EffectStream.runCollect, Effect.map((chunk) => Array.from(chunk).flatMap((page) => page.ClusterSchedulerConfigSummaries ?? [])));
|
|
50
|
+
return summaries.find((s) => s.Name === name && s.Status !== "Deleted");
|
|
51
|
+
});
|
|
52
|
+
const fetchConfigTags = Effect.fn(function* (arn) {
|
|
53
|
+
const response = yield* sagemaker
|
|
54
|
+
.listTags({ ResourceArn: arn })
|
|
55
|
+
.pipe(Effect.catchTag("AccessDeniedException", () => Effect.succeed(undefined)));
|
|
56
|
+
return Object.fromEntries((response?.Tags ?? []).flatMap((tag) => tag.Key !== undefined ? [[tag.Key, tag.Value ?? ""]] : []));
|
|
57
|
+
});
|
|
58
|
+
const toAttrs = (described) => ({
|
|
59
|
+
clusterSchedulerConfigId: described.ClusterSchedulerConfigId,
|
|
60
|
+
clusterSchedulerConfigArn: described.ClusterSchedulerConfigArn,
|
|
61
|
+
name: described.Name,
|
|
62
|
+
clusterArn: described.ClusterArn ?? "",
|
|
63
|
+
clusterSchedulerConfigVersion: described.ClusterSchedulerConfigVersion,
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* The cluster policy is still transitioning toward the awaited state —
|
|
67
|
+
* retried by the bounded wait schedule.
|
|
68
|
+
*/
|
|
69
|
+
class SchedulerConfigNotReady extends Data.TaggedError("SchedulerConfigNotReady") {
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The cluster policy converged to a terminal failed status.
|
|
73
|
+
*/
|
|
74
|
+
export class SchedulerConfigFailed extends Data.TaggedError("SchedulerConfigFailed") {
|
|
75
|
+
}
|
|
76
|
+
const FAILED_STATUSES = [
|
|
77
|
+
"CreateFailed",
|
|
78
|
+
"CreateRollbackFailed",
|
|
79
|
+
"UpdateFailed",
|
|
80
|
+
"UpdateRollbackFailed",
|
|
81
|
+
"DeleteFailed",
|
|
82
|
+
"DeleteRollbackFailed",
|
|
83
|
+
];
|
|
84
|
+
// Explicitly-typed retry wrapper — an inline `Effect.retry` in provider
|
|
85
|
+
// lifecycle code leaks `Retry.Return`'s conditional type into declaration
|
|
86
|
+
// emit and widens the provider layer to `unknown` for every consumer of
|
|
87
|
+
// `AWS.providers()`.
|
|
88
|
+
const retryWhileNotReady = (self) => Effect.retry(self, {
|
|
89
|
+
while: (e) => e._tag === "SchedulerConfigNotReady",
|
|
90
|
+
schedule: Schedule.max([Schedule.spaced("5 seconds"), Schedule.recurs(60)]),
|
|
91
|
+
});
|
|
92
|
+
const waitForConfig = (configId, target) => retryWhileNotReady(Effect.gen(function* () {
|
|
93
|
+
const described = yield* describeConfigOrUndefined(configId);
|
|
94
|
+
if (target === "Gone") {
|
|
95
|
+
if (described === undefined || described.Status === "Deleted")
|
|
96
|
+
return;
|
|
97
|
+
if (FAILED_STATUSES.includes(described.Status)) {
|
|
98
|
+
return yield* Effect.fail(new SchedulerConfigFailed({
|
|
99
|
+
configId,
|
|
100
|
+
status: described.Status,
|
|
101
|
+
message: described.FailureReason,
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
return yield* Effect.fail(new SchedulerConfigNotReady({ configId, status: described.Status }));
|
|
105
|
+
}
|
|
106
|
+
if (described?.Status === "Created" || described?.Status === "Updated") {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (described !== undefined &&
|
|
110
|
+
FAILED_STATUSES.includes(described.Status)) {
|
|
111
|
+
return yield* Effect.fail(new SchedulerConfigFailed({
|
|
112
|
+
configId,
|
|
113
|
+
status: described.Status,
|
|
114
|
+
message: described.FailureReason,
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
return yield* Effect.fail(new SchedulerConfigNotReady({ configId, status: described?.Status }));
|
|
118
|
+
}));
|
|
119
|
+
export const ClusterSchedulerConfigProvider = () => Provider.effect(ClusterSchedulerConfig, Effect.gen(function* () {
|
|
120
|
+
return {
|
|
121
|
+
stables: [
|
|
122
|
+
"clusterSchedulerConfigId",
|
|
123
|
+
"clusterSchedulerConfigArn",
|
|
124
|
+
"name",
|
|
125
|
+
"clusterArn",
|
|
126
|
+
],
|
|
127
|
+
list: () => Effect.gen(function* () {
|
|
128
|
+
const summaries = yield* sagemaker.listClusterSchedulerConfigs
|
|
129
|
+
.pages({})
|
|
130
|
+
.pipe(EffectStream.runCollect, Effect.map((chunk) => Array.from(chunk).flatMap((page) => page.ClusterSchedulerConfigSummaries ?? [])));
|
|
131
|
+
return summaries.flatMap((s) => s.ClusterSchedulerConfigId !== undefined && s.Status !== "Deleted"
|
|
132
|
+
? [
|
|
133
|
+
{
|
|
134
|
+
clusterSchedulerConfigId: s.ClusterSchedulerConfigId,
|
|
135
|
+
clusterSchedulerConfigArn: s.ClusterSchedulerConfigArn ?? "",
|
|
136
|
+
name: s.Name ?? "",
|
|
137
|
+
clusterArn: s.ClusterArn ?? "",
|
|
138
|
+
clusterSchedulerConfigVersion: s.ClusterSchedulerConfigVersion ?? 1,
|
|
139
|
+
},
|
|
140
|
+
]
|
|
141
|
+
: []);
|
|
142
|
+
}),
|
|
143
|
+
read: Effect.fn(function* ({ id, olds, output }) {
|
|
144
|
+
const configId = output?.clusterSchedulerConfigId ??
|
|
145
|
+
(yield* findConfigByName(yield* createConfigName(id, olds ?? {})))
|
|
146
|
+
?.ClusterSchedulerConfigId;
|
|
147
|
+
if (configId === undefined)
|
|
148
|
+
return undefined;
|
|
149
|
+
const described = yield* describeConfigOrUndefined(configId);
|
|
150
|
+
if (!described ||
|
|
151
|
+
described.Status === "Deleting" ||
|
|
152
|
+
described.Status === "Deleted") {
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
const attrs = toAttrs(described);
|
|
156
|
+
const tags = yield* fetchConfigTags(attrs.clusterSchedulerConfigArn);
|
|
157
|
+
return (yield* hasAlchemyTags(id, tags))
|
|
158
|
+
? attrs
|
|
159
|
+
: Unowned(attrs);
|
|
160
|
+
}),
|
|
161
|
+
diff: Effect.fn(function* ({ id, news, olds }) {
|
|
162
|
+
if (!isResolved(news))
|
|
163
|
+
return;
|
|
164
|
+
if (olds === undefined)
|
|
165
|
+
return;
|
|
166
|
+
const oldName = yield* createConfigName(id, olds);
|
|
167
|
+
const newName = yield* createConfigName(id, news);
|
|
168
|
+
// The name and target cluster are fixed at creation.
|
|
169
|
+
if (oldName !== newName || olds.clusterArn !== news.clusterArn) {
|
|
170
|
+
return { action: "replace" };
|
|
171
|
+
}
|
|
172
|
+
}),
|
|
173
|
+
reconcile: Effect.fn(function* ({ id, news, output, session }) {
|
|
174
|
+
if (!news) {
|
|
175
|
+
return yield* Effect.fail(new Error("SageMaker ClusterSchedulerConfig requires props"));
|
|
176
|
+
}
|
|
177
|
+
const name = yield* createConfigName(id, news);
|
|
178
|
+
const internalTags = yield* createInternalTags(id);
|
|
179
|
+
const desiredTags = { ...internalTags, ...news.tags };
|
|
180
|
+
// Observe — by cached id first, then by name (lost state or race).
|
|
181
|
+
let configId = output?.clusterSchedulerConfigId;
|
|
182
|
+
let described = configId !== undefined
|
|
183
|
+
? yield* describeConfigOrUndefined(configId)
|
|
184
|
+
: undefined;
|
|
185
|
+
if (described === undefined) {
|
|
186
|
+
const found = yield* findConfigByName(name);
|
|
187
|
+
described =
|
|
188
|
+
found?.ClusterSchedulerConfigId !== undefined
|
|
189
|
+
? yield* describeConfigOrUndefined(found.ClusterSchedulerConfigId)
|
|
190
|
+
: undefined;
|
|
191
|
+
}
|
|
192
|
+
// Ensure — create if missing; a Conflict means a concurrent
|
|
193
|
+
// create won the race, so re-observe by name.
|
|
194
|
+
if (described === undefined) {
|
|
195
|
+
const created = yield* sagemaker
|
|
196
|
+
.createClusterSchedulerConfig({
|
|
197
|
+
Name: name,
|
|
198
|
+
ClusterArn: news.clusterArn,
|
|
199
|
+
SchedulerConfig: news.schedulerConfig,
|
|
200
|
+
Description: news.description,
|
|
201
|
+
Tags: Object.entries(desiredTags).map(([Key, Value]) => ({
|
|
202
|
+
Key,
|
|
203
|
+
Value,
|
|
204
|
+
})),
|
|
205
|
+
})
|
|
206
|
+
.pipe(Effect.catchTag("ConflictException", () => Effect.succeed(undefined)));
|
|
207
|
+
configId =
|
|
208
|
+
created?.ClusterSchedulerConfigId ??
|
|
209
|
+
(yield* findConfigByName(name))?.ClusterSchedulerConfigId;
|
|
210
|
+
if (configId === undefined) {
|
|
211
|
+
return yield* Effect.fail(new Error(`failed to create cluster scheduler config ${name}`));
|
|
212
|
+
}
|
|
213
|
+
yield* session.note(`Creating cluster policy ${name}...`);
|
|
214
|
+
yield* waitForConfig(configId, "Ready");
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
configId = described.ClusterSchedulerConfigId;
|
|
218
|
+
// Wait out any in-flight transition before diffing.
|
|
219
|
+
yield* waitForConfig(configId, "Ready");
|
|
220
|
+
described = yield* describeConfigOrUndefined(configId);
|
|
221
|
+
// Sync — diff observed policy against desired.
|
|
222
|
+
if (described !== undefined &&
|
|
223
|
+
(JSON.stringify(described.SchedulerConfig) !==
|
|
224
|
+
JSON.stringify(news.schedulerConfig) ||
|
|
225
|
+
(described.Description ?? undefined) !==
|
|
226
|
+
(news.description ?? undefined))) {
|
|
227
|
+
yield* sagemaker.updateClusterSchedulerConfig({
|
|
228
|
+
ClusterSchedulerConfigId: configId,
|
|
229
|
+
TargetVersion: described.ClusterSchedulerConfigVersion,
|
|
230
|
+
SchedulerConfig: news.schedulerConfig,
|
|
231
|
+
Description: news.description,
|
|
232
|
+
});
|
|
233
|
+
yield* session.note(`Updating cluster policy ${name}...`);
|
|
234
|
+
yield* waitForConfig(configId, "Ready");
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
described = yield* describeConfigOrUndefined(configId);
|
|
238
|
+
if (described === undefined) {
|
|
239
|
+
return yield* Effect.fail(new Error(`failed to read reconciled cluster scheduler config ${name}`));
|
|
240
|
+
}
|
|
241
|
+
const attrs = toAttrs(described);
|
|
242
|
+
// Sync tags — diff against OBSERVED cloud tags.
|
|
243
|
+
const currentTags = yield* fetchConfigTags(attrs.clusterSchedulerConfigArn);
|
|
244
|
+
const { removed, upsert } = diffTags(currentTags, desiredTags);
|
|
245
|
+
if (removed.length > 0) {
|
|
246
|
+
yield* sagemaker.deleteTags({
|
|
247
|
+
ResourceArn: attrs.clusterSchedulerConfigArn,
|
|
248
|
+
TagKeys: removed,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
if (upsert.length > 0) {
|
|
252
|
+
yield* sagemaker.addTags({
|
|
253
|
+
ResourceArn: attrs.clusterSchedulerConfigArn,
|
|
254
|
+
Tags: upsert.map(({ Key, Value }) => ({ Key, Value })),
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
yield* session.note(attrs.clusterSchedulerConfigArn);
|
|
258
|
+
return attrs;
|
|
259
|
+
}),
|
|
260
|
+
delete: Effect.fn(function* ({ output }) {
|
|
261
|
+
yield* sagemaker
|
|
262
|
+
.deleteClusterSchedulerConfig({
|
|
263
|
+
ClusterSchedulerConfigId: output.clusterSchedulerConfigId,
|
|
264
|
+
})
|
|
265
|
+
.pipe(Effect.catchTag("ResourceNotFound", () => Effect.void));
|
|
266
|
+
yield* waitForConfig(output.clusterSchedulerConfigId, "Gone");
|
|
267
|
+
}),
|
|
268
|
+
};
|
|
269
|
+
}));
|
|
270
|
+
//# sourceMappingURL=ClusterSchedulerConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClusterSchedulerConfig.js","sourceRoot":"","sources":["../../../src/AWS/SageMaker/ClusterSchedulerConfig.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import * as sagemaker from "@distilled.cloud/aws/sagemaker";
|
|
2
|
+
import * as Provider from "../../Provider.ts";
|
|
3
|
+
import { Resource } from "../../Resource.ts";
|
|
4
|
+
import type { Providers } from "../Providers.ts";
|
|
5
|
+
export interface ComputeQuotaProps {
|
|
6
|
+
/**
|
|
7
|
+
* Name of the compute allocation. Maximum 63 characters, alphanumeric and
|
|
8
|
+
* hyphens.
|
|
9
|
+
* @default ${app}-${stage}-${id}
|
|
10
|
+
*/
|
|
11
|
+
name?: string;
|
|
12
|
+
/**
|
|
13
|
+
* ARN of the EKS-orchestrated HyperPod cluster the allocation applies to.
|
|
14
|
+
* Changing the cluster replaces the allocation.
|
|
15
|
+
*/
|
|
16
|
+
clusterArn: string;
|
|
17
|
+
/**
|
|
18
|
+
* The team the quota is allocated to (its name maps to a Kubernetes
|
|
19
|
+
* namespace `hyperpod-ns-<team-name>`) and its fair-share weight.
|
|
20
|
+
*/
|
|
21
|
+
computeQuotaTarget: sagemaker.ComputeQuotaTarget;
|
|
22
|
+
/**
|
|
23
|
+
* The allocation itself: instance-type quotas, the resource-sharing
|
|
24
|
+
* strategy for idle compute, and whether the team's own tasks can preempt
|
|
25
|
+
* each other.
|
|
26
|
+
*/
|
|
27
|
+
computeQuotaConfig?: sagemaker.ComputeQuotaConfig;
|
|
28
|
+
/**
|
|
29
|
+
* Whether the quota is enforced.
|
|
30
|
+
* @default "Enabled"
|
|
31
|
+
*/
|
|
32
|
+
activationState?: sagemaker.ActivationState;
|
|
33
|
+
/**
|
|
34
|
+
* A description of the compute allocation.
|
|
35
|
+
*/
|
|
36
|
+
description?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Tags to associate with the compute allocation. Merged with internal
|
|
39
|
+
* Alchemy tags.
|
|
40
|
+
*/
|
|
41
|
+
tags?: Record<string, string>;
|
|
42
|
+
}
|
|
43
|
+
export interface ComputeQuota extends Resource<"AWS.SageMaker.ComputeQuota", ComputeQuotaProps, {
|
|
44
|
+
/**
|
|
45
|
+
* The compute allocation's ID.
|
|
46
|
+
*/
|
|
47
|
+
computeQuotaId: string;
|
|
48
|
+
/**
|
|
49
|
+
* ARN of the compute allocation.
|
|
50
|
+
*/
|
|
51
|
+
computeQuotaArn: string;
|
|
52
|
+
/**
|
|
53
|
+
* The compute allocation's name.
|
|
54
|
+
*/
|
|
55
|
+
name: string;
|
|
56
|
+
/**
|
|
57
|
+
* ARN of the HyperPod cluster the allocation applies to.
|
|
58
|
+
*/
|
|
59
|
+
clusterArn: string;
|
|
60
|
+
/**
|
|
61
|
+
* The allocation's current version (incremented on every update).
|
|
62
|
+
*/
|
|
63
|
+
computeQuotaVersion: number;
|
|
64
|
+
/**
|
|
65
|
+
* The team the quota is allocated to. Task governance materializes the
|
|
66
|
+
* `hyperpod-ns-<teamName>` namespace and its Kueue LocalQueue from it.
|
|
67
|
+
*/
|
|
68
|
+
teamName: string;
|
|
69
|
+
}, never, Providers> {
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* A SageMaker HyperPod compute allocation (task governance) — reserves
|
|
73
|
+
* instance capacity on an EKS-orchestrated HyperPod cluster for a team,
|
|
74
|
+
* with fair-share weights and borrow/lend rules for idle compute.
|
|
75
|
+
* @resource
|
|
76
|
+
* @section Creating Compute Allocations
|
|
77
|
+
* @example Team Quota with Borrowing
|
|
78
|
+
* ```typescript
|
|
79
|
+
* import * as AWS from "alchemy/AWS";
|
|
80
|
+
*
|
|
81
|
+
* const quota = yield* AWS.SageMaker.ComputeQuota("ResearchQuota", {
|
|
82
|
+
* clusterArn: hyperpod.clusterArn,
|
|
83
|
+
* computeQuotaTarget: { TeamName: "research", FairShareWeight: 10 },
|
|
84
|
+
* computeQuotaConfig: {
|
|
85
|
+
* ComputeQuotaResources: [{ InstanceType: "ml.g5.xlarge", Count: 2 }],
|
|
86
|
+
* ResourceSharingConfig: { Strategy: "Lend", BorrowLimit: 50 },
|
|
87
|
+
* },
|
|
88
|
+
* });
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare const ComputeQuota: import("../../Resource.ts").ResourceClass<ComputeQuota>;
|
|
92
|
+
declare const ComputeQuotaFailed_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
93
|
+
readonly _tag: "ComputeQuotaFailed";
|
|
94
|
+
} & Readonly<A>;
|
|
95
|
+
/**
|
|
96
|
+
* The compute allocation converged to a terminal failed status.
|
|
97
|
+
*/
|
|
98
|
+
export declare class ComputeQuotaFailed extends ComputeQuotaFailed_base<{
|
|
99
|
+
readonly quotaId: string;
|
|
100
|
+
readonly status: string | undefined;
|
|
101
|
+
readonly message: string | undefined;
|
|
102
|
+
}> {
|
|
103
|
+
}
|
|
104
|
+
export declare const ComputeQuotaProvider: () => import("effect/Layer").Layer<Provider.Provider<ComputeQuota>, never, import("@distilled.cloud/aws/Credentials").Credentials | import("effect/unstable/http/HttpClient").HttpClient | import("@distilled.cloud/aws/Region").Region | import("../../Stack.ts").Stack | import("../../Stage.ts").Stage>;
|
|
105
|
+
export {};
|
|
106
|
+
//# sourceMappingURL=ComputeQuota.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComputeQuota.d.ts","sourceRoot":"","sources":["../../../src/AWS/SageMaker/ComputeQuota.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,gCAAgC,CAAC;AAQ5D,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAO7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,kBAAkB,EAAE,SAAS,CAAC,kBAAkB,CAAC;IACjD;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,SAAS,CAAC,kBAAkB,CAAC;IAClD;;;OAGG;IACH,eAAe,CAAC,EAAE,SAAS,CAAC,eAAe,CAAC;IAC5C;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,YAAa,SAAQ,QAAQ,CAC5C,4BAA4B,EAC5B,iBAAiB,EACjB;IACE;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB,EACD,KAAK,EACL,SAAS,CACV;CAAG;AAEJ;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,YAAY,yDAExB,CAAC;;;;AA6DF;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,wBAAuC;IAC7E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC,CAAC;CAAG;AA+DL,eAAO,MAAM,oBAAoB,4SAqL9B,CAAC"}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import * as sagemaker from "@distilled.cloud/aws/sagemaker";
|
|
2
|
+
import * as Data from "effect/Data";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Schedule from "effect/Schedule";
|
|
5
|
+
import * as EffectStream from "effect/Stream";
|
|
6
|
+
import { Unowned } from "../../AdoptPolicy.js";
|
|
7
|
+
import { isResolved } from "../../Diff.js";
|
|
8
|
+
import { createPhysicalName } from "../../PhysicalName.js";
|
|
9
|
+
import * as Provider from "../../Provider.js";
|
|
10
|
+
import { Resource } from "../../Resource.js";
|
|
11
|
+
import { createInternalTags, diffTags, hasAlchemyTags, } from "../../Tags.js";
|
|
12
|
+
/**
|
|
13
|
+
* A SageMaker HyperPod compute allocation (task governance) — reserves
|
|
14
|
+
* instance capacity on an EKS-orchestrated HyperPod cluster for a team,
|
|
15
|
+
* with fair-share weights and borrow/lend rules for idle compute.
|
|
16
|
+
* @resource
|
|
17
|
+
* @section Creating Compute Allocations
|
|
18
|
+
* @example Team Quota with Borrowing
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import * as AWS from "alchemy/AWS";
|
|
21
|
+
*
|
|
22
|
+
* const quota = yield* AWS.SageMaker.ComputeQuota("ResearchQuota", {
|
|
23
|
+
* clusterArn: hyperpod.clusterArn,
|
|
24
|
+
* computeQuotaTarget: { TeamName: "research", FairShareWeight: 10 },
|
|
25
|
+
* computeQuotaConfig: {
|
|
26
|
+
* ComputeQuotaResources: [{ InstanceType: "ml.g5.xlarge", Count: 2 }],
|
|
27
|
+
* ResourceSharingConfig: { Strategy: "Lend", BorrowLimit: 50 },
|
|
28
|
+
* },
|
|
29
|
+
* });
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export const ComputeQuota = Resource("AWS.SageMaker.ComputeQuota");
|
|
33
|
+
const createQuotaName = (id, props) => props.name
|
|
34
|
+
? Effect.succeed(props.name)
|
|
35
|
+
: createPhysicalName({ id, maxLength: 63 });
|
|
36
|
+
const describeQuotaOrUndefined = (quotaId) => sagemaker
|
|
37
|
+
.describeComputeQuota({ ComputeQuotaId: quotaId })
|
|
38
|
+
.pipe(Effect.catchTag("ResourceNotFound", () => Effect.succeed(undefined)));
|
|
39
|
+
/**
|
|
40
|
+
* Look a compute allocation up by exact name — used when state was lost
|
|
41
|
+
* (read without output) or a create raced.
|
|
42
|
+
*/
|
|
43
|
+
const findQuotaByName = Effect.fn(function* (name) {
|
|
44
|
+
const summaries = yield* sagemaker.listComputeQuotas
|
|
45
|
+
.pages({ NameContains: name })
|
|
46
|
+
.pipe(EffectStream.runCollect, Effect.map((chunk) => Array.from(chunk).flatMap((page) => page.ComputeQuotaSummaries ?? [])));
|
|
47
|
+
return summaries.find((s) => s.Name === name && s.Status !== "Deleted");
|
|
48
|
+
});
|
|
49
|
+
const fetchQuotaTags = Effect.fn(function* (arn) {
|
|
50
|
+
const response = yield* sagemaker
|
|
51
|
+
.listTags({ ResourceArn: arn })
|
|
52
|
+
.pipe(Effect.catchTag("AccessDeniedException", () => Effect.succeed(undefined)));
|
|
53
|
+
return Object.fromEntries((response?.Tags ?? []).flatMap((tag) => tag.Key !== undefined ? [[tag.Key, tag.Value ?? ""]] : []));
|
|
54
|
+
});
|
|
55
|
+
const toAttrs = (described) => ({
|
|
56
|
+
computeQuotaId: described.ComputeQuotaId,
|
|
57
|
+
computeQuotaArn: described.ComputeQuotaArn,
|
|
58
|
+
name: described.Name,
|
|
59
|
+
clusterArn: described.ClusterArn ?? "",
|
|
60
|
+
computeQuotaVersion: described.ComputeQuotaVersion,
|
|
61
|
+
teamName: described.ComputeQuotaTarget?.TeamName ?? "",
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* The compute allocation is still transitioning toward the awaited state —
|
|
65
|
+
* retried by the bounded wait schedule.
|
|
66
|
+
*/
|
|
67
|
+
class ComputeQuotaNotReady extends Data.TaggedError("ComputeQuotaNotReady") {
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The compute allocation converged to a terminal failed status.
|
|
71
|
+
*/
|
|
72
|
+
export class ComputeQuotaFailed extends Data.TaggedError("ComputeQuotaFailed") {
|
|
73
|
+
}
|
|
74
|
+
const FAILED_STATUSES = [
|
|
75
|
+
"CreateFailed",
|
|
76
|
+
"CreateRollbackFailed",
|
|
77
|
+
"UpdateFailed",
|
|
78
|
+
"UpdateRollbackFailed",
|
|
79
|
+
"DeleteFailed",
|
|
80
|
+
"DeleteRollbackFailed",
|
|
81
|
+
];
|
|
82
|
+
// Explicitly-typed retry wrapper — an inline `Effect.retry` in provider
|
|
83
|
+
// lifecycle code leaks `Retry.Return`'s conditional type into declaration
|
|
84
|
+
// emit and widens the provider layer to `unknown` for every consumer of
|
|
85
|
+
// `AWS.providers()`.
|
|
86
|
+
const retryWhileNotReady = (self) => Effect.retry(self, {
|
|
87
|
+
while: (e) => e._tag === "ComputeQuotaNotReady",
|
|
88
|
+
schedule: Schedule.max([Schedule.spaced("5 seconds"), Schedule.recurs(60)]),
|
|
89
|
+
});
|
|
90
|
+
const waitForQuota = (quotaId, target) => retryWhileNotReady(Effect.gen(function* () {
|
|
91
|
+
const described = yield* describeQuotaOrUndefined(quotaId);
|
|
92
|
+
if (target === "Gone") {
|
|
93
|
+
if (described === undefined || described.Status === "Deleted")
|
|
94
|
+
return;
|
|
95
|
+
if (FAILED_STATUSES.includes(described.Status)) {
|
|
96
|
+
return yield* Effect.fail(new ComputeQuotaFailed({
|
|
97
|
+
quotaId,
|
|
98
|
+
status: described.Status,
|
|
99
|
+
message: described.FailureReason,
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
return yield* Effect.fail(new ComputeQuotaNotReady({ quotaId, status: described.Status }));
|
|
103
|
+
}
|
|
104
|
+
if (described?.Status === "Created" || described?.Status === "Updated") {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (described !== undefined &&
|
|
108
|
+
FAILED_STATUSES.includes(described.Status)) {
|
|
109
|
+
return yield* Effect.fail(new ComputeQuotaFailed({
|
|
110
|
+
quotaId,
|
|
111
|
+
status: described.Status,
|
|
112
|
+
message: described.FailureReason,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
return yield* Effect.fail(new ComputeQuotaNotReady({ quotaId, status: described?.Status }));
|
|
116
|
+
}));
|
|
117
|
+
export const ComputeQuotaProvider = () => Provider.effect(ComputeQuota, Effect.gen(function* () {
|
|
118
|
+
return {
|
|
119
|
+
stables: ["computeQuotaId", "computeQuotaArn", "name", "clusterArn"],
|
|
120
|
+
list: () => Effect.gen(function* () {
|
|
121
|
+
const summaries = yield* sagemaker.listComputeQuotas.pages({}).pipe(EffectStream.runCollect, Effect.map((chunk) => Array.from(chunk).flatMap((page) => page.ComputeQuotaSummaries ?? [])));
|
|
122
|
+
return summaries.flatMap((s) => s.ComputeQuotaId !== undefined && s.Status !== "Deleted"
|
|
123
|
+
? [
|
|
124
|
+
{
|
|
125
|
+
computeQuotaId: s.ComputeQuotaId,
|
|
126
|
+
computeQuotaArn: s.ComputeQuotaArn ?? "",
|
|
127
|
+
name: s.Name ?? "",
|
|
128
|
+
clusterArn: s.ClusterArn ?? "",
|
|
129
|
+
computeQuotaVersion: s.ComputeQuotaVersion ?? 1,
|
|
130
|
+
teamName: s.ComputeQuotaTarget?.TeamName ?? "",
|
|
131
|
+
},
|
|
132
|
+
]
|
|
133
|
+
: []);
|
|
134
|
+
}),
|
|
135
|
+
read: Effect.fn(function* ({ id, olds, output }) {
|
|
136
|
+
const quotaId = output?.computeQuotaId ??
|
|
137
|
+
(yield* findQuotaByName(yield* createQuotaName(id, olds ?? {})))
|
|
138
|
+
?.ComputeQuotaId;
|
|
139
|
+
if (quotaId === undefined)
|
|
140
|
+
return undefined;
|
|
141
|
+
const described = yield* describeQuotaOrUndefined(quotaId);
|
|
142
|
+
if (!described ||
|
|
143
|
+
described.Status === "Deleting" ||
|
|
144
|
+
described.Status === "Deleted") {
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
const attrs = toAttrs(described);
|
|
148
|
+
const tags = yield* fetchQuotaTags(attrs.computeQuotaArn);
|
|
149
|
+
return (yield* hasAlchemyTags(id, tags))
|
|
150
|
+
? attrs
|
|
151
|
+
: Unowned(attrs);
|
|
152
|
+
}),
|
|
153
|
+
diff: Effect.fn(function* ({ id, news, olds }) {
|
|
154
|
+
if (!isResolved(news))
|
|
155
|
+
return;
|
|
156
|
+
if (olds === undefined)
|
|
157
|
+
return;
|
|
158
|
+
const oldName = yield* createQuotaName(id, olds);
|
|
159
|
+
const newName = yield* createQuotaName(id, news);
|
|
160
|
+
// The name and target cluster are fixed at creation.
|
|
161
|
+
if (oldName !== newName || olds.clusterArn !== news.clusterArn) {
|
|
162
|
+
return { action: "replace" };
|
|
163
|
+
}
|
|
164
|
+
}),
|
|
165
|
+
reconcile: Effect.fn(function* ({ id, news, output, session }) {
|
|
166
|
+
if (!news) {
|
|
167
|
+
return yield* Effect.fail(new Error("SageMaker ComputeQuota requires props"));
|
|
168
|
+
}
|
|
169
|
+
const name = yield* createQuotaName(id, news);
|
|
170
|
+
const internalTags = yield* createInternalTags(id);
|
|
171
|
+
const desiredTags = { ...internalTags, ...news.tags };
|
|
172
|
+
// Observe — by cached id first, then by name (lost state or race).
|
|
173
|
+
let quotaId = output?.computeQuotaId;
|
|
174
|
+
let described = quotaId !== undefined
|
|
175
|
+
? yield* describeQuotaOrUndefined(quotaId)
|
|
176
|
+
: undefined;
|
|
177
|
+
if (described === undefined) {
|
|
178
|
+
const found = yield* findQuotaByName(name);
|
|
179
|
+
described =
|
|
180
|
+
found?.ComputeQuotaId !== undefined
|
|
181
|
+
? yield* describeQuotaOrUndefined(found.ComputeQuotaId)
|
|
182
|
+
: undefined;
|
|
183
|
+
}
|
|
184
|
+
// Ensure — create if missing; a Conflict means a concurrent
|
|
185
|
+
// create won the race, so re-observe by name.
|
|
186
|
+
if (described === undefined) {
|
|
187
|
+
const created = yield* sagemaker
|
|
188
|
+
.createComputeQuota({
|
|
189
|
+
Name: name,
|
|
190
|
+
ClusterArn: news.clusterArn,
|
|
191
|
+
ComputeQuotaConfig: news.computeQuotaConfig,
|
|
192
|
+
ComputeQuotaTarget: news.computeQuotaTarget,
|
|
193
|
+
ActivationState: news.activationState,
|
|
194
|
+
Description: news.description,
|
|
195
|
+
Tags: Object.entries(desiredTags).map(([Key, Value]) => ({
|
|
196
|
+
Key,
|
|
197
|
+
Value,
|
|
198
|
+
})),
|
|
199
|
+
})
|
|
200
|
+
.pipe(Effect.catchTag("ConflictException", () => Effect.succeed(undefined)));
|
|
201
|
+
quotaId =
|
|
202
|
+
created?.ComputeQuotaId ??
|
|
203
|
+
(yield* findQuotaByName(name))?.ComputeQuotaId;
|
|
204
|
+
if (quotaId === undefined) {
|
|
205
|
+
return yield* Effect.fail(new Error(`failed to create compute quota ${name}`));
|
|
206
|
+
}
|
|
207
|
+
yield* session.note(`Creating compute quota ${name}...`);
|
|
208
|
+
yield* waitForQuota(quotaId, "Ready");
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
quotaId = described.ComputeQuotaId;
|
|
212
|
+
// Wait out any in-flight transition before diffing.
|
|
213
|
+
yield* waitForQuota(quotaId, "Ready");
|
|
214
|
+
described = yield* describeQuotaOrUndefined(quotaId);
|
|
215
|
+
// Sync — diff observed allocation against desired.
|
|
216
|
+
if (described !== undefined &&
|
|
217
|
+
(JSON.stringify(described.ComputeQuotaConfig) !==
|
|
218
|
+
JSON.stringify(news.computeQuotaConfig) ||
|
|
219
|
+
JSON.stringify(described.ComputeQuotaTarget) !==
|
|
220
|
+
JSON.stringify(news.computeQuotaTarget) ||
|
|
221
|
+
(news.activationState !== undefined &&
|
|
222
|
+
described.ActivationState !== news.activationState) ||
|
|
223
|
+
(described.Description ?? undefined) !==
|
|
224
|
+
(news.description ?? undefined))) {
|
|
225
|
+
yield* sagemaker.updateComputeQuota({
|
|
226
|
+
ComputeQuotaId: quotaId,
|
|
227
|
+
TargetVersion: described.ComputeQuotaVersion,
|
|
228
|
+
ComputeQuotaConfig: news.computeQuotaConfig,
|
|
229
|
+
ComputeQuotaTarget: news.computeQuotaTarget,
|
|
230
|
+
ActivationState: news.activationState,
|
|
231
|
+
Description: news.description,
|
|
232
|
+
});
|
|
233
|
+
yield* session.note(`Updating compute quota ${name}...`);
|
|
234
|
+
yield* waitForQuota(quotaId, "Ready");
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
described = yield* describeQuotaOrUndefined(quotaId);
|
|
238
|
+
if (described === undefined) {
|
|
239
|
+
return yield* Effect.fail(new Error(`failed to read reconciled compute quota ${name}`));
|
|
240
|
+
}
|
|
241
|
+
const attrs = toAttrs(described);
|
|
242
|
+
// Sync tags — diff against OBSERVED cloud tags.
|
|
243
|
+
const currentTags = yield* fetchQuotaTags(attrs.computeQuotaArn);
|
|
244
|
+
const { removed, upsert } = diffTags(currentTags, desiredTags);
|
|
245
|
+
if (removed.length > 0) {
|
|
246
|
+
yield* sagemaker.deleteTags({
|
|
247
|
+
ResourceArn: attrs.computeQuotaArn,
|
|
248
|
+
TagKeys: removed,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
if (upsert.length > 0) {
|
|
252
|
+
yield* sagemaker.addTags({
|
|
253
|
+
ResourceArn: attrs.computeQuotaArn,
|
|
254
|
+
Tags: upsert.map(({ Key, Value }) => ({ Key, Value })),
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
yield* session.note(attrs.computeQuotaArn);
|
|
258
|
+
return attrs;
|
|
259
|
+
}),
|
|
260
|
+
delete: Effect.fn(function* ({ output }) {
|
|
261
|
+
yield* sagemaker
|
|
262
|
+
.deleteComputeQuota({ ComputeQuotaId: output.computeQuotaId })
|
|
263
|
+
.pipe(Effect.catchTag("ResourceNotFound", () => Effect.void));
|
|
264
|
+
yield* waitForQuota(output.computeQuotaId, "Gone");
|
|
265
|
+
}),
|
|
266
|
+
};
|
|
267
|
+
}));
|
|
268
|
+
//# sourceMappingURL=ComputeQuota.js.map
|