@highstate/backend 0.7.2 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index.mjs → index.js} +1254 -915
- package/dist/library/source-resolution-worker.js +55 -0
- package/dist/library/worker/main.js +207 -0
- package/dist/{terminal-CqIsctlZ.mjs → library-BW5oPM7V.js} +210 -87
- package/dist/shared/index.js +6 -0
- package/dist/utils-ByadNcv4.js +102 -0
- package/package.json +14 -18
- package/src/common/index.ts +3 -0
- package/src/common/local.ts +22 -0
- package/src/common/pulumi.ts +230 -0
- package/src/common/utils.ts +137 -0
- package/src/config.ts +40 -0
- package/src/index.ts +6 -0
- package/src/library/abstractions.ts +83 -0
- package/src/library/factory.ts +20 -0
- package/src/library/index.ts +2 -0
- package/src/library/local.ts +404 -0
- package/src/library/source-resolution-worker.ts +96 -0
- package/src/library/worker/evaluator.ts +119 -0
- package/src/library/worker/loader.ts +93 -0
- package/src/library/worker/main.ts +82 -0
- package/src/library/worker/protocol.ts +38 -0
- package/src/orchestrator/index.ts +1 -0
- package/src/orchestrator/manager.ts +165 -0
- package/src/orchestrator/operation-workset.ts +483 -0
- package/src/orchestrator/operation.ts +647 -0
- package/src/preferences/shared.ts +1 -0
- package/src/project/abstractions.ts +89 -0
- package/src/project/factory.ts +11 -0
- package/src/project/index.ts +4 -0
- package/src/project/local.ts +412 -0
- package/src/project/lock.ts +39 -0
- package/src/project/manager.ts +374 -0
- package/src/runner/abstractions.ts +146 -0
- package/src/runner/factory.ts +22 -0
- package/src/runner/index.ts +2 -0
- package/src/runner/local.ts +698 -0
- package/src/secret/abstractions.ts +59 -0
- package/src/secret/factory.ts +22 -0
- package/src/secret/index.ts +2 -0
- package/src/secret/local.ts +152 -0
- package/src/services.ts +133 -0
- package/src/shared/index.ts +10 -0
- package/src/shared/library.ts +77 -0
- package/src/shared/operation.ts +85 -0
- package/src/shared/project.ts +62 -0
- package/src/shared/resolvers/graph-resolver.ts +111 -0
- package/src/shared/resolvers/input-hash.ts +77 -0
- package/src/shared/resolvers/input.ts +314 -0
- package/src/shared/resolvers/registry.ts +10 -0
- package/src/shared/resolvers/validation.ts +94 -0
- package/src/shared/state.ts +262 -0
- package/src/shared/terminal.ts +13 -0
- package/src/state/abstractions.ts +222 -0
- package/src/state/factory.ts +22 -0
- package/src/state/index.ts +3 -0
- package/src/state/local.ts +605 -0
- package/src/state/manager.ts +33 -0
- package/src/terminal/docker.ts +90 -0
- package/src/terminal/factory.ts +20 -0
- package/src/terminal/index.ts +3 -0
- package/src/terminal/manager.ts +330 -0
- package/src/terminal/run.sh.ts +37 -0
- package/src/terminal/shared.ts +50 -0
- package/src/workspace/abstractions.ts +41 -0
- package/src/workspace/factory.ts +14 -0
- package/src/workspace/index.ts +2 -0
- package/src/workspace/local.ts +54 -0
- package/dist/index.d.ts +0 -760
- package/dist/library/worker/main.mjs +0 -164
- package/dist/runner/source-resolution-worker.mjs +0 -22
- package/dist/shared/index.d.ts +0 -85
- package/dist/shared/index.mjs +0 -54
- package/dist/terminal-Cm2WqcyB.d.ts +0 -1589
@@ -0,0 +1,374 @@
|
|
1
|
+
import type { StateBackend, StateManager } from "../state"
|
2
|
+
import type { ProjectBackend } from "./abstractions"
|
3
|
+
import type { Logger } from "pino"
|
4
|
+
import type { LibraryBackend } from "../library"
|
5
|
+
import type { ProjectLockManager } from "./lock"
|
6
|
+
import { EventEmitter, on } from "node:events"
|
7
|
+
import { isUnitModel, type InstanceModel } from "@highstate/contract"
|
8
|
+
import {
|
9
|
+
createInputResolver,
|
10
|
+
createInputHashResolver,
|
11
|
+
type InputResolverInput,
|
12
|
+
type InputHashResolverInput,
|
13
|
+
type InstanceModelPatch,
|
14
|
+
type LibraryUpdate,
|
15
|
+
createInstanceState,
|
16
|
+
type CompositeInstance,
|
17
|
+
type ResolvedInstanceInput,
|
18
|
+
} from "../shared"
|
19
|
+
|
20
|
+
type CompositeInstanceEvent =
|
21
|
+
| {
|
22
|
+
type: "updated"
|
23
|
+
instance: CompositeInstance
|
24
|
+
}
|
25
|
+
| {
|
26
|
+
type: "deleted"
|
27
|
+
instanceId: string
|
28
|
+
}
|
29
|
+
|
30
|
+
type CompositeInstanceEvents = {
|
31
|
+
[K in string]: [CompositeInstanceEvent]
|
32
|
+
}
|
33
|
+
|
34
|
+
export class ProjectManager {
|
35
|
+
private constructor(
|
36
|
+
private readonly projectBackend: ProjectBackend,
|
37
|
+
private readonly stateBackend: StateBackend,
|
38
|
+
private readonly libraryBackend: LibraryBackend,
|
39
|
+
private readonly projectLockManager: ProjectLockManager,
|
40
|
+
private readonly stateManager: StateManager,
|
41
|
+
private readonly logger: Logger,
|
42
|
+
) {
|
43
|
+
void this.watchLibraryChanges()
|
44
|
+
}
|
45
|
+
|
46
|
+
private readonly compositeInstanceEE = new EventEmitter<CompositeInstanceEvents>()
|
47
|
+
|
48
|
+
async *watchCompositeInstances(
|
49
|
+
projectId: string,
|
50
|
+
signal?: AbortSignal,
|
51
|
+
): AsyncIterable<CompositeInstanceEvent> {
|
52
|
+
for await (const [children] of on(this.compositeInstanceEE, projectId, {
|
53
|
+
signal,
|
54
|
+
})) {
|
55
|
+
yield children
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
async createInstance(projectId: string, instance: InstanceModel): Promise<InstanceModel> {
|
60
|
+
const createdInstance = await this.projectBackend.createInstance(projectId, instance)
|
61
|
+
await this.updateCompositeInstance(projectId, createdInstance)
|
62
|
+
|
63
|
+
return createdInstance
|
64
|
+
}
|
65
|
+
|
66
|
+
async updateInstance(
|
67
|
+
projectId: string,
|
68
|
+
instanceId: string,
|
69
|
+
patch: InstanceModelPatch,
|
70
|
+
): Promise<InstanceModel> {
|
71
|
+
const instance = await this.projectBackend.updateInstance(projectId, instanceId, patch)
|
72
|
+
await this.updateCompositeInstance(projectId, instance)
|
73
|
+
|
74
|
+
return instance
|
75
|
+
}
|
76
|
+
|
77
|
+
async renameInstance(
|
78
|
+
projectId: string,
|
79
|
+
instanceId: string,
|
80
|
+
newName: string,
|
81
|
+
): Promise<InstanceModel> {
|
82
|
+
const instance = await this.projectBackend.renameInstance(projectId, instanceId, newName)
|
83
|
+
await this.updateCompositeInstance(projectId, instance)
|
84
|
+
|
85
|
+
return instance
|
86
|
+
}
|
87
|
+
|
88
|
+
async deleteInstance(projectId: string, instanceId: string): Promise<void> {
|
89
|
+
await Promise.all([
|
90
|
+
this.projectBackend.deleteInstance(projectId, instanceId),
|
91
|
+
this.stateBackend.clearCompositeInstances(projectId, [instanceId]),
|
92
|
+
])
|
93
|
+
}
|
94
|
+
|
95
|
+
private async updateCompositeInstance(projectId: string, instance: InstanceModel): Promise<void> {
|
96
|
+
const { resolveInputHash, library } = await this.prepareInputHashResolver(projectId)
|
97
|
+
|
98
|
+
const component = library.components[instance.type]
|
99
|
+
if (!component) {
|
100
|
+
return
|
101
|
+
}
|
102
|
+
|
103
|
+
if (isUnitModel(component)) {
|
104
|
+
return
|
105
|
+
}
|
106
|
+
|
107
|
+
const { inputHash: expectedInputHash } = await resolveInputHash(instance.id)
|
108
|
+
const inputHash = await this.stateBackend.getCompositeInstanceInputHash(projectId, instance.id)
|
109
|
+
|
110
|
+
if (inputHash !== expectedInputHash) {
|
111
|
+
this.logger.info("re-evaluating instance since input hash has changed", {
|
112
|
+
projectId,
|
113
|
+
instanceId: instance.id,
|
114
|
+
})
|
115
|
+
|
116
|
+
await this.evaluateCompositeInstances(projectId, [instance.id])
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
private async evaluateCompositeInstances(projectId: string, instanceIds: string[]) {
|
121
|
+
await this.projectLockManager.getLock(projectId).lockInstances(instanceIds, async () => {
|
122
|
+
const [
|
123
|
+
{ instances, resolvedInputs, stateMap, resolveInputHash },
|
124
|
+
topLevelCompositeChildrenIds,
|
125
|
+
] = await Promise.all([
|
126
|
+
this.prepareInputHashResolver(projectId),
|
127
|
+
this.stateBackend.getTopLevelCompositeChildrenIds(projectId, instanceIds),
|
128
|
+
])
|
129
|
+
|
130
|
+
const results = await this.libraryBackend.evaluateCompositeInstances(
|
131
|
+
instances,
|
132
|
+
resolvedInputs,
|
133
|
+
instanceIds,
|
134
|
+
)
|
135
|
+
|
136
|
+
const newStates = results.map(result => {
|
137
|
+
const existingState = stateMap.get(result.instanceId)
|
138
|
+
const newState = existingState ?? createInstanceState(result.instanceId)
|
139
|
+
|
140
|
+
newState.evaluationError = result.success ? null : result.error
|
141
|
+
|
142
|
+
return newState
|
143
|
+
})
|
144
|
+
|
145
|
+
const inputHashes = new Map<string, string>()
|
146
|
+
for (const instanceId of instanceIds) {
|
147
|
+
const { inputHash } = await resolveInputHash(instanceId)
|
148
|
+
inputHashes.set(instanceId, inputHash)
|
149
|
+
}
|
150
|
+
|
151
|
+
const compositeInstances = results
|
152
|
+
.filter(result => result.success)
|
153
|
+
.flatMap(result =>
|
154
|
+
result.compositeInstances.map(instance => ({
|
155
|
+
...instance,
|
156
|
+
inputHash: inputHashes.get(instance.instance.id),
|
157
|
+
})),
|
158
|
+
)
|
159
|
+
|
160
|
+
const newTopLevelCompositeChildrenIds = Object.fromEntries(
|
161
|
+
results
|
162
|
+
.filter(result => result.success)
|
163
|
+
.map(result => [
|
164
|
+
result.instanceId,
|
165
|
+
result.compositeInstances
|
166
|
+
.filter(instance => instance.instance.id !== result.instanceId)
|
167
|
+
.map(instance => instance.instance.id),
|
168
|
+
]),
|
169
|
+
)
|
170
|
+
|
171
|
+
const deletedCompositeInstanceIds = new Set(
|
172
|
+
Object.values(topLevelCompositeChildrenIds).flat(),
|
173
|
+
)
|
174
|
+
|
175
|
+
for (const childInstanceId of Object.values(newTopLevelCompositeChildrenIds).flat()) {
|
176
|
+
deletedCompositeInstanceIds.delete(childInstanceId)
|
177
|
+
}
|
178
|
+
|
179
|
+
await Promise.all([
|
180
|
+
this.stateBackend.clearCompositeInstances(
|
181
|
+
projectId,
|
182
|
+
Array.from(deletedCompositeInstanceIds),
|
183
|
+
),
|
184
|
+
this.stateBackend.putTopLevelCompositeChildrenIds(
|
185
|
+
projectId,
|
186
|
+
newTopLevelCompositeChildrenIds,
|
187
|
+
),
|
188
|
+
])
|
189
|
+
|
190
|
+
for (const state of newStates) {
|
191
|
+
this.stateManager.emitStatePatch(projectId, state)
|
192
|
+
}
|
193
|
+
|
194
|
+
for (const instance of compositeInstances) {
|
195
|
+
this.compositeInstanceEE.emit(projectId, { type: "updated", instance })
|
196
|
+
}
|
197
|
+
|
198
|
+
for (const instanceId of deletedCompositeInstanceIds) {
|
199
|
+
this.compositeInstanceEE.emit(projectId, { type: "deleted", instanceId })
|
200
|
+
}
|
201
|
+
|
202
|
+
const promises: Promise<void>[] = []
|
203
|
+
|
204
|
+
if (newStates.length > 0) {
|
205
|
+
promises.push(this.stateBackend.putInstanceStates(projectId, newStates))
|
206
|
+
}
|
207
|
+
|
208
|
+
if (compositeInstances.length > 0) {
|
209
|
+
promises.push(this.stateBackend.putCompositeInstances(projectId, compositeInstances))
|
210
|
+
}
|
211
|
+
|
212
|
+
this.logger.info(
|
213
|
+
{ projectId },
|
214
|
+
"instance evaluation completed, %d instances persisted",
|
215
|
+
compositeInstances.length,
|
216
|
+
)
|
217
|
+
|
218
|
+
await Promise.all(promises)
|
219
|
+
})
|
220
|
+
}
|
221
|
+
|
222
|
+
private async prepareInputHashResolver(projectId: string) {
|
223
|
+
const { instances, hubs } = await this.projectBackend.getProject(projectId)
|
224
|
+
|
225
|
+
const library = await this.libraryBackend.loadLibrary()
|
226
|
+
const filteredInstances = instances.filter(instance => instance.type in library.components)
|
227
|
+
|
228
|
+
const states = await this.stateBackend.getAllInstanceStates(projectId)
|
229
|
+
const stateMap = new Map(states.map(state => [state.id, state]))
|
230
|
+
|
231
|
+
const inputResolverNodes = new Map<string, InputResolverInput>()
|
232
|
+
|
233
|
+
for (const instance of filteredInstances) {
|
234
|
+
inputResolverNodes.set(`instance:${instance.id}`, {
|
235
|
+
kind: "instance",
|
236
|
+
instance,
|
237
|
+
component: library.components[instance.type],
|
238
|
+
})
|
239
|
+
}
|
240
|
+
|
241
|
+
for (const hub of hubs) {
|
242
|
+
inputResolverNodes.set(`hub:${hub.id}`, { kind: "hub", hub })
|
243
|
+
}
|
244
|
+
|
245
|
+
const resolveInputs = createInputResolver(inputResolverNodes, this.logger)
|
246
|
+
|
247
|
+
const inputHashInputs = new Map<string, InputHashResolverInput>()
|
248
|
+
const resolvedInputs: Record<string, Record<string, ResolvedInstanceInput[]>> = {}
|
249
|
+
|
250
|
+
for (const instance of filteredInstances) {
|
251
|
+
const output = await resolveInputs(`instance:${instance.id}`)
|
252
|
+
if (output.kind !== "instance") {
|
253
|
+
throw new Error("Expected instance node")
|
254
|
+
}
|
255
|
+
|
256
|
+
let sourceHash: string | undefined
|
257
|
+
if (isUnitModel(library.components[instance.type])) {
|
258
|
+
const resolvedUnit = await this.libraryBackend.getResolvedUnitSource(instance.type)
|
259
|
+
if (!resolvedUnit) {
|
260
|
+
throw new Error(`Resolved unit not found: ${instance.type}`)
|
261
|
+
}
|
262
|
+
|
263
|
+
sourceHash = resolvedUnit.sourceHash
|
264
|
+
}
|
265
|
+
|
266
|
+
inputHashInputs.set(instance.id, {
|
267
|
+
instance,
|
268
|
+
component: library.components[instance.type],
|
269
|
+
resolvedInputs: output.resolvedInputs,
|
270
|
+
state: stateMap.get(instance.id),
|
271
|
+
sourceHash,
|
272
|
+
})
|
273
|
+
|
274
|
+
resolvedInputs[instance.id] = output.resolvedInputs
|
275
|
+
}
|
276
|
+
|
277
|
+
const resolveInputHash = createInputHashResolver(inputHashInputs, this.logger)
|
278
|
+
|
279
|
+
return {
|
280
|
+
resolveInputHash,
|
281
|
+
library,
|
282
|
+
instances,
|
283
|
+
stateMap,
|
284
|
+
resolvedInputs,
|
285
|
+
}
|
286
|
+
}
|
287
|
+
|
288
|
+
private async watchLibraryChanges(): Promise<void> {
|
289
|
+
for await (const updates of this.libraryBackend.watchLibrary()) {
|
290
|
+
try {
|
291
|
+
await this.handleLibraryUpdates(updates)
|
292
|
+
} catch (error) {
|
293
|
+
this.logger.error({ error }, "failed to handle library updates")
|
294
|
+
}
|
295
|
+
}
|
296
|
+
}
|
297
|
+
|
298
|
+
private async handleLibraryUpdates(updates: LibraryUpdate[]): Promise<void> {
|
299
|
+
const changedComponents = new Set<string>()
|
300
|
+
const library = await this.libraryBackend.loadLibrary()
|
301
|
+
|
302
|
+
// TODO: handle entity updates
|
303
|
+
|
304
|
+
for (const update of updates) {
|
305
|
+
switch (update.type) {
|
306
|
+
case "component-updated":
|
307
|
+
changedComponents.add(update.component.type)
|
308
|
+
break
|
309
|
+
case "component-removed":
|
310
|
+
changedComponents.add(update.componentType)
|
311
|
+
break
|
312
|
+
}
|
313
|
+
}
|
314
|
+
|
315
|
+
if (changedComponents.size === 0) {
|
316
|
+
return
|
317
|
+
}
|
318
|
+
|
319
|
+
this.logger.info(
|
320
|
+
{ changedComponents },
|
321
|
+
"library components changed, updating composite instances",
|
322
|
+
)
|
323
|
+
|
324
|
+
const projects = await this.projectBackend.getProjectIds()
|
325
|
+
for (const projectId of projects) {
|
326
|
+
const { resolveInputHash, instances } = await this.prepareInputHashResolver(projectId)
|
327
|
+
|
328
|
+
const filteredInstances = instances.filter(
|
329
|
+
instance =>
|
330
|
+
changedComponents.has(instance.type) &&
|
331
|
+
library.components[instance.type] &&
|
332
|
+
!isUnitModel(library.components[instance.type]),
|
333
|
+
)
|
334
|
+
|
335
|
+
this.logger.info(
|
336
|
+
{ projectId, filteredInstanceIds: filteredInstances.map(instance => instance.id) },
|
337
|
+
"updating composite instances for project",
|
338
|
+
)
|
339
|
+
|
340
|
+
const inputHashMap = new Map<string, string>()
|
341
|
+
for (const instance of filteredInstances) {
|
342
|
+
const { inputHash } = await resolveInputHash(instance.id)
|
343
|
+
inputHashMap.set(instance.id, inputHash)
|
344
|
+
}
|
345
|
+
|
346
|
+
try {
|
347
|
+
await this.evaluateCompositeInstances(
|
348
|
+
projectId,
|
349
|
+
filteredInstances.map(instance => instance.id),
|
350
|
+
)
|
351
|
+
} catch (error) {
|
352
|
+
this.logger.error({ error }, "failed to evaluate composite instances")
|
353
|
+
}
|
354
|
+
}
|
355
|
+
}
|
356
|
+
|
357
|
+
static create(
|
358
|
+
projectBackend: ProjectBackend,
|
359
|
+
stateBackend: StateBackend,
|
360
|
+
libraryBackend: LibraryBackend,
|
361
|
+
projectLockManager: ProjectLockManager,
|
362
|
+
stateManager: StateManager,
|
363
|
+
logger: Logger,
|
364
|
+
): ProjectManager {
|
365
|
+
return new ProjectManager(
|
366
|
+
projectBackend,
|
367
|
+
stateBackend,
|
368
|
+
libraryBackend,
|
369
|
+
projectLockManager,
|
370
|
+
stateManager,
|
371
|
+
logger.child({ service: "ProjectManager" }),
|
372
|
+
)
|
373
|
+
}
|
374
|
+
}
|
@@ -0,0 +1,146 @@
|
|
1
|
+
import type {
|
2
|
+
InstancePageBlock,
|
3
|
+
InstanceState,
|
4
|
+
InstanceStateUpdate,
|
5
|
+
InstanceStatus,
|
6
|
+
InstanceTerminal,
|
7
|
+
} from "../shared"
|
8
|
+
|
9
|
+
export type RunnerBaseOptions = {
|
10
|
+
/**
|
11
|
+
* The HighState project ID.
|
12
|
+
*/
|
13
|
+
projectId: string
|
14
|
+
|
15
|
+
/**
|
16
|
+
* The type of the instance to run.
|
17
|
+
*/
|
18
|
+
instanceType: string
|
19
|
+
|
20
|
+
/**
|
21
|
+
* The name of the instance to run.
|
22
|
+
*/
|
23
|
+
instanceName: string
|
24
|
+
|
25
|
+
/**
|
26
|
+
* The signal to abort the operation.
|
27
|
+
*/
|
28
|
+
signal?: AbortSignal
|
29
|
+
}
|
30
|
+
|
31
|
+
export type InstanceUpdateOptions = RunnerBaseOptions & {
|
32
|
+
/**
|
33
|
+
* The configuration of the stack.
|
34
|
+
*/
|
35
|
+
config: Record<string, string>
|
36
|
+
|
37
|
+
/**
|
38
|
+
* The values of the secrets.
|
39
|
+
*/
|
40
|
+
secrets: Record<string, string>
|
41
|
+
|
42
|
+
/**
|
43
|
+
* Whether to refresh the state before updating.
|
44
|
+
*/
|
45
|
+
refresh?: boolean
|
46
|
+
}
|
47
|
+
|
48
|
+
export type InstanceDestroyOptions = RunnerBaseOptions & {
|
49
|
+
/**
|
50
|
+
* Whether to refresh the state before updating.
|
51
|
+
*/
|
52
|
+
refresh?: boolean
|
53
|
+
|
54
|
+
/**
|
55
|
+
* Whether to delete the unreachable resources (e.g. k8s resources in unreachable clusters).
|
56
|
+
*/
|
57
|
+
deleteUnreachable?: boolean
|
58
|
+
}
|
59
|
+
|
60
|
+
export type InstanceWatchOptions = RunnerBaseOptions & {
|
61
|
+
/**
|
62
|
+
* The final statuses to watch.
|
63
|
+
* If the instance reaches one of these statuses, it should return the current state and exit.
|
64
|
+
*/
|
65
|
+
finalStatuses?: InstanceStatus[]
|
66
|
+
}
|
67
|
+
|
68
|
+
export class InvalidInstanceStatusError extends Error {
|
69
|
+
constructor(
|
70
|
+
public readonly currentStatus: InstanceStatus,
|
71
|
+
public readonly expectedStatuses: InstanceStatus[],
|
72
|
+
) {
|
73
|
+
const expectedString = expectedStatuses.join(", ")
|
74
|
+
super(`The current state is "${currentStatus}", but it should be one of "${expectedString}".`)
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
export interface RunnerBackend {
|
79
|
+
/**
|
80
|
+
* Watches the instance state.
|
81
|
+
*
|
82
|
+
* Returns the async iterable of the instance state patches.
|
83
|
+
* The fields with `undefined` values should be ignored, and the fields with `null` values should be removed.
|
84
|
+
*/
|
85
|
+
watch(options: InstanceWatchOptions): AsyncIterable<InstanceStateUpdate>
|
86
|
+
|
87
|
+
/**
|
88
|
+
* Gets the actual state of the instance.
|
89
|
+
*/
|
90
|
+
getState(options: RunnerBaseOptions): Promise<InstanceState>
|
91
|
+
|
92
|
+
/**
|
93
|
+
* Gets the content of the page.
|
94
|
+
*/
|
95
|
+
getPageContent(options: RunnerBaseOptions, pageName: string): Promise<InstancePageBlock[] | null>
|
96
|
+
|
97
|
+
/**
|
98
|
+
* Gets the content of the file.
|
99
|
+
*/
|
100
|
+
getFileContent(options: RunnerBaseOptions, fileName: string): Promise<string | null>
|
101
|
+
|
102
|
+
/**
|
103
|
+
* Gets the terminal factory.
|
104
|
+
*/
|
105
|
+
getTerminalFactory(
|
106
|
+
options: RunnerBaseOptions,
|
107
|
+
terminalName: string,
|
108
|
+
): Promise<InstanceTerminal | null>
|
109
|
+
|
110
|
+
/**
|
111
|
+
* Updates the instance.
|
112
|
+
*
|
113
|
+
* The operation must only be aborted by the signal, not even when the connection is closed.
|
114
|
+
* If the instance is already updating, it should exit immediately.
|
115
|
+
* If the instance is running another operation, it should throw an error.
|
116
|
+
*/
|
117
|
+
update(options: InstanceUpdateOptions): Promise<void>
|
118
|
+
|
119
|
+
/**
|
120
|
+
* Previews the instance update without actually applying the changes.
|
121
|
+
*
|
122
|
+
* The operation must only be aborted by the signal, not even when the connection is closed.
|
123
|
+
* If the instance is already updating, it should exit immediately.
|
124
|
+
* If the instance is running another operation, it should throw an error.
|
125
|
+
*/
|
126
|
+
preview(options: InstanceUpdateOptions): Promise<void>
|
127
|
+
|
128
|
+
/**
|
129
|
+
* Destroys the instance.
|
130
|
+
*
|
131
|
+
* The operation must only be aborted by the signal, not even when the connection is closed.
|
132
|
+
* If the instance is not created, it should exit immediately.
|
133
|
+
* If the instance is running another operation, it should throw an error.
|
134
|
+
*/
|
135
|
+
destroy(options: InstanceDestroyOptions): Promise<void>
|
136
|
+
|
137
|
+
/**
|
138
|
+
* Refreshes the instance.
|
139
|
+
*
|
140
|
+
* The operation must only be aborted by the signal, not even when the connection is closed.
|
141
|
+
* If the instance is not created, it should exit immediately.
|
142
|
+
* If the instance is running another operation, it should throw an error.
|
143
|
+
* If the instance is not running, it should exit immediately.
|
144
|
+
*/
|
145
|
+
refresh(options: RunnerBaseOptions): Promise<void>
|
146
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import type { RunnerBackend } from "./abstractions"
|
2
|
+
import type { LocalPulumiHost } from "../common"
|
3
|
+
import type { LibraryBackend } from "../library"
|
4
|
+
import { z } from "zod"
|
5
|
+
import { LocalRunnerBackend, localRunnerBackendConfig } from "./local"
|
6
|
+
|
7
|
+
export const runnerBackendConfig = z.object({
|
8
|
+
HIGHSTATE_BACKEND_RUNNER_TYPE: z.enum(["local"]).default("local"),
|
9
|
+
...localRunnerBackendConfig.shape,
|
10
|
+
})
|
11
|
+
|
12
|
+
export function createRunnerBackend(
|
13
|
+
config: z.infer<typeof runnerBackendConfig>,
|
14
|
+
pulumiProjectHost: LocalPulumiHost,
|
15
|
+
libraryBackend: LibraryBackend,
|
16
|
+
): RunnerBackend {
|
17
|
+
switch (config.HIGHSTATE_BACKEND_RUNNER_TYPE) {
|
18
|
+
case "local": {
|
19
|
+
return LocalRunnerBackend.create(config, pulumiProjectHost, libraryBackend)
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|