@terraforge/terraform 0.0.1
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/cli/build-package.ts +84 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.js +1845 -0
- package/package.json +37 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1845 @@
|
|
|
1
|
+
// src/plugin/client.ts
|
|
2
|
+
import { credentials, loadPackageDefinition } from "@grpc/grpc-js";
|
|
3
|
+
import { fromJSON } from "@grpc/proto-loader";
|
|
4
|
+
import { createDebugger } from "@terraforge/core";
|
|
5
|
+
|
|
6
|
+
// src/plugin/diagnostic.ts
|
|
7
|
+
class DiagnosticsError extends Error {
|
|
8
|
+
diagnostics;
|
|
9
|
+
constructor(diagnostics) {
|
|
10
|
+
super(diagnostics[0]?.summary ?? "Diagnostic error");
|
|
11
|
+
this.diagnostics = diagnostics;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
var throwDiagnosticError = (response) => {
|
|
15
|
+
const diagnostics = response.diagnostics.map((item) => ({
|
|
16
|
+
severity: item.severity === 1 ? "error" : "warning",
|
|
17
|
+
summary: item.summary,
|
|
18
|
+
detail: item.detail,
|
|
19
|
+
path: item.attribute?.steps.map((step) => step.attributeName)
|
|
20
|
+
}));
|
|
21
|
+
return new DiagnosticsError(diagnostics);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// src/plugin/protocol/tfplugin5.ts
|
|
25
|
+
var tfplugin5_default = {
|
|
26
|
+
options: { syntax: "proto3" },
|
|
27
|
+
nested: {
|
|
28
|
+
tfplugin5: {
|
|
29
|
+
nested: {
|
|
30
|
+
DynamicValue: { fields: { msgpack: { type: "bytes", id: 1 }, json: { type: "bytes", id: 2 } } },
|
|
31
|
+
Diagnostic: {
|
|
32
|
+
fields: {
|
|
33
|
+
severity: { type: "Severity", id: 1 },
|
|
34
|
+
summary: { type: "string", id: 2 },
|
|
35
|
+
detail: { type: "string", id: 3 },
|
|
36
|
+
attribute: { type: "AttributePath", id: 4 }
|
|
37
|
+
},
|
|
38
|
+
nested: { Severity: { values: { INVALID: 0, ERROR: 1, WARNING: 2 } } }
|
|
39
|
+
},
|
|
40
|
+
AttributePath: {
|
|
41
|
+
fields: { steps: { rule: "repeated", type: "Step", id: 1 } },
|
|
42
|
+
nested: {
|
|
43
|
+
Step: {
|
|
44
|
+
oneofs: { selector: { oneof: ["attributeName", "elementKeyString", "elementKeyInt"] } },
|
|
45
|
+
fields: {
|
|
46
|
+
attributeName: { type: "string", id: 1 },
|
|
47
|
+
elementKeyString: { type: "string", id: 2 },
|
|
48
|
+
elementKeyInt: { type: "int64", id: 3 }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
Stop: {
|
|
54
|
+
fields: {},
|
|
55
|
+
nested: { Request: { fields: {} }, Response: { fields: { Error: { type: "string", id: 1 } } } }
|
|
56
|
+
},
|
|
57
|
+
RawState: {
|
|
58
|
+
fields: { json: { type: "bytes", id: 1 }, flatmap: { keyType: "string", type: "string", id: 2 } }
|
|
59
|
+
},
|
|
60
|
+
Schema: {
|
|
61
|
+
fields: { version: { type: "int64", id: 1 }, block: { type: "Block", id: 2 } },
|
|
62
|
+
nested: {
|
|
63
|
+
Block: {
|
|
64
|
+
fields: {
|
|
65
|
+
version: { type: "int64", id: 1 },
|
|
66
|
+
attributes: { rule: "repeated", type: "Attribute", id: 2 },
|
|
67
|
+
blockTypes: { rule: "repeated", type: "NestedBlock", id: 3 }
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
Attribute: {
|
|
71
|
+
fields: {
|
|
72
|
+
name: { type: "string", id: 1 },
|
|
73
|
+
type: { type: "bytes", id: 2 },
|
|
74
|
+
description: { type: "string", id: 3 },
|
|
75
|
+
required: { type: "bool", id: 4 },
|
|
76
|
+
optional: { type: "bool", id: 5 },
|
|
77
|
+
computed: { type: "bool", id: 6 },
|
|
78
|
+
sensitive: { type: "bool", id: 7 }
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
NestedBlock: {
|
|
82
|
+
fields: {
|
|
83
|
+
typeName: { type: "string", id: 1 },
|
|
84
|
+
block: { type: "Block", id: 2 },
|
|
85
|
+
nesting: { type: "NestingMode", id: 3 },
|
|
86
|
+
minItems: { type: "int64", id: 4 },
|
|
87
|
+
maxItems: { type: "int64", id: 5 }
|
|
88
|
+
},
|
|
89
|
+
nested: {
|
|
90
|
+
NestingMode: { values: { INVALID: 0, SINGLE: 1, LIST: 2, SET: 3, MAP: 4, GROUP: 5 } }
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
Provider: {
|
|
96
|
+
methods: {
|
|
97
|
+
GetSchema: {
|
|
98
|
+
requestType: "GetProviderSchema.Request",
|
|
99
|
+
responseType: "GetProviderSchema.Response"
|
|
100
|
+
},
|
|
101
|
+
PrepareProviderConfig: {
|
|
102
|
+
requestType: "PrepareProviderConfig.Request",
|
|
103
|
+
responseType: "PrepareProviderConfig.Response"
|
|
104
|
+
},
|
|
105
|
+
ValidateResourceTypeConfig: {
|
|
106
|
+
requestType: "ValidateResourceTypeConfig.Request",
|
|
107
|
+
responseType: "ValidateResourceTypeConfig.Response"
|
|
108
|
+
},
|
|
109
|
+
ValidateDataSourceConfig: {
|
|
110
|
+
requestType: "ValidateDataSourceConfig.Request",
|
|
111
|
+
responseType: "ValidateDataSourceConfig.Response"
|
|
112
|
+
},
|
|
113
|
+
UpgradeResourceState: {
|
|
114
|
+
requestType: "UpgradeResourceState.Request",
|
|
115
|
+
responseType: "UpgradeResourceState.Response"
|
|
116
|
+
},
|
|
117
|
+
Configure: { requestType: "Configure.Request", responseType: "Configure.Response" },
|
|
118
|
+
ReadResource: { requestType: "ReadResource.Request", responseType: "ReadResource.Response" },
|
|
119
|
+
PlanResourceChange: {
|
|
120
|
+
requestType: "PlanResourceChange.Request",
|
|
121
|
+
responseType: "PlanResourceChange.Response"
|
|
122
|
+
},
|
|
123
|
+
ApplyResourceChange: {
|
|
124
|
+
requestType: "ApplyResourceChange.Request",
|
|
125
|
+
responseType: "ApplyResourceChange.Response"
|
|
126
|
+
},
|
|
127
|
+
ImportResourceState: {
|
|
128
|
+
requestType: "ImportResourceState.Request",
|
|
129
|
+
responseType: "ImportResourceState.Response"
|
|
130
|
+
},
|
|
131
|
+
ReadDataSource: {
|
|
132
|
+
requestType: "ReadDataSource.Request",
|
|
133
|
+
responseType: "ReadDataSource.Response"
|
|
134
|
+
},
|
|
135
|
+
Stop: { requestType: "Stop.Request", responseType: "Stop.Response" }
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
GetProviderSchema: {
|
|
139
|
+
fields: {},
|
|
140
|
+
nested: {
|
|
141
|
+
Request: { fields: {} },
|
|
142
|
+
Response: {
|
|
143
|
+
fields: {
|
|
144
|
+
provider: { type: "Schema", id: 1 },
|
|
145
|
+
resourceSchemas: { keyType: "string", type: "Schema", id: 2 },
|
|
146
|
+
dataSourceSchemas: { keyType: "string", type: "Schema", id: 3 },
|
|
147
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 4 }
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
PrepareProviderConfig: {
|
|
153
|
+
fields: {},
|
|
154
|
+
nested: {
|
|
155
|
+
Request: { fields: { config: { type: "DynamicValue", id: 1 } } },
|
|
156
|
+
Response: {
|
|
157
|
+
fields: {
|
|
158
|
+
preparedConfig: { type: "DynamicValue", id: 1 },
|
|
159
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 2 }
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
UpgradeResourceState: {
|
|
165
|
+
fields: {},
|
|
166
|
+
nested: {
|
|
167
|
+
Request: {
|
|
168
|
+
fields: {
|
|
169
|
+
typeName: { type: "string", id: 1 },
|
|
170
|
+
version: { type: "int64", id: 2 },
|
|
171
|
+
rawState: { type: "RawState", id: 3 }
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
Response: {
|
|
175
|
+
fields: {
|
|
176
|
+
upgradedState: { type: "DynamicValue", id: 1 },
|
|
177
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 2 }
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
ValidateResourceTypeConfig: {
|
|
183
|
+
fields: {},
|
|
184
|
+
nested: {
|
|
185
|
+
Request: {
|
|
186
|
+
fields: { typeName: { type: "string", id: 1 }, config: { type: "DynamicValue", id: 2 } }
|
|
187
|
+
},
|
|
188
|
+
Response: { fields: { diagnostics: { rule: "repeated", type: "Diagnostic", id: 1 } } }
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
ValidateDataSourceConfig: {
|
|
192
|
+
fields: {},
|
|
193
|
+
nested: {
|
|
194
|
+
Request: {
|
|
195
|
+
fields: { typeName: { type: "string", id: 1 }, config: { type: "DynamicValue", id: 2 } }
|
|
196
|
+
},
|
|
197
|
+
Response: { fields: { diagnostics: { rule: "repeated", type: "Diagnostic", id: 1 } } }
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
Configure: {
|
|
201
|
+
fields: {},
|
|
202
|
+
nested: {
|
|
203
|
+
Request: {
|
|
204
|
+
fields: {
|
|
205
|
+
terraformVersion: { type: "string", id: 1 },
|
|
206
|
+
config: { type: "DynamicValue", id: 2 }
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
Response: { fields: { diagnostics: { rule: "repeated", type: "Diagnostic", id: 1 } } }
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
ReadResource: {
|
|
213
|
+
fields: {},
|
|
214
|
+
nested: {
|
|
215
|
+
Request: {
|
|
216
|
+
fields: {
|
|
217
|
+
typeName: { type: "string", id: 1 },
|
|
218
|
+
currentState: { type: "DynamicValue", id: 2 },
|
|
219
|
+
private: { type: "bytes", id: 3 }
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
Response: {
|
|
223
|
+
fields: {
|
|
224
|
+
newState: { type: "DynamicValue", id: 1 },
|
|
225
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 2 },
|
|
226
|
+
private: { type: "bytes", id: 3 }
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
PlanResourceChange: {
|
|
232
|
+
fields: {},
|
|
233
|
+
nested: {
|
|
234
|
+
Request: {
|
|
235
|
+
fields: {
|
|
236
|
+
typeName: { type: "string", id: 1 },
|
|
237
|
+
priorState: { type: "DynamicValue", id: 2 },
|
|
238
|
+
proposedNewState: { type: "DynamicValue", id: 3 },
|
|
239
|
+
config: { type: "DynamicValue", id: 4 },
|
|
240
|
+
priorPrivate: { type: "bytes", id: 5 }
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
Response: {
|
|
244
|
+
fields: {
|
|
245
|
+
plannedState: { type: "DynamicValue", id: 1 },
|
|
246
|
+
requiresReplace: { rule: "repeated", type: "AttributePath", id: 2 },
|
|
247
|
+
plannedPrivate: { type: "bytes", id: 3 },
|
|
248
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 4 },
|
|
249
|
+
legacyTypeSystem: { type: "bool", id: 5 }
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
ApplyResourceChange: {
|
|
255
|
+
fields: {},
|
|
256
|
+
nested: {
|
|
257
|
+
Request: {
|
|
258
|
+
fields: {
|
|
259
|
+
typeName: { type: "string", id: 1 },
|
|
260
|
+
priorState: { type: "DynamicValue", id: 2 },
|
|
261
|
+
plannedState: { type: "DynamicValue", id: 3 },
|
|
262
|
+
config: { type: "DynamicValue", id: 4 },
|
|
263
|
+
plannedPrivate: { type: "bytes", id: 5 }
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
Response: {
|
|
267
|
+
fields: {
|
|
268
|
+
newState: { type: "DynamicValue", id: 1 },
|
|
269
|
+
private: { type: "bytes", id: 2 },
|
|
270
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 3 },
|
|
271
|
+
legacyTypeSystem: { type: "bool", id: 4 }
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
ImportResourceState: {
|
|
277
|
+
fields: {},
|
|
278
|
+
nested: {
|
|
279
|
+
Request: { fields: { typeName: { type: "string", id: 1 }, id: { type: "string", id: 2 } } },
|
|
280
|
+
ImportedResource: {
|
|
281
|
+
fields: {
|
|
282
|
+
typeName: { type: "string", id: 1 },
|
|
283
|
+
state: { type: "DynamicValue", id: 2 },
|
|
284
|
+
private: { type: "bytes", id: 3 }
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
Response: {
|
|
288
|
+
fields: {
|
|
289
|
+
importedResources: { rule: "repeated", type: "ImportedResource", id: 1 },
|
|
290
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 2 }
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
ReadDataSource: {
|
|
296
|
+
fields: {},
|
|
297
|
+
nested: {
|
|
298
|
+
Request: {
|
|
299
|
+
fields: { typeName: { type: "string", id: 1 }, config: { type: "DynamicValue", id: 2 } }
|
|
300
|
+
},
|
|
301
|
+
Response: {
|
|
302
|
+
fields: {
|
|
303
|
+
state: { type: "DynamicValue", id: 1 },
|
|
304
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 2 }
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
Provisioner: {
|
|
310
|
+
methods: {
|
|
311
|
+
GetSchema: {
|
|
312
|
+
requestType: "GetProvisionerSchema.Request",
|
|
313
|
+
responseType: "GetProvisionerSchema.Response"
|
|
314
|
+
},
|
|
315
|
+
ValidateProvisionerConfig: {
|
|
316
|
+
requestType: "ValidateProvisionerConfig.Request",
|
|
317
|
+
responseType: "ValidateProvisionerConfig.Response"
|
|
318
|
+
},
|
|
319
|
+
ProvisionResource: {
|
|
320
|
+
requestType: "ProvisionResource.Request",
|
|
321
|
+
responseType: "ProvisionResource.Response",
|
|
322
|
+
responseStream: true
|
|
323
|
+
},
|
|
324
|
+
Stop: { requestType: "Stop.Request", responseType: "Stop.Response" }
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
GetProvisionerSchema: {
|
|
328
|
+
fields: {},
|
|
329
|
+
nested: {
|
|
330
|
+
Request: { fields: {} },
|
|
331
|
+
Response: {
|
|
332
|
+
fields: {
|
|
333
|
+
provisioner: { type: "Schema", id: 1 },
|
|
334
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 2 }
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
ValidateProvisionerConfig: {
|
|
340
|
+
fields: {},
|
|
341
|
+
nested: {
|
|
342
|
+
Request: { fields: { config: { type: "DynamicValue", id: 1 } } },
|
|
343
|
+
Response: { fields: { diagnostics: { rule: "repeated", type: "Diagnostic", id: 1 } } }
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
ProvisionResource: {
|
|
347
|
+
fields: {},
|
|
348
|
+
nested: {
|
|
349
|
+
Request: {
|
|
350
|
+
fields: {
|
|
351
|
+
config: { type: "DynamicValue", id: 1 },
|
|
352
|
+
connection: { type: "DynamicValue", id: 2 }
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
Response: {
|
|
356
|
+
fields: {
|
|
357
|
+
output: { type: "string", id: 1 },
|
|
358
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 2 }
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
// src/plugin/protocol/tfplugin6.ts
|
|
369
|
+
var tfplugin6_default = {
|
|
370
|
+
options: { syntax: "proto3", go_package: "github.com/hashicorp/terraform/internal/tfplugin6" },
|
|
371
|
+
nested: {
|
|
372
|
+
tfplugin6: {
|
|
373
|
+
nested: {
|
|
374
|
+
DynamicValue: { fields: { msgpack: { type: "bytes", id: 1 }, json: { type: "bytes", id: 2 } } },
|
|
375
|
+
Diagnostic: {
|
|
376
|
+
fields: {
|
|
377
|
+
severity: { type: "Severity", id: 1 },
|
|
378
|
+
summary: { type: "string", id: 2 },
|
|
379
|
+
detail: { type: "string", id: 3 },
|
|
380
|
+
attribute: { type: "AttributePath", id: 4 }
|
|
381
|
+
},
|
|
382
|
+
nested: { Severity: { values: { INVALID: 0, ERROR: 1, WARNING: 2 } } }
|
|
383
|
+
},
|
|
384
|
+
AttributePath: {
|
|
385
|
+
fields: { steps: { rule: "repeated", type: "Step", id: 1 } },
|
|
386
|
+
nested: {
|
|
387
|
+
Step: {
|
|
388
|
+
oneofs: { selector: { oneof: ["attributeName", "elementKeyString", "elementKeyInt"] } },
|
|
389
|
+
fields: {
|
|
390
|
+
attributeName: { type: "string", id: 1 },
|
|
391
|
+
elementKeyString: { type: "string", id: 2 },
|
|
392
|
+
elementKeyInt: { type: "int64", id: 3 }
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
StopProvider: {
|
|
398
|
+
fields: {},
|
|
399
|
+
nested: { Request: { fields: {} }, Response: { fields: { Error: { type: "string", id: 1 } } } }
|
|
400
|
+
},
|
|
401
|
+
RawState: {
|
|
402
|
+
fields: { json: { type: "bytes", id: 1 }, flatmap: { keyType: "string", type: "string", id: 2 } }
|
|
403
|
+
},
|
|
404
|
+
StringKind: { values: { PLAIN: 0, MARKDOWN: 1 } },
|
|
405
|
+
Schema: {
|
|
406
|
+
fields: { version: { type: "int64", id: 1 }, block: { type: "Block", id: 2 } },
|
|
407
|
+
nested: {
|
|
408
|
+
Block: {
|
|
409
|
+
fields: {
|
|
410
|
+
version: { type: "int64", id: 1 },
|
|
411
|
+
attributes: { rule: "repeated", type: "Attribute", id: 2 },
|
|
412
|
+
blockTypes: { rule: "repeated", type: "NestedBlock", id: 3 },
|
|
413
|
+
description: { type: "string", id: 4 },
|
|
414
|
+
descriptionKind: { type: "StringKind", id: 5 },
|
|
415
|
+
deprecated: { type: "bool", id: 6 }
|
|
416
|
+
}
|
|
417
|
+
},
|
|
418
|
+
Attribute: {
|
|
419
|
+
fields: {
|
|
420
|
+
name: { type: "string", id: 1 },
|
|
421
|
+
type: { type: "bytes", id: 2 },
|
|
422
|
+
nestedType: { type: "Object", id: 10 },
|
|
423
|
+
description: { type: "string", id: 3 },
|
|
424
|
+
required: { type: "bool", id: 4 },
|
|
425
|
+
optional: { type: "bool", id: 5 },
|
|
426
|
+
computed: { type: "bool", id: 6 },
|
|
427
|
+
sensitive: { type: "bool", id: 7 },
|
|
428
|
+
descriptionKind: { type: "StringKind", id: 8 },
|
|
429
|
+
deprecated: { type: "bool", id: 9 }
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
NestedBlock: {
|
|
433
|
+
fields: {
|
|
434
|
+
typeName: { type: "string", id: 1 },
|
|
435
|
+
block: { type: "Block", id: 2 },
|
|
436
|
+
nesting: { type: "NestingMode", id: 3 },
|
|
437
|
+
minItems: { type: "int64", id: 4 },
|
|
438
|
+
maxItems: { type: "int64", id: 5 }
|
|
439
|
+
},
|
|
440
|
+
nested: {
|
|
441
|
+
NestingMode: { values: { INVALID: 0, SINGLE: 1, LIST: 2, SET: 3, MAP: 4, GROUP: 5 } }
|
|
442
|
+
}
|
|
443
|
+
},
|
|
444
|
+
Object: {
|
|
445
|
+
fields: {
|
|
446
|
+
attributes: { rule: "repeated", type: "Attribute", id: 1 },
|
|
447
|
+
nesting: { type: "NestingMode", id: 3 },
|
|
448
|
+
minItems: { type: "int64", id: 4 },
|
|
449
|
+
maxItems: { type: "int64", id: 5 }
|
|
450
|
+
},
|
|
451
|
+
nested: { NestingMode: { values: { INVALID: 0, SINGLE: 1, LIST: 2, SET: 3, MAP: 4 } } }
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
Provider: {
|
|
456
|
+
methods: {
|
|
457
|
+
GetProviderSchema: {
|
|
458
|
+
requestType: "GetProviderSchema.Request",
|
|
459
|
+
responseType: "GetProviderSchema.Response"
|
|
460
|
+
},
|
|
461
|
+
ValidateProviderConfig: {
|
|
462
|
+
requestType: "ValidateProviderConfig.Request",
|
|
463
|
+
responseType: "ValidateProviderConfig.Response"
|
|
464
|
+
},
|
|
465
|
+
ValidateResourceConfig: {
|
|
466
|
+
requestType: "ValidateResourceConfig.Request",
|
|
467
|
+
responseType: "ValidateResourceConfig.Response"
|
|
468
|
+
},
|
|
469
|
+
ValidateDataResourceConfig: {
|
|
470
|
+
requestType: "ValidateDataResourceConfig.Request",
|
|
471
|
+
responseType: "ValidateDataResourceConfig.Response"
|
|
472
|
+
},
|
|
473
|
+
UpgradeResourceState: {
|
|
474
|
+
requestType: "UpgradeResourceState.Request",
|
|
475
|
+
responseType: "UpgradeResourceState.Response"
|
|
476
|
+
},
|
|
477
|
+
ConfigureProvider: {
|
|
478
|
+
requestType: "ConfigureProvider.Request",
|
|
479
|
+
responseType: "ConfigureProvider.Response"
|
|
480
|
+
},
|
|
481
|
+
ReadResource: { requestType: "ReadResource.Request", responseType: "ReadResource.Response" },
|
|
482
|
+
PlanResourceChange: {
|
|
483
|
+
requestType: "PlanResourceChange.Request",
|
|
484
|
+
responseType: "PlanResourceChange.Response"
|
|
485
|
+
},
|
|
486
|
+
ApplyResourceChange: {
|
|
487
|
+
requestType: "ApplyResourceChange.Request",
|
|
488
|
+
responseType: "ApplyResourceChange.Response"
|
|
489
|
+
},
|
|
490
|
+
ImportResourceState: {
|
|
491
|
+
requestType: "ImportResourceState.Request",
|
|
492
|
+
responseType: "ImportResourceState.Response"
|
|
493
|
+
},
|
|
494
|
+
ReadDataSource: {
|
|
495
|
+
requestType: "ReadDataSource.Request",
|
|
496
|
+
responseType: "ReadDataSource.Response"
|
|
497
|
+
},
|
|
498
|
+
StopProvider: { requestType: "StopProvider.Request", responseType: "StopProvider.Response" }
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
GetProviderSchema: {
|
|
502
|
+
fields: {},
|
|
503
|
+
nested: {
|
|
504
|
+
Request: { fields: {} },
|
|
505
|
+
Response: {
|
|
506
|
+
fields: {
|
|
507
|
+
provider: { type: "Schema", id: 1 },
|
|
508
|
+
resourceSchemas: { keyType: "string", type: "Schema", id: 2 },
|
|
509
|
+
dataSourceSchemas: { keyType: "string", type: "Schema", id: 3 },
|
|
510
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 4 },
|
|
511
|
+
providerMeta: { type: "Schema", id: 5 }
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
},
|
|
516
|
+
ValidateProviderConfig: {
|
|
517
|
+
fields: {},
|
|
518
|
+
nested: {
|
|
519
|
+
Request: { fields: { config: { type: "DynamicValue", id: 1 } } },
|
|
520
|
+
Response: { fields: { diagnostics: { rule: "repeated", type: "Diagnostic", id: 2 } } }
|
|
521
|
+
}
|
|
522
|
+
},
|
|
523
|
+
UpgradeResourceState: {
|
|
524
|
+
fields: {},
|
|
525
|
+
nested: {
|
|
526
|
+
Request: {
|
|
527
|
+
fields: {
|
|
528
|
+
typeName: { type: "string", id: 1 },
|
|
529
|
+
version: { type: "int64", id: 2 },
|
|
530
|
+
rawState: { type: "RawState", id: 3 }
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
Response: {
|
|
534
|
+
fields: {
|
|
535
|
+
upgradedState: { type: "DynamicValue", id: 1 },
|
|
536
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 2 }
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
},
|
|
541
|
+
ValidateResourceConfig: {
|
|
542
|
+
fields: {},
|
|
543
|
+
nested: {
|
|
544
|
+
Request: {
|
|
545
|
+
fields: { typeName: { type: "string", id: 1 }, config: { type: "DynamicValue", id: 2 } }
|
|
546
|
+
},
|
|
547
|
+
Response: { fields: { diagnostics: { rule: "repeated", type: "Diagnostic", id: 1 } } }
|
|
548
|
+
}
|
|
549
|
+
},
|
|
550
|
+
ValidateDataResourceConfig: {
|
|
551
|
+
fields: {},
|
|
552
|
+
nested: {
|
|
553
|
+
Request: {
|
|
554
|
+
fields: { typeName: { type: "string", id: 1 }, config: { type: "DynamicValue", id: 2 } }
|
|
555
|
+
},
|
|
556
|
+
Response: { fields: { diagnostics: { rule: "repeated", type: "Diagnostic", id: 1 } } }
|
|
557
|
+
}
|
|
558
|
+
},
|
|
559
|
+
ConfigureProvider: {
|
|
560
|
+
fields: {},
|
|
561
|
+
nested: {
|
|
562
|
+
Request: {
|
|
563
|
+
fields: {
|
|
564
|
+
terraformVersion: { type: "string", id: 1 },
|
|
565
|
+
config: { type: "DynamicValue", id: 2 }
|
|
566
|
+
}
|
|
567
|
+
},
|
|
568
|
+
Response: { fields: { diagnostics: { rule: "repeated", type: "Diagnostic", id: 1 } } }
|
|
569
|
+
}
|
|
570
|
+
},
|
|
571
|
+
ReadResource: {
|
|
572
|
+
fields: {},
|
|
573
|
+
nested: {
|
|
574
|
+
Request: {
|
|
575
|
+
fields: {
|
|
576
|
+
typeName: { type: "string", id: 1 },
|
|
577
|
+
currentState: { type: "DynamicValue", id: 2 },
|
|
578
|
+
private: { type: "bytes", id: 3 },
|
|
579
|
+
providerMeta: { type: "DynamicValue", id: 4 }
|
|
580
|
+
}
|
|
581
|
+
},
|
|
582
|
+
Response: {
|
|
583
|
+
fields: {
|
|
584
|
+
newState: { type: "DynamicValue", id: 1 },
|
|
585
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 2 },
|
|
586
|
+
private: { type: "bytes", id: 3 }
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
},
|
|
591
|
+
PlanResourceChange: {
|
|
592
|
+
fields: {},
|
|
593
|
+
nested: {
|
|
594
|
+
Request: {
|
|
595
|
+
fields: {
|
|
596
|
+
typeName: { type: "string", id: 1 },
|
|
597
|
+
priorState: { type: "DynamicValue", id: 2 },
|
|
598
|
+
proposedNewState: { type: "DynamicValue", id: 3 },
|
|
599
|
+
config: { type: "DynamicValue", id: 4 },
|
|
600
|
+
priorPrivate: { type: "bytes", id: 5 },
|
|
601
|
+
providerMeta: { type: "DynamicValue", id: 6 }
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
Response: {
|
|
605
|
+
fields: {
|
|
606
|
+
plannedState: { type: "DynamicValue", id: 1 },
|
|
607
|
+
requiresReplace: { rule: "repeated", type: "AttributePath", id: 2 },
|
|
608
|
+
plannedPrivate: { type: "bytes", id: 3 },
|
|
609
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 4 }
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
},
|
|
614
|
+
ApplyResourceChange: {
|
|
615
|
+
fields: {},
|
|
616
|
+
nested: {
|
|
617
|
+
Request: {
|
|
618
|
+
fields: {
|
|
619
|
+
typeName: { type: "string", id: 1 },
|
|
620
|
+
priorState: { type: "DynamicValue", id: 2 },
|
|
621
|
+
plannedState: { type: "DynamicValue", id: 3 },
|
|
622
|
+
config: { type: "DynamicValue", id: 4 },
|
|
623
|
+
plannedPrivate: { type: "bytes", id: 5 },
|
|
624
|
+
providerMeta: { type: "DynamicValue", id: 6 }
|
|
625
|
+
}
|
|
626
|
+
},
|
|
627
|
+
Response: {
|
|
628
|
+
fields: {
|
|
629
|
+
newState: { type: "DynamicValue", id: 1 },
|
|
630
|
+
private: { type: "bytes", id: 2 },
|
|
631
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 3 }
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
},
|
|
636
|
+
ImportResourceState: {
|
|
637
|
+
fields: {},
|
|
638
|
+
nested: {
|
|
639
|
+
Request: { fields: { typeName: { type: "string", id: 1 }, id: { type: "string", id: 2 } } },
|
|
640
|
+
ImportedResource: {
|
|
641
|
+
fields: {
|
|
642
|
+
typeName: { type: "string", id: 1 },
|
|
643
|
+
state: { type: "DynamicValue", id: 2 },
|
|
644
|
+
private: { type: "bytes", id: 3 }
|
|
645
|
+
}
|
|
646
|
+
},
|
|
647
|
+
Response: {
|
|
648
|
+
fields: {
|
|
649
|
+
importedResources: { rule: "repeated", type: "ImportedResource", id: 1 },
|
|
650
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 2 }
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
},
|
|
655
|
+
ReadDataSource: {
|
|
656
|
+
fields: {},
|
|
657
|
+
nested: {
|
|
658
|
+
Request: {
|
|
659
|
+
fields: {
|
|
660
|
+
typeName: { type: "string", id: 1 },
|
|
661
|
+
config: { type: "DynamicValue", id: 2 },
|
|
662
|
+
providerMeta: { type: "DynamicValue", id: 3 }
|
|
663
|
+
}
|
|
664
|
+
},
|
|
665
|
+
Response: {
|
|
666
|
+
fields: {
|
|
667
|
+
state: { type: "DynamicValue", id: 1 },
|
|
668
|
+
diagnostics: { rule: "repeated", type: "Diagnostic", id: 2 }
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
// src/plugin/client.ts
|
|
679
|
+
var debug = createDebugger("Client");
|
|
680
|
+
var protocols = {
|
|
681
|
+
tfplugin5: tfplugin5_default,
|
|
682
|
+
tfplugin6: tfplugin6_default
|
|
683
|
+
};
|
|
684
|
+
var createPluginClient = async (props) => {
|
|
685
|
+
const proto = protocols[props.protocol.split(".").at(0) ?? ""];
|
|
686
|
+
if (!proto) {
|
|
687
|
+
throw new Error(`We don't have support for the ${props.protocol} protocol`);
|
|
688
|
+
}
|
|
689
|
+
const pack = fromJSON(proto);
|
|
690
|
+
const grpc = loadPackageDefinition(pack);
|
|
691
|
+
const client = new grpc["tfplugin" + props.version].Provider(`unix://${props.endpoint}`, credentials.createInsecure(), {
|
|
692
|
+
"grpc.max_receive_message_length": 100 * 1024 * 1024,
|
|
693
|
+
"grpc.max_send_message_length": 100 * 1024 * 1024
|
|
694
|
+
});
|
|
695
|
+
debug("init", props.protocol);
|
|
696
|
+
await new Promise((resolve, reject) => {
|
|
697
|
+
const deadline = new Date;
|
|
698
|
+
deadline.setSeconds(deadline.getSeconds() + 10);
|
|
699
|
+
client.waitForReady(deadline, (error) => {
|
|
700
|
+
if (error) {
|
|
701
|
+
reject(error);
|
|
702
|
+
} else {
|
|
703
|
+
resolve();
|
|
704
|
+
}
|
|
705
|
+
});
|
|
706
|
+
});
|
|
707
|
+
debug("connected");
|
|
708
|
+
return {
|
|
709
|
+
call(method, payload) {
|
|
710
|
+
return new Promise((resolve, reject) => {
|
|
711
|
+
const fn = client[method];
|
|
712
|
+
debug("call", method);
|
|
713
|
+
if (!fn) {
|
|
714
|
+
reject(new Error(`Unknown method call: ${method}`));
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
fn.call(client, payload, (error, response) => {
|
|
718
|
+
if (error) {
|
|
719
|
+
debug("failed", error);
|
|
720
|
+
reject(error);
|
|
721
|
+
} else if (response.diagnostics) {
|
|
722
|
+
debug("failed", response.diagnostics);
|
|
723
|
+
reject(throwDiagnosticError(response));
|
|
724
|
+
} else {
|
|
725
|
+
resolve(response);
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
// src/plugin/download.ts
|
|
734
|
+
import { createDebugger as createDebugger2 } from "@terraforge/core";
|
|
735
|
+
import jszip from "jszip";
|
|
736
|
+
import { mkdir, stat, writeFile } from "node:fs/promises";
|
|
737
|
+
import { homedir } from "node:os";
|
|
738
|
+
import { join } from "node:path";
|
|
739
|
+
|
|
740
|
+
// src/plugin/registry.ts
|
|
741
|
+
import { arch, platform } from "node:os";
|
|
742
|
+
import { compare } from "semver";
|
|
743
|
+
var baseUrl = "https://registry.terraform.io/v1/providers";
|
|
744
|
+
var getProviderVersions = async (org, type) => {
|
|
745
|
+
const resp = await fetch(`${baseUrl}/${org}/${type}/versions`);
|
|
746
|
+
const data = await resp.json();
|
|
747
|
+
const versions = data.versions;
|
|
748
|
+
const os = getOS();
|
|
749
|
+
const ar = getArchitecture();
|
|
750
|
+
const supported = versions.filter((v) => {
|
|
751
|
+
return !!v.platforms.find((p) => p.os === os && p.arch === ar);
|
|
752
|
+
});
|
|
753
|
+
const sorted = supported.sort((a, b) => compare(a.version, b.version));
|
|
754
|
+
const latest = sorted.at(-1);
|
|
755
|
+
if (!latest) {
|
|
756
|
+
throw new Error("Version is unsupported for your platform.");
|
|
757
|
+
}
|
|
758
|
+
return {
|
|
759
|
+
versions,
|
|
760
|
+
supported,
|
|
761
|
+
latest: latest.version
|
|
762
|
+
};
|
|
763
|
+
};
|
|
764
|
+
var getProviderDownloadUrl = async (org, type, version) => {
|
|
765
|
+
const url = [
|
|
766
|
+
baseUrl,
|
|
767
|
+
org,
|
|
768
|
+
type,
|
|
769
|
+
version,
|
|
770
|
+
"download",
|
|
771
|
+
getOS(),
|
|
772
|
+
getArchitecture()
|
|
773
|
+
].join("/");
|
|
774
|
+
const response = await fetch(url);
|
|
775
|
+
const result = await response.json();
|
|
776
|
+
return {
|
|
777
|
+
url: result.download_url,
|
|
778
|
+
shasum: result.shasum,
|
|
779
|
+
protocols: result.protocols
|
|
780
|
+
};
|
|
781
|
+
};
|
|
782
|
+
var getOS = () => {
|
|
783
|
+
const os = platform();
|
|
784
|
+
switch (os) {
|
|
785
|
+
case "linux":
|
|
786
|
+
return "linux";
|
|
787
|
+
case "win32":
|
|
788
|
+
return "windows";
|
|
789
|
+
case "darwin":
|
|
790
|
+
return "darwin";
|
|
791
|
+
case "freebsd":
|
|
792
|
+
return "freebsd";
|
|
793
|
+
case "openbsd":
|
|
794
|
+
return "openbsd";
|
|
795
|
+
}
|
|
796
|
+
throw new Error(`Unsupported OS platform: ${os}`);
|
|
797
|
+
};
|
|
798
|
+
var getArchitecture = () => {
|
|
799
|
+
const ar = arch();
|
|
800
|
+
switch (ar) {
|
|
801
|
+
case "arm":
|
|
802
|
+
return "arm";
|
|
803
|
+
case "arm64":
|
|
804
|
+
return "arm64";
|
|
805
|
+
case "x64":
|
|
806
|
+
return "amd64";
|
|
807
|
+
case "ia32":
|
|
808
|
+
return "386";
|
|
809
|
+
}
|
|
810
|
+
throw new Error(`Unsupported architecture: ${ar}`);
|
|
811
|
+
};
|
|
812
|
+
|
|
813
|
+
// src/plugin/download.ts
|
|
814
|
+
var exists = async (file) => {
|
|
815
|
+
try {
|
|
816
|
+
await stat(file);
|
|
817
|
+
} catch (error) {
|
|
818
|
+
return false;
|
|
819
|
+
}
|
|
820
|
+
return true;
|
|
821
|
+
};
|
|
822
|
+
var debug2 = createDebugger2("Downloader");
|
|
823
|
+
var installPath = join(homedir(), ".terraforge", "plugins");
|
|
824
|
+
var downloadPlugin = async (props) => {
|
|
825
|
+
if (props.version === "latest") {
|
|
826
|
+
const { latest } = await getProviderVersions(props.org, props.type);
|
|
827
|
+
props.version = latest;
|
|
828
|
+
}
|
|
829
|
+
const dir = props.location ?? installPath;
|
|
830
|
+
const file = join(dir, `${props.org}-${props.type}-${props.version}`);
|
|
831
|
+
const exist = await exists(file);
|
|
832
|
+
if (!exist) {
|
|
833
|
+
debug2(props.type, "downloading...");
|
|
834
|
+
const info = await getProviderDownloadUrl(props.org, props.type, props.version);
|
|
835
|
+
const res = await fetch(info.url);
|
|
836
|
+
const buf = await res.bytes();
|
|
837
|
+
const zip = await jszip.loadAsync(buf);
|
|
838
|
+
const zipped = zip.filter((file2) => file2.startsWith("terraform-provider")).at(0);
|
|
839
|
+
if (!zipped) {
|
|
840
|
+
throw new Error(`Can't find the provider inside the downloaded zip file.`);
|
|
841
|
+
}
|
|
842
|
+
const binary = await zipped.async("nodebuffer");
|
|
843
|
+
debug2(props.type, "done");
|
|
844
|
+
await mkdir(dir, { recursive: true });
|
|
845
|
+
await writeFile(file, binary, {
|
|
846
|
+
mode: 509
|
|
847
|
+
});
|
|
848
|
+
} else {
|
|
849
|
+
debug2(props.type, "already downloaded");
|
|
850
|
+
}
|
|
851
|
+
return {
|
|
852
|
+
file,
|
|
853
|
+
version: props.version
|
|
854
|
+
};
|
|
855
|
+
};
|
|
856
|
+
|
|
857
|
+
// src/plugin/server.ts
|
|
858
|
+
import { createDebugger as createDebugger3 } from "@terraforge/core";
|
|
859
|
+
import { spawn } from "node:child_process";
|
|
860
|
+
var debug3 = createDebugger3("Server");
|
|
861
|
+
var createPluginServer = (props) => {
|
|
862
|
+
return new Promise((resolve, reject) => {
|
|
863
|
+
debug3("init");
|
|
864
|
+
const process = spawn(`${props.file}`, ["-debug"]);
|
|
865
|
+
process.stderr.on("data", (data) => {
|
|
866
|
+
if (props.debug) {
|
|
867
|
+
const message = data.toString("utf8");
|
|
868
|
+
console.log(message);
|
|
869
|
+
}
|
|
870
|
+
});
|
|
871
|
+
process.stdout.once("data", (data) => {
|
|
872
|
+
try {
|
|
873
|
+
const message = data.toString("utf8");
|
|
874
|
+
const matches = message.match(/TF_REATTACH_PROVIDERS\=\'(.*)\'/);
|
|
875
|
+
if (matches && matches.length > 0) {
|
|
876
|
+
const match = matches[0];
|
|
877
|
+
const json = match.slice(23, -1);
|
|
878
|
+
const data2 = JSON.parse(json);
|
|
879
|
+
const entries = Object.values(data2);
|
|
880
|
+
if (entries.length > 0) {
|
|
881
|
+
const entry = entries[0];
|
|
882
|
+
const version = entry.ProtocolVersion;
|
|
883
|
+
const endpoint = entry.Addr.String;
|
|
884
|
+
debug3("started", endpoint);
|
|
885
|
+
resolve({
|
|
886
|
+
kill() {
|
|
887
|
+
process.kill();
|
|
888
|
+
},
|
|
889
|
+
protocol: "tfplugin" + version.toFixed(1),
|
|
890
|
+
version,
|
|
891
|
+
endpoint
|
|
892
|
+
});
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
} catch (error) {}
|
|
897
|
+
debug3("failed");
|
|
898
|
+
reject(new Error("Failed to start the plugin"));
|
|
899
|
+
});
|
|
900
|
+
});
|
|
901
|
+
};
|
|
902
|
+
|
|
903
|
+
// src/plugin/schema.ts
|
|
904
|
+
var NestingMode = {
|
|
905
|
+
INVALID: 0,
|
|
906
|
+
SINGLE: 1,
|
|
907
|
+
LIST: 2,
|
|
908
|
+
SET: 3,
|
|
909
|
+
MAP: 4,
|
|
910
|
+
GROUP: 5
|
|
911
|
+
};
|
|
912
|
+
var parseResourceSchema = (schemas) => {
|
|
913
|
+
const props = {};
|
|
914
|
+
for (const [name, schema] of Object.entries(schemas)) {
|
|
915
|
+
if (schema.block) {
|
|
916
|
+
const block = parseBlock(schema.block);
|
|
917
|
+
props[name] = {
|
|
918
|
+
...block,
|
|
919
|
+
version: block.version ?? schema.version
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
return props;
|
|
924
|
+
};
|
|
925
|
+
var parseProviderSchema = (schema) => {
|
|
926
|
+
if (schema.block) {
|
|
927
|
+
const block = parseBlock(schema.block);
|
|
928
|
+
return {
|
|
929
|
+
...block,
|
|
930
|
+
version: block.version ?? schema.version
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
throw new Error("Invalid block");
|
|
934
|
+
};
|
|
935
|
+
var parseBlock = (block) => {
|
|
936
|
+
const properties = {};
|
|
937
|
+
for (const entry of block.attributes ?? []) {
|
|
938
|
+
properties[entry.name] = parseAttribute(entry);
|
|
939
|
+
}
|
|
940
|
+
for (const entry of block.blockTypes ?? []) {
|
|
941
|
+
properties[entry.typeName] = parseNestedBlock(entry);
|
|
942
|
+
}
|
|
943
|
+
if (block.deprecated) {
|
|
944
|
+
console.warn("Deprecated block");
|
|
945
|
+
}
|
|
946
|
+
return {
|
|
947
|
+
type: "object",
|
|
948
|
+
version: block.version,
|
|
949
|
+
description: block.description,
|
|
950
|
+
properties
|
|
951
|
+
};
|
|
952
|
+
};
|
|
953
|
+
var parseNestedBlock = (block) => {
|
|
954
|
+
const type = parseNestedBlockType(block);
|
|
955
|
+
const item = parseBlock(block.block);
|
|
956
|
+
const prop = {
|
|
957
|
+
optional: true,
|
|
958
|
+
required: false,
|
|
959
|
+
computed: false
|
|
960
|
+
};
|
|
961
|
+
if (type === "array" || type === "record") {
|
|
962
|
+
return {
|
|
963
|
+
...prop,
|
|
964
|
+
type,
|
|
965
|
+
item
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
if (type === "array-object") {
|
|
969
|
+
return {
|
|
970
|
+
...prop,
|
|
971
|
+
...item,
|
|
972
|
+
type
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
return {
|
|
976
|
+
...prop,
|
|
977
|
+
...item
|
|
978
|
+
};
|
|
979
|
+
};
|
|
980
|
+
var parseNestedBlockType = (block) => {
|
|
981
|
+
if (block.nesting === NestingMode.SET) {
|
|
982
|
+
return "array";
|
|
983
|
+
}
|
|
984
|
+
if (block.nesting === NestingMode.LIST) {
|
|
985
|
+
if (block.maxItems?.eq(1)) {
|
|
986
|
+
return "array-object";
|
|
987
|
+
}
|
|
988
|
+
return "array";
|
|
989
|
+
}
|
|
990
|
+
if (block.nesting === NestingMode.MAP) {
|
|
991
|
+
return "record";
|
|
992
|
+
}
|
|
993
|
+
if (block.nesting === NestingMode.GROUP) {
|
|
994
|
+
return "object";
|
|
995
|
+
}
|
|
996
|
+
if (block.nesting === NestingMode.SINGLE) {
|
|
997
|
+
return "object";
|
|
998
|
+
}
|
|
999
|
+
throw new Error(`Invalid nested block type ${block.nesting}`);
|
|
1000
|
+
};
|
|
1001
|
+
var parseAttribute = (attr) => {
|
|
1002
|
+
const prop = {
|
|
1003
|
+
description: attr.description,
|
|
1004
|
+
required: attr.required,
|
|
1005
|
+
optional: attr.optional,
|
|
1006
|
+
computed: attr.computed,
|
|
1007
|
+
deprecated: attr.deprecated,
|
|
1008
|
+
sensitive: attr.sensitive
|
|
1009
|
+
};
|
|
1010
|
+
if (attr.type) {
|
|
1011
|
+
const json = JSON.parse(attr.type.toString("utf8"));
|
|
1012
|
+
return {
|
|
1013
|
+
...prop,
|
|
1014
|
+
...parseAttributeType(json)
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
if (attr.nestedType) {
|
|
1018
|
+
return {
|
|
1019
|
+
...prop,
|
|
1020
|
+
...parseBlock(attr.nestedType)
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1023
|
+
throw new Error("Empty attr");
|
|
1024
|
+
};
|
|
1025
|
+
var parseAttributeType = (item) => {
|
|
1026
|
+
if (Array.isArray(item)) {
|
|
1027
|
+
const type2 = parseType(item[0]);
|
|
1028
|
+
if (type2 === "array" || type2 === "record" && item) {
|
|
1029
|
+
const record = item[1];
|
|
1030
|
+
return {
|
|
1031
|
+
type: type2,
|
|
1032
|
+
item: parseAttributeType(record)
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
1035
|
+
if (type2 === "object") {
|
|
1036
|
+
const object = item[1];
|
|
1037
|
+
const properties = {};
|
|
1038
|
+
for (const [name, prop] of Object.entries(object)) {
|
|
1039
|
+
properties[name] = parseAttributeType(prop);
|
|
1040
|
+
}
|
|
1041
|
+
return {
|
|
1042
|
+
type: type2,
|
|
1043
|
+
properties
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
throw new Error("Invalid attribute type");
|
|
1047
|
+
}
|
|
1048
|
+
const type = parseType(item);
|
|
1049
|
+
if (isLeafType(type)) {
|
|
1050
|
+
return {
|
|
1051
|
+
type
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
throw new Error(`Invalid attribute type`);
|
|
1055
|
+
};
|
|
1056
|
+
var isLeafType = (type) => {
|
|
1057
|
+
return ["string", "number", "boolean", "unknown"].includes(type);
|
|
1058
|
+
};
|
|
1059
|
+
var parseType = (type) => {
|
|
1060
|
+
if (type === "string") {
|
|
1061
|
+
return "string";
|
|
1062
|
+
}
|
|
1063
|
+
if (type === "number") {
|
|
1064
|
+
return "number";
|
|
1065
|
+
}
|
|
1066
|
+
if (type === "bool") {
|
|
1067
|
+
return "boolean";
|
|
1068
|
+
}
|
|
1069
|
+
if (["set", "list"].includes(type)) {
|
|
1070
|
+
return "array";
|
|
1071
|
+
}
|
|
1072
|
+
if (type === "object") {
|
|
1073
|
+
return "object";
|
|
1074
|
+
}
|
|
1075
|
+
if (type === "map") {
|
|
1076
|
+
return "record";
|
|
1077
|
+
}
|
|
1078
|
+
if (type === "dynamic") {
|
|
1079
|
+
return "unknown";
|
|
1080
|
+
}
|
|
1081
|
+
throw new Error(`Invalid type: ${type}`);
|
|
1082
|
+
};
|
|
1083
|
+
|
|
1084
|
+
// src/plugin/version/util.ts
|
|
1085
|
+
import { camelCase, snakeCase } from "change-case";
|
|
1086
|
+
import { pack, unpack } from "msgpackr";
|
|
1087
|
+
var encodeDynamicValue = (value) => {
|
|
1088
|
+
return {
|
|
1089
|
+
msgpack: pack(value),
|
|
1090
|
+
json: value
|
|
1091
|
+
};
|
|
1092
|
+
};
|
|
1093
|
+
var decodeDynamicValue = (value) => {
|
|
1094
|
+
return unpack(value.msgpack);
|
|
1095
|
+
};
|
|
1096
|
+
var getResourceSchema = (resources, type) => {
|
|
1097
|
+
const resource = resources[type];
|
|
1098
|
+
if (!resource) {
|
|
1099
|
+
throw new Error(`Unknown resource type: ${type}`);
|
|
1100
|
+
}
|
|
1101
|
+
return resource;
|
|
1102
|
+
};
|
|
1103
|
+
var formatAttributePath = (state) => {
|
|
1104
|
+
if (!state) {
|
|
1105
|
+
return [];
|
|
1106
|
+
}
|
|
1107
|
+
return state.map((item) => {
|
|
1108
|
+
if (!item.steps) {
|
|
1109
|
+
throw new Error("AttributePath should always have steps");
|
|
1110
|
+
}
|
|
1111
|
+
return item.steps.map((attr) => {
|
|
1112
|
+
if ("attributeName" in attr) {
|
|
1113
|
+
return attr.attributeName;
|
|
1114
|
+
}
|
|
1115
|
+
if ("elementKeyString" in attr) {
|
|
1116
|
+
return attr.elementKeyString;
|
|
1117
|
+
}
|
|
1118
|
+
if ("elementKeyInt" in attr) {
|
|
1119
|
+
return attr.elementKeyInt;
|
|
1120
|
+
}
|
|
1121
|
+
throw new Error("AttributePath step should always have an element");
|
|
1122
|
+
});
|
|
1123
|
+
});
|
|
1124
|
+
};
|
|
1125
|
+
|
|
1126
|
+
class IncorrectType extends TypeError {
|
|
1127
|
+
constructor(type, path) {
|
|
1128
|
+
super(`${path.join(".")} should be a ${type}`);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
var formatInputState = (schema, state, includeSchemaFields = true, path = []) => {
|
|
1132
|
+
if (state === null) {
|
|
1133
|
+
return null;
|
|
1134
|
+
}
|
|
1135
|
+
if (typeof state === "undefined") {
|
|
1136
|
+
return null;
|
|
1137
|
+
}
|
|
1138
|
+
if (schema.type === "unknown") {
|
|
1139
|
+
return state;
|
|
1140
|
+
}
|
|
1141
|
+
if (schema.type === "string") {
|
|
1142
|
+
if (typeof state === "string") {
|
|
1143
|
+
return state;
|
|
1144
|
+
}
|
|
1145
|
+
throw new IncorrectType(schema.type, path);
|
|
1146
|
+
}
|
|
1147
|
+
if (schema.type === "number") {
|
|
1148
|
+
if (typeof state === "number") {
|
|
1149
|
+
return state;
|
|
1150
|
+
}
|
|
1151
|
+
throw new IncorrectType(schema.type, path);
|
|
1152
|
+
}
|
|
1153
|
+
if (schema.type === "boolean") {
|
|
1154
|
+
if (typeof state === "boolean") {
|
|
1155
|
+
return state;
|
|
1156
|
+
}
|
|
1157
|
+
throw new IncorrectType(schema.type, path);
|
|
1158
|
+
}
|
|
1159
|
+
if (schema.type === "array") {
|
|
1160
|
+
if (Array.isArray(state)) {
|
|
1161
|
+
return state.map((item, i) => formatInputState(schema.item, item, includeSchemaFields, [...path, i]));
|
|
1162
|
+
}
|
|
1163
|
+
throw new IncorrectType(schema.type, path);
|
|
1164
|
+
}
|
|
1165
|
+
if (schema.type === "record") {
|
|
1166
|
+
if (typeof state === "object" && state !== null) {
|
|
1167
|
+
const record = {};
|
|
1168
|
+
for (const [key, value] of Object.entries(state)) {
|
|
1169
|
+
record[key] = formatInputState(schema.item, value, includeSchemaFields, [...path, key]);
|
|
1170
|
+
}
|
|
1171
|
+
return record;
|
|
1172
|
+
}
|
|
1173
|
+
throw new IncorrectType(schema.type, path);
|
|
1174
|
+
}
|
|
1175
|
+
if (schema.type === "object" || schema.type === "array-object") {
|
|
1176
|
+
if (typeof state === "object" && state !== null) {
|
|
1177
|
+
const object = {};
|
|
1178
|
+
if (includeSchemaFields) {
|
|
1179
|
+
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
1180
|
+
const value = state[camelCase(key)];
|
|
1181
|
+
object[key] = formatInputState(prop, value, true, [...path, key]);
|
|
1182
|
+
}
|
|
1183
|
+
} else {
|
|
1184
|
+
for (const [key, value] of Object.entries(state)) {
|
|
1185
|
+
const prop = schema.properties[snakeCase(key)];
|
|
1186
|
+
if (prop) {
|
|
1187
|
+
object[key] = formatInputState(prop, value, false, [...path, key]);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
if (schema.type === "array-object") {
|
|
1192
|
+
return [object];
|
|
1193
|
+
}
|
|
1194
|
+
return object;
|
|
1195
|
+
}
|
|
1196
|
+
throw new IncorrectType(schema.type, path);
|
|
1197
|
+
}
|
|
1198
|
+
throw new Error(`Unknown schema type: ${schema.type}`);
|
|
1199
|
+
};
|
|
1200
|
+
var formatOutputState = (schema, state, path = []) => {
|
|
1201
|
+
if (state === null) {
|
|
1202
|
+
return;
|
|
1203
|
+
}
|
|
1204
|
+
if (schema.type === "array") {
|
|
1205
|
+
if (Array.isArray(state)) {
|
|
1206
|
+
return state.map((item, i) => formatOutputState(schema.item, item, [...path, i]));
|
|
1207
|
+
}
|
|
1208
|
+
throw new IncorrectType(schema.type, path);
|
|
1209
|
+
}
|
|
1210
|
+
if (schema.type === "record") {
|
|
1211
|
+
if (typeof state === "object" && state !== null) {
|
|
1212
|
+
const record = {};
|
|
1213
|
+
for (const [key, value] of Object.entries(state)) {
|
|
1214
|
+
record[key] = formatOutputState(schema.item, value, [...path, key]);
|
|
1215
|
+
}
|
|
1216
|
+
return record;
|
|
1217
|
+
}
|
|
1218
|
+
throw new IncorrectType(schema.type, path);
|
|
1219
|
+
}
|
|
1220
|
+
if (schema.type === "object") {
|
|
1221
|
+
if (typeof state === "object" && state !== null) {
|
|
1222
|
+
const object = {};
|
|
1223
|
+
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
1224
|
+
const value = state[key];
|
|
1225
|
+
object[camelCase(key)] = formatOutputState(prop, value, [...path, key]);
|
|
1226
|
+
}
|
|
1227
|
+
return object;
|
|
1228
|
+
}
|
|
1229
|
+
throw new IncorrectType(schema.type, path);
|
|
1230
|
+
}
|
|
1231
|
+
if (schema.type === "array-object") {
|
|
1232
|
+
if (Array.isArray(state)) {
|
|
1233
|
+
if (state.length === 1) {
|
|
1234
|
+
const object = {};
|
|
1235
|
+
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
1236
|
+
const value = state[0][key];
|
|
1237
|
+
object[camelCase(key)] = formatOutputState(prop, value, [...path, key]);
|
|
1238
|
+
}
|
|
1239
|
+
return object;
|
|
1240
|
+
} else {
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
throw new IncorrectType(schema.type, path);
|
|
1245
|
+
}
|
|
1246
|
+
return state;
|
|
1247
|
+
};
|
|
1248
|
+
|
|
1249
|
+
// src/plugin/version/5.ts
|
|
1250
|
+
var createPlugin5 = async ({
|
|
1251
|
+
server,
|
|
1252
|
+
client
|
|
1253
|
+
}) => {
|
|
1254
|
+
const schema = await client.call("GetSchema");
|
|
1255
|
+
const provider = parseProviderSchema(schema.provider);
|
|
1256
|
+
const resources = parseResourceSchema(schema.resourceSchemas);
|
|
1257
|
+
const dataSources = parseResourceSchema(schema.dataSourceSchemas);
|
|
1258
|
+
return {
|
|
1259
|
+
schema() {
|
|
1260
|
+
return {
|
|
1261
|
+
provider,
|
|
1262
|
+
resources,
|
|
1263
|
+
dataSources
|
|
1264
|
+
};
|
|
1265
|
+
},
|
|
1266
|
+
async stop() {
|
|
1267
|
+
await client.call("Stop");
|
|
1268
|
+
server.kill();
|
|
1269
|
+
},
|
|
1270
|
+
async configure(config) {
|
|
1271
|
+
const prepared = await client.call("PrepareProviderConfig", {
|
|
1272
|
+
config: encodeDynamicValue(formatInputState(provider, config))
|
|
1273
|
+
});
|
|
1274
|
+
await client.call("Configure", {
|
|
1275
|
+
config: prepared.preparedConfig
|
|
1276
|
+
});
|
|
1277
|
+
},
|
|
1278
|
+
async readResource(type, state) {
|
|
1279
|
+
const schema2 = getResourceSchema(resources, type);
|
|
1280
|
+
const read = await client.call("ReadResource", {
|
|
1281
|
+
typeName: type,
|
|
1282
|
+
currentState: encodeDynamicValue(formatInputState(schema2, state))
|
|
1283
|
+
});
|
|
1284
|
+
return formatOutputState(schema2, decodeDynamicValue(read.newState));
|
|
1285
|
+
},
|
|
1286
|
+
async readDataSource(type, state) {
|
|
1287
|
+
const schema2 = getResourceSchema(dataSources, type);
|
|
1288
|
+
const read = await client.call("ReadDataSource", {
|
|
1289
|
+
typeName: type,
|
|
1290
|
+
config: encodeDynamicValue(formatInputState(schema2, state))
|
|
1291
|
+
});
|
|
1292
|
+
return formatOutputState(schema2, decodeDynamicValue(read.state));
|
|
1293
|
+
},
|
|
1294
|
+
async validateResource(type, state) {
|
|
1295
|
+
const schema2 = getResourceSchema(resources, type);
|
|
1296
|
+
await client.call("ValidateResourceTypeConfig", {
|
|
1297
|
+
typeName: type,
|
|
1298
|
+
config: encodeDynamicValue(formatInputState(schema2, state))
|
|
1299
|
+
});
|
|
1300
|
+
},
|
|
1301
|
+
async planResourceChange(type, priorState, proposedState) {
|
|
1302
|
+
const schema2 = getResourceSchema(resources, type);
|
|
1303
|
+
const preparedPriorState = formatInputState(schema2, priorState);
|
|
1304
|
+
const preparedProposedState = formatInputState(schema2, proposedState);
|
|
1305
|
+
const plan = await client.call("PlanResourceChange", {
|
|
1306
|
+
typeName: type,
|
|
1307
|
+
priorState: encodeDynamicValue(preparedPriorState),
|
|
1308
|
+
proposedNewState: encodeDynamicValue(preparedProposedState),
|
|
1309
|
+
config: encodeDynamicValue(preparedProposedState)
|
|
1310
|
+
});
|
|
1311
|
+
const plannedState = decodeDynamicValue(plan.plannedState);
|
|
1312
|
+
const requiresReplace = formatAttributePath(plan.requiresReplace);
|
|
1313
|
+
return {
|
|
1314
|
+
requiresReplace,
|
|
1315
|
+
plannedState
|
|
1316
|
+
};
|
|
1317
|
+
},
|
|
1318
|
+
async applyResourceChange(type, priorState, proposedState) {
|
|
1319
|
+
const schema2 = getResourceSchema(resources, type);
|
|
1320
|
+
const preparedPriorState = formatInputState(schema2, priorState);
|
|
1321
|
+
const preparedProposedState = formatInputState(schema2, proposedState);
|
|
1322
|
+
const apply = await client.call("ApplyResourceChange", {
|
|
1323
|
+
typeName: type,
|
|
1324
|
+
priorState: encodeDynamicValue(preparedPriorState),
|
|
1325
|
+
plannedState: encodeDynamicValue(preparedProposedState),
|
|
1326
|
+
config: encodeDynamicValue(preparedProposedState)
|
|
1327
|
+
});
|
|
1328
|
+
return formatOutputState(schema2, decodeDynamicValue(apply.newState));
|
|
1329
|
+
}
|
|
1330
|
+
};
|
|
1331
|
+
};
|
|
1332
|
+
|
|
1333
|
+
// src/plugin/version/6.ts
|
|
1334
|
+
var createPlugin6 = async ({
|
|
1335
|
+
server,
|
|
1336
|
+
client
|
|
1337
|
+
}) => {
|
|
1338
|
+
const schema = await client.call("GetProviderSchema");
|
|
1339
|
+
const provider = parseProviderSchema(schema.provider);
|
|
1340
|
+
const resources = parseResourceSchema(schema.resourceSchemas);
|
|
1341
|
+
const dataSources = parseResourceSchema(schema.dataSourceSchemas);
|
|
1342
|
+
return {
|
|
1343
|
+
schema() {
|
|
1344
|
+
return {
|
|
1345
|
+
provider,
|
|
1346
|
+
resources,
|
|
1347
|
+
dataSources
|
|
1348
|
+
};
|
|
1349
|
+
},
|
|
1350
|
+
async stop() {
|
|
1351
|
+
await client.call("StopProvider");
|
|
1352
|
+
server.kill();
|
|
1353
|
+
},
|
|
1354
|
+
async configure(config) {
|
|
1355
|
+
const prepared = await client.call("ValidateProviderConfig", {
|
|
1356
|
+
config: encodeDynamicValue(formatInputState(provider, config))
|
|
1357
|
+
});
|
|
1358
|
+
await client.call("ConfigureProvider", {
|
|
1359
|
+
config: prepared.preparedConfig
|
|
1360
|
+
});
|
|
1361
|
+
},
|
|
1362
|
+
async readResource(type, state) {
|
|
1363
|
+
const schema2 = getResourceSchema(resources, type);
|
|
1364
|
+
const read = await client.call("ReadResource", {
|
|
1365
|
+
typeName: type,
|
|
1366
|
+
currentState: encodeDynamicValue(formatInputState(schema2, state))
|
|
1367
|
+
});
|
|
1368
|
+
return formatOutputState(schema2, decodeDynamicValue(read.newState));
|
|
1369
|
+
},
|
|
1370
|
+
async readDataSource(type, state) {
|
|
1371
|
+
const schema2 = getResourceSchema(dataSources, type);
|
|
1372
|
+
const read = await client.call("ReadDataSource", {
|
|
1373
|
+
typeName: type,
|
|
1374
|
+
config: encodeDynamicValue(formatInputState(schema2, state))
|
|
1375
|
+
});
|
|
1376
|
+
return formatOutputState(schema2, decodeDynamicValue(read.state));
|
|
1377
|
+
},
|
|
1378
|
+
async validateResource(type, state) {
|
|
1379
|
+
const schema2 = getResourceSchema(resources, type);
|
|
1380
|
+
await client.call("ValidateResourceConfig", {
|
|
1381
|
+
typeName: type,
|
|
1382
|
+
config: encodeDynamicValue(formatInputState(schema2, state))
|
|
1383
|
+
});
|
|
1384
|
+
},
|
|
1385
|
+
async planResourceChange(type, priorState, proposedState) {
|
|
1386
|
+
const schema2 = getResourceSchema(resources, type);
|
|
1387
|
+
const preparedPriorState = formatInputState(schema2, priorState);
|
|
1388
|
+
const preparedProposedState = formatInputState(schema2, proposedState);
|
|
1389
|
+
const plan = await client.call("PlanResourceChange", {
|
|
1390
|
+
typeName: type,
|
|
1391
|
+
priorState: encodeDynamicValue(preparedPriorState),
|
|
1392
|
+
proposedNewState: encodeDynamicValue(preparedProposedState),
|
|
1393
|
+
config: encodeDynamicValue(preparedProposedState)
|
|
1394
|
+
});
|
|
1395
|
+
const plannedState = decodeDynamicValue(plan.plannedState);
|
|
1396
|
+
const requiresReplace = formatAttributePath(plan.requiresReplace);
|
|
1397
|
+
return {
|
|
1398
|
+
requiresReplace,
|
|
1399
|
+
plannedState
|
|
1400
|
+
};
|
|
1401
|
+
},
|
|
1402
|
+
async applyResourceChange(type, priorState, proposedState) {
|
|
1403
|
+
const schema2 = getResourceSchema(resources, type);
|
|
1404
|
+
const preparedPriorState = formatInputState(schema2, priorState);
|
|
1405
|
+
const preparedProposedState = formatInputState(schema2, proposedState);
|
|
1406
|
+
const apply = await client.call("ApplyResourceChange", {
|
|
1407
|
+
typeName: type,
|
|
1408
|
+
priorState: encodeDynamicValue(preparedPriorState),
|
|
1409
|
+
plannedState: encodeDynamicValue(preparedProposedState),
|
|
1410
|
+
config: encodeDynamicValue(preparedProposedState)
|
|
1411
|
+
});
|
|
1412
|
+
return formatOutputState(schema2, decodeDynamicValue(apply.newState));
|
|
1413
|
+
}
|
|
1414
|
+
};
|
|
1415
|
+
};
|
|
1416
|
+
|
|
1417
|
+
// src/lazy-plugin.ts
|
|
1418
|
+
var createLazyPlugin = (props) => {
|
|
1419
|
+
return async () => {
|
|
1420
|
+
const { file } = await downloadPlugin(props);
|
|
1421
|
+
const server = await retry(3, () => createPluginServer({ file, debug: false }));
|
|
1422
|
+
const client = await retry(3, () => createPluginClient(server));
|
|
1423
|
+
const plugins = {
|
|
1424
|
+
5: () => createPlugin5({ server, client }),
|
|
1425
|
+
6: () => createPlugin6({ server, client })
|
|
1426
|
+
};
|
|
1427
|
+
const plugin = await plugins[server.version]?.();
|
|
1428
|
+
if (!plugin) {
|
|
1429
|
+
throw new Error(`No plugin client available for protocol version ${server.version}`);
|
|
1430
|
+
}
|
|
1431
|
+
return plugin;
|
|
1432
|
+
};
|
|
1433
|
+
};
|
|
1434
|
+
var retry = async (tries, cb) => {
|
|
1435
|
+
let latestError;
|
|
1436
|
+
while (--tries) {
|
|
1437
|
+
try {
|
|
1438
|
+
const result = await cb();
|
|
1439
|
+
return result;
|
|
1440
|
+
} catch (error) {
|
|
1441
|
+
latestError = error;
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
throw latestError;
|
|
1445
|
+
};
|
|
1446
|
+
|
|
1447
|
+
// src/provider.ts
|
|
1448
|
+
import {
|
|
1449
|
+
ResourceNotFound
|
|
1450
|
+
} from "@terraforge/core";
|
|
1451
|
+
|
|
1452
|
+
class TerraformProvider {
|
|
1453
|
+
type;
|
|
1454
|
+
id;
|
|
1455
|
+
createPlugin;
|
|
1456
|
+
config;
|
|
1457
|
+
configured;
|
|
1458
|
+
plugin;
|
|
1459
|
+
constructor(type, id, createPlugin, config) {
|
|
1460
|
+
this.type = type;
|
|
1461
|
+
this.id = id;
|
|
1462
|
+
this.createPlugin = createPlugin;
|
|
1463
|
+
this.config = config;
|
|
1464
|
+
}
|
|
1465
|
+
async configure() {
|
|
1466
|
+
const plugin = await this.prepare();
|
|
1467
|
+
if (!this.configured) {
|
|
1468
|
+
this.configured = plugin.configure(this.config);
|
|
1469
|
+
}
|
|
1470
|
+
await this.configured;
|
|
1471
|
+
return plugin;
|
|
1472
|
+
}
|
|
1473
|
+
prepare() {
|
|
1474
|
+
if (!this.plugin) {
|
|
1475
|
+
this.plugin = this.createPlugin();
|
|
1476
|
+
}
|
|
1477
|
+
return this.plugin;
|
|
1478
|
+
}
|
|
1479
|
+
async destroy() {
|
|
1480
|
+
if (this.plugin) {
|
|
1481
|
+
const plugin = await this.plugin;
|
|
1482
|
+
plugin.stop();
|
|
1483
|
+
this.plugin = undefined;
|
|
1484
|
+
this.configured = undefined;
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
ownResource(id) {
|
|
1488
|
+
return `terraform:${this.type}:${this.id}` === id;
|
|
1489
|
+
}
|
|
1490
|
+
async getResource({ type, state }) {
|
|
1491
|
+
const plugin = await this.configure();
|
|
1492
|
+
const newState = await plugin.readResource(type, state);
|
|
1493
|
+
if (!newState) {
|
|
1494
|
+
throw new ResourceNotFound;
|
|
1495
|
+
}
|
|
1496
|
+
return {
|
|
1497
|
+
version: 0,
|
|
1498
|
+
state: newState
|
|
1499
|
+
};
|
|
1500
|
+
}
|
|
1501
|
+
async createResource({ type, state }) {
|
|
1502
|
+
const plugin = await this.configure();
|
|
1503
|
+
const newState = await plugin.applyResourceChange(type, null, state);
|
|
1504
|
+
return {
|
|
1505
|
+
version: 0,
|
|
1506
|
+
state: newState
|
|
1507
|
+
};
|
|
1508
|
+
}
|
|
1509
|
+
async updateResource({ type, priorState, proposedState }) {
|
|
1510
|
+
const plugin = await this.configure();
|
|
1511
|
+
const { requiresReplace } = await plugin.planResourceChange(type, priorState, proposedState);
|
|
1512
|
+
if (requiresReplace.length > 0) {
|
|
1513
|
+
const formattedAttrs = requiresReplace.map((p) => p.join(".")).join('", "');
|
|
1514
|
+
throw new Error(`Updating the "${formattedAttrs}" properties for the "${type}" resource will require the resource to be replaced.`);
|
|
1515
|
+
}
|
|
1516
|
+
const newState = await plugin.applyResourceChange(type, priorState, proposedState);
|
|
1517
|
+
return {
|
|
1518
|
+
version: 0,
|
|
1519
|
+
state: newState
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
async deleteResource({ type, state }) {
|
|
1523
|
+
const plugin = await this.configure();
|
|
1524
|
+
try {
|
|
1525
|
+
await plugin.applyResourceChange(type, state, null);
|
|
1526
|
+
} catch (error) {
|
|
1527
|
+
try {
|
|
1528
|
+
const newState = await plugin.readResource(type, state);
|
|
1529
|
+
if (!newState) {
|
|
1530
|
+
throw new ResourceNotFound;
|
|
1531
|
+
}
|
|
1532
|
+
} catch (_) {}
|
|
1533
|
+
throw error;
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
async getData({ type, state }) {
|
|
1537
|
+
const plugin = await this.configure();
|
|
1538
|
+
const data = await plugin.readDataSource(type, state);
|
|
1539
|
+
if (!data) {
|
|
1540
|
+
throw new Error(`Data source not found ${type}`);
|
|
1541
|
+
}
|
|
1542
|
+
return {
|
|
1543
|
+
state: data
|
|
1544
|
+
};
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
// src/resource.ts
|
|
1549
|
+
import { createMeta } from "@terraforge/core";
|
|
1550
|
+
import { snakeCase as snakeCase2 } from "change-case";
|
|
1551
|
+
var createNamespaceProxy = (cb, target = {}) => {
|
|
1552
|
+
const cache = new Map;
|
|
1553
|
+
return new Proxy(target, {
|
|
1554
|
+
get(_, key) {
|
|
1555
|
+
if (!cache.has(key)) {
|
|
1556
|
+
cache.set(key, cb(key));
|
|
1557
|
+
}
|
|
1558
|
+
return cache.get(key);
|
|
1559
|
+
},
|
|
1560
|
+
set(_, key) {
|
|
1561
|
+
throw new Error(`Cannot assign to ${key} because it is a read-only property.`);
|
|
1562
|
+
}
|
|
1563
|
+
});
|
|
1564
|
+
};
|
|
1565
|
+
var createClassProxy = (construct, get) => {
|
|
1566
|
+
return new Proxy(class {
|
|
1567
|
+
}, {
|
|
1568
|
+
construct(_, args) {
|
|
1569
|
+
return construct(...args);
|
|
1570
|
+
},
|
|
1571
|
+
get(_, key) {
|
|
1572
|
+
if (key === "get") {
|
|
1573
|
+
return (...args) => {
|
|
1574
|
+
return get(...args);
|
|
1575
|
+
};
|
|
1576
|
+
}
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
});
|
|
1580
|
+
};
|
|
1581
|
+
var createRecursiveProxy = ({
|
|
1582
|
+
resource,
|
|
1583
|
+
dataSource
|
|
1584
|
+
}) => {
|
|
1585
|
+
const createProxy = (names) => {
|
|
1586
|
+
return createNamespaceProxy((name) => {
|
|
1587
|
+
const ns = [...names, name];
|
|
1588
|
+
if (name === name.toLowerCase()) {
|
|
1589
|
+
return createProxy(ns);
|
|
1590
|
+
} else if (name.startsWith("get")) {
|
|
1591
|
+
return (...args) => {
|
|
1592
|
+
return dataSource([...names, name.substring(3)], ...args);
|
|
1593
|
+
};
|
|
1594
|
+
} else {
|
|
1595
|
+
return createClassProxy((...args) => {
|
|
1596
|
+
return resource(ns, ...args);
|
|
1597
|
+
}, (...args) => {
|
|
1598
|
+
return dataSource(ns, ...args);
|
|
1599
|
+
});
|
|
1600
|
+
}
|
|
1601
|
+
});
|
|
1602
|
+
};
|
|
1603
|
+
return createProxy([]);
|
|
1604
|
+
};
|
|
1605
|
+
var createResourceProxy = (name) => {
|
|
1606
|
+
return createRecursiveProxy({
|
|
1607
|
+
resource: (ns, parent, id, input, config) => {
|
|
1608
|
+
const type = snakeCase2(name + "_" + ns.join("_"));
|
|
1609
|
+
const provider = `terraform:${name}:${config?.provider ?? "default"}`;
|
|
1610
|
+
const $ = createMeta("resource", provider, parent, type, id, input, config);
|
|
1611
|
+
const resource = createNamespaceProxy((key) => {
|
|
1612
|
+
if (key === "$") {
|
|
1613
|
+
return $;
|
|
1614
|
+
}
|
|
1615
|
+
return $.output((data) => data[key]);
|
|
1616
|
+
}, { $ });
|
|
1617
|
+
parent.add(resource);
|
|
1618
|
+
return resource;
|
|
1619
|
+
},
|
|
1620
|
+
dataSource: (ns, parent, id, input, config) => {
|
|
1621
|
+
const type = snakeCase2(name + "_" + ns.join("_"));
|
|
1622
|
+
const provider = `terraform:${name}:${config?.provider ?? "default"}`;
|
|
1623
|
+
const $ = createMeta("data", provider, parent, type, id, input, config);
|
|
1624
|
+
const dataSource = createNamespaceProxy((key) => {
|
|
1625
|
+
if (key === "$") {
|
|
1626
|
+
return $;
|
|
1627
|
+
}
|
|
1628
|
+
return $.output((data) => data[key]);
|
|
1629
|
+
}, { $ });
|
|
1630
|
+
parent.add(dataSource);
|
|
1631
|
+
return dataSource;
|
|
1632
|
+
}
|
|
1633
|
+
});
|
|
1634
|
+
};
|
|
1635
|
+
|
|
1636
|
+
// src/api.ts
|
|
1637
|
+
var createTerraformAPI = (props) => {
|
|
1638
|
+
const resource = createResourceProxy(props.namespace);
|
|
1639
|
+
const install = async ({ location }) => {
|
|
1640
|
+
await downloadPlugin({ ...props.provider, location });
|
|
1641
|
+
};
|
|
1642
|
+
const createPlugin = ({ location }) => {
|
|
1643
|
+
return createLazyPlugin({ ...props.provider, location });
|
|
1644
|
+
};
|
|
1645
|
+
return new Proxy(() => {}, {
|
|
1646
|
+
apply(_, _this, [input, config]) {
|
|
1647
|
+
return new TerraformProvider(props.namespace, config?.id ?? "default", createPlugin({ location: config?.location }), input);
|
|
1648
|
+
},
|
|
1649
|
+
get(_, prop) {
|
|
1650
|
+
if (prop === "install") {
|
|
1651
|
+
return install;
|
|
1652
|
+
}
|
|
1653
|
+
return resource;
|
|
1654
|
+
}
|
|
1655
|
+
});
|
|
1656
|
+
};
|
|
1657
|
+
// src/type-gen.ts
|
|
1658
|
+
import { camelCase as camelCase2, pascalCase } from "change-case";
|
|
1659
|
+
var tab = (indent) => {
|
|
1660
|
+
return "\t".repeat(indent);
|
|
1661
|
+
};
|
|
1662
|
+
var generateTypes = (providers, resources, dataSources) => {
|
|
1663
|
+
return [
|
|
1664
|
+
generateImport("c", "@terraforge/core"),
|
|
1665
|
+
generateImport("t", "@terraforge/terraform"),
|
|
1666
|
+
"type _Record<T> = Record<string, T>",
|
|
1667
|
+
generateNamespace(providers, (name, prop, indent) => {
|
|
1668
|
+
const typeName = name.toLowerCase();
|
|
1669
|
+
return `${tab(indent)}export function ${typeName}(props: ${generatePropertyInputConst(prop, indent)}, config?: t.TerraformProviderConfig): t.TerraformProvider`;
|
|
1670
|
+
}),
|
|
1671
|
+
generateNamespace(resources, (name, prop, indent) => {
|
|
1672
|
+
const typeName = pascalCase(name);
|
|
1673
|
+
return [
|
|
1674
|
+
`${tab(indent)}export type ${typeName}Input = ${generatePropertyInputType(prop, indent)}`,
|
|
1675
|
+
`${tab(indent)}export type ${typeName}Output = ${generatePropertyOutputType(prop, indent)}`,
|
|
1676
|
+
`${tab(indent)}export class ${typeName} {`,
|
|
1677
|
+
`${tab(indent + 1)}constructor(parent: c.Group, id: string, props: ${typeName}Input, config?:c.ResourceConfig)`,
|
|
1678
|
+
`${tab(indent + 1)}readonly $: c.ResourceMeta<${typeName}Input, ${typeName}Output>`,
|
|
1679
|
+
generateClassProperties(prop, indent + 1),
|
|
1680
|
+
`${tab(indent)}}`
|
|
1681
|
+
].join(`
|
|
1682
|
+
|
|
1683
|
+
`);
|
|
1684
|
+
}),
|
|
1685
|
+
generateNamespace(dataSources, (name, prop, indent) => {
|
|
1686
|
+
const typeName = pascalCase(name);
|
|
1687
|
+
return [
|
|
1688
|
+
`${tab(indent)}export type Get${typeName}Input = ${generatePropertyInputType(prop, indent)}`,
|
|
1689
|
+
`${tab(indent)}export type Get${typeName}Output = ${generatePropertyOutputType(prop, indent)}`,
|
|
1690
|
+
`${tab(indent)}export const get${typeName}:c.DataSourceFunction<Get${typeName}Input, Get${typeName}Output>`
|
|
1691
|
+
].join(`
|
|
1692
|
+
|
|
1693
|
+
`);
|
|
1694
|
+
})
|
|
1695
|
+
].join(`
|
|
1696
|
+
|
|
1697
|
+
`);
|
|
1698
|
+
};
|
|
1699
|
+
var generateImport = (name, from) => {
|
|
1700
|
+
return `import * as ${name} from '${from}'`;
|
|
1701
|
+
};
|
|
1702
|
+
var generatePropertyInputConst = (prop, indent) => {
|
|
1703
|
+
return generateValue(prop, {
|
|
1704
|
+
depth: 0,
|
|
1705
|
+
indent: indent + 1,
|
|
1706
|
+
wrap: (v, _, ctx) => {
|
|
1707
|
+
return `${v}${ctx.depth === 1 ? "," : ""}`;
|
|
1708
|
+
},
|
|
1709
|
+
filter: () => true,
|
|
1710
|
+
optional: (p) => p.optional ?? false
|
|
1711
|
+
});
|
|
1712
|
+
};
|
|
1713
|
+
var generatePropertyInputType = (prop, indent) => {
|
|
1714
|
+
return generateValue(prop, {
|
|
1715
|
+
depth: 0,
|
|
1716
|
+
indent: indent + 1,
|
|
1717
|
+
wrap: (v, p, ctx) => {
|
|
1718
|
+
return ctx.depth > 0 ? p.optional ? `c.OptionalInput<${v}>` : `c.Input<${v}>` : v;
|
|
1719
|
+
},
|
|
1720
|
+
filter: (prop2) => !(prop2.computed && typeof prop2.optional === "undefined" && typeof prop2.required === "undefined"),
|
|
1721
|
+
optional: (p) => p.optional ?? false
|
|
1722
|
+
});
|
|
1723
|
+
};
|
|
1724
|
+
var generatePropertyOutputType = (prop, indent) => {
|
|
1725
|
+
return generateValue(prop, {
|
|
1726
|
+
indent: indent + 1,
|
|
1727
|
+
depth: 0,
|
|
1728
|
+
wrap: (v, p, ctx) => ctx.depth === 1 ? p.optional && !p.computed ? `c.OptionalOutput<${v}>` : `c.Output<${v}>` : v,
|
|
1729
|
+
filter: () => true,
|
|
1730
|
+
readonly: true,
|
|
1731
|
+
optional: (p, ctx) => ctx.depth > 1 && p.optional && !p.computed || false
|
|
1732
|
+
});
|
|
1733
|
+
};
|
|
1734
|
+
var generateClassProperties = (prop, indent) => {
|
|
1735
|
+
if (prop.type !== "object") {
|
|
1736
|
+
return "";
|
|
1737
|
+
}
|
|
1738
|
+
return Object.entries(prop.properties).map(([name, prop2]) => {
|
|
1739
|
+
return [
|
|
1740
|
+
prop2.description ? [`
|
|
1741
|
+
`, ` `.repeat(indent), `/** `, prop2.description.trim(), " */", `
|
|
1742
|
+
`].join("") : "",
|
|
1743
|
+
` `.repeat(indent),
|
|
1744
|
+
"readonly ",
|
|
1745
|
+
camelCase2(name),
|
|
1746
|
+
": ",
|
|
1747
|
+
generateValue(prop2, {
|
|
1748
|
+
readonly: true,
|
|
1749
|
+
filter: () => true,
|
|
1750
|
+
optional: (p, ctx) => ctx.depth > 1 && p.optional && !p.computed || false,
|
|
1751
|
+
wrap: (v, p, ctx) => {
|
|
1752
|
+
return ctx.depth === 1 ? p.optional && !p.computed ? `c.OptionalOutput<${v}>` : `c.Output<${v}>` : v;
|
|
1753
|
+
},
|
|
1754
|
+
indent: indent + 1,
|
|
1755
|
+
depth: 1
|
|
1756
|
+
})
|
|
1757
|
+
].join("");
|
|
1758
|
+
}).join(`
|
|
1759
|
+
`);
|
|
1760
|
+
};
|
|
1761
|
+
var groupByNamespace = (resources, minLevel, maxLevel) => {
|
|
1762
|
+
const grouped = {};
|
|
1763
|
+
const types = Object.keys(resources).sort();
|
|
1764
|
+
for (const type of types) {
|
|
1765
|
+
const names = type.split("_");
|
|
1766
|
+
if (names.length < minLevel) {
|
|
1767
|
+
throw new Error(`Resource not properly namespaced: ${type}`);
|
|
1768
|
+
}
|
|
1769
|
+
let current = grouped;
|
|
1770
|
+
let count = Math.min(maxLevel, names.length - 1);
|
|
1771
|
+
while (count--) {
|
|
1772
|
+
const ns = camelCase2(names.shift());
|
|
1773
|
+
if (!current[ns]) {
|
|
1774
|
+
current[ns] = {};
|
|
1775
|
+
}
|
|
1776
|
+
current = current[ns];
|
|
1777
|
+
}
|
|
1778
|
+
const name = pascalCase(names.join("_"));
|
|
1779
|
+
current[name] = type;
|
|
1780
|
+
}
|
|
1781
|
+
return grouped;
|
|
1782
|
+
};
|
|
1783
|
+
var generateNamespace = (resources, render) => {
|
|
1784
|
+
const grouped = groupByNamespace(resources, 1, 2);
|
|
1785
|
+
const renderNamespace = (name, group, indent) => {
|
|
1786
|
+
if (name === "default") {
|
|
1787
|
+
name = "$default";
|
|
1788
|
+
}
|
|
1789
|
+
return [
|
|
1790
|
+
`${tab(indent)}export ${indent === 0 ? "declare " : ""}namespace ${name.toLowerCase()} {`,
|
|
1791
|
+
Object.entries(group).map(([name2, entry]) => {
|
|
1792
|
+
if (typeof entry !== "string") {
|
|
1793
|
+
return renderNamespace(name2, entry, indent + 1);
|
|
1794
|
+
} else {
|
|
1795
|
+
return render(name2, resources[entry], indent + 1);
|
|
1796
|
+
}
|
|
1797
|
+
}).join(`
|
|
1798
|
+
`),
|
|
1799
|
+
`${tab(indent)}}`
|
|
1800
|
+
].join(`
|
|
1801
|
+
`);
|
|
1802
|
+
};
|
|
1803
|
+
return renderNamespace("root", grouped, 0);
|
|
1804
|
+
};
|
|
1805
|
+
var generateValue = (prop, ctx) => {
|
|
1806
|
+
if (["string", "number", "boolean", "unknown"].includes(prop.type)) {
|
|
1807
|
+
return ctx.wrap(prop.type, prop, ctx);
|
|
1808
|
+
}
|
|
1809
|
+
if (prop.type === "array") {
|
|
1810
|
+
const type = generateValue(prop.item, { ...ctx, depth: ctx.depth + 1 });
|
|
1811
|
+
const array = ctx.readonly ? `ReadonlyArray<${type}>` : `Array<${type}>`;
|
|
1812
|
+
return ctx.wrap(array, prop, ctx);
|
|
1813
|
+
}
|
|
1814
|
+
if (prop.type === "record") {
|
|
1815
|
+
const type = generateValue(prop.item, { ...ctx, depth: ctx.depth + 1 });
|
|
1816
|
+
const record = ctx.readonly ? `Readonly<_Record<${type}>>` : `_Record<${type}>`;
|
|
1817
|
+
return ctx.wrap(record, prop, ctx);
|
|
1818
|
+
}
|
|
1819
|
+
if (prop.type === "object" || prop.type === "array-object") {
|
|
1820
|
+
const type = [
|
|
1821
|
+
"{",
|
|
1822
|
+
Object.entries(prop.properties).filter(([_, p]) => ctx.filter(p)).map(([name, prop2]) => [
|
|
1823
|
+
prop2.description ? [`
|
|
1824
|
+
`, ` `.repeat(ctx.indent), `/** `, prop2.description.trim(), " */", `
|
|
1825
|
+
`].join("") : "",
|
|
1826
|
+
` `.repeat(ctx.indent),
|
|
1827
|
+
camelCase2(name),
|
|
1828
|
+
ctx.optional(prop2, ctx) ? "?" : "",
|
|
1829
|
+
": ",
|
|
1830
|
+
generateValue(prop2, { ...ctx, indent: ctx.indent + 1, depth: ctx.depth + 1 })
|
|
1831
|
+
].join("")).join(`
|
|
1832
|
+
`),
|
|
1833
|
+
`${` `.repeat(ctx.indent - 1)}}`
|
|
1834
|
+
].join(`
|
|
1835
|
+
`);
|
|
1836
|
+
const object = ctx.readonly ? `Readonly<${type}>` : type;
|
|
1837
|
+
return ctx.wrap(object, prop, ctx);
|
|
1838
|
+
}
|
|
1839
|
+
throw new Error(`Unknown property type: ${prop.type}`);
|
|
1840
|
+
};
|
|
1841
|
+
export {
|
|
1842
|
+
generateTypes,
|
|
1843
|
+
createTerraformAPI,
|
|
1844
|
+
TerraformProvider
|
|
1845
|
+
};
|