@gershy/lilac 0.0.12 → 0.0.13
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/cmp/cjs/main.d.ts +16 -29
- package/cmp/cjs/main.js +114 -145
- package/cmp/cjs/petal/terraform/terraform.d.ts +4 -4
- package/cmp/cjs/petal/terraform/terraform.js +6 -6
- package/cmp/cjs/soil/soil.d.ts +79 -0
- package/cmp/cjs/soil/soil.js +291 -0
- package/cmp/cjs/util/aws.d.ts +18 -4
- package/cmp/cjs/util/aws.js +4 -1
- package/cmp/cjs/util/procTerraform.d.ts +8 -6
- package/cmp/cjs/util/procTerraform.js +6 -5
- package/cmp/cjs/util/superIterable.d.ts +1 -0
- package/cmp/cjs/util/superIterable.js +2 -0
- package/cmp/cjs/util/terraform.js +1 -0
- package/cmp/mjs/main.d.ts +16 -29
- package/cmp/mjs/main.js +114 -145
- package/cmp/mjs/petal/terraform/terraform.d.ts +4 -4
- package/cmp/mjs/petal/terraform/terraform.js +6 -6
- package/cmp/mjs/soil/soil.d.ts +79 -0
- package/cmp/mjs/soil/soil.js +285 -0
- package/cmp/mjs/util/aws.d.ts +18 -4
- package/cmp/mjs/util/aws.js +4 -1
- package/cmp/mjs/util/procTerraform.d.ts +8 -6
- package/cmp/mjs/util/procTerraform.js +6 -5
- package/cmp/mjs/util/superIterable.d.ts +1 -0
- package/cmp/mjs/util/superIterable.js +1 -0
- package/cmp/mjs/util/terraform.js +1 -0
- package/package.json +6 -3
- package/cmp/cjs/util/mockAws.d.ts +0 -13
- package/cmp/cjs/util/mockAws.js +0 -39
- package/cmp/cjs/util/tryWithHealing.d.ts +0 -7
- package/cmp/cjs/util/tryWithHealing.js +0 -11
- package/cmp/mjs/util/mockAws.d.ts +0 -13
- package/cmp/mjs/util/mockAws.js +0 -34
- package/cmp/mjs/util/tryWithHealing.d.ts +0 -7
- package/cmp/mjs/util/tryWithHealing.js +0 -9
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Soil = void 0;
|
|
7
|
+
const disk_1 = require("@gershy/disk");
|
|
8
|
+
const nodejs_proc_1 = __importDefault(require("@gershy/nodejs-proc"));
|
|
9
|
+
const main_ts_1 = require("../main.js");
|
|
10
|
+
const util_retry_1 = __importDefault(require("@gershy/util-retry"));
|
|
11
|
+
const clearing_1 = require("@gershy/clearing");
|
|
12
|
+
const util_http_1 = __importDefault(require("@gershy/util-http"));
|
|
13
|
+
const aws_ts_1 = require("../util/aws.js");
|
|
14
|
+
var Soil;
|
|
15
|
+
(function (Soil) {
|
|
16
|
+
class Base {
|
|
17
|
+
registry;
|
|
18
|
+
constructor(args) {
|
|
19
|
+
this.registry = args.registry;
|
|
20
|
+
}
|
|
21
|
+
async getTerraformPetals(ctx) {
|
|
22
|
+
throw Error('not implemented');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
Soil.Base = Base;
|
|
26
|
+
;
|
|
27
|
+
class LocalStack extends Base {
|
|
28
|
+
static localStackInternalPort = 4566;
|
|
29
|
+
aws;
|
|
30
|
+
localStackDocker;
|
|
31
|
+
procArgs;
|
|
32
|
+
constructor(args) {
|
|
33
|
+
super(args);
|
|
34
|
+
this.aws = args.aws;
|
|
35
|
+
this.localStackDocker = {
|
|
36
|
+
image: 'localstack/localstack:latest',
|
|
37
|
+
port: LocalStack.localStackInternalPort,
|
|
38
|
+
containerName: 'gershyLilacLocalStack'
|
|
39
|
+
}[merge](args.localStackDocker ?? {});
|
|
40
|
+
this.procArgs = { cwd: disk_1.rootFact, env: process.env };
|
|
41
|
+
}
|
|
42
|
+
getAwsServices() {
|
|
43
|
+
// Note that "overhead" services are essential for initializing localstack:
|
|
44
|
+
// - s3 + ddb used for terraform state locking
|
|
45
|
+
// - sts is used for credential validation
|
|
46
|
+
// - iam is needed for role creation
|
|
47
|
+
const overheadAwsServices = ['s3', 'dynamodb', 'sts', 'iam'];
|
|
48
|
+
return new Set([...overheadAwsServices, ...this.registry.getAwsServices()]);
|
|
49
|
+
}
|
|
50
|
+
async getDockerContainers() {
|
|
51
|
+
const { containerName } = this.localStackDocker;
|
|
52
|
+
const dockerPs = await (0, nodejs_proc_1.default)(`docker ps -a --filter "name=${containerName}" --format "{{.Names}},{{.State}}"`, this.procArgs);
|
|
53
|
+
return dockerPs
|
|
54
|
+
.output
|
|
55
|
+
.split('\n')[map](v => v.trim() || clearing_1.skip)[map](v => v[cut](',', 1))[map](([name, state]) => ({ name, state }))
|
|
56
|
+
// Exclude containers which match the `docker ps` filter but don't have the prefix
|
|
57
|
+
[map](v => (v.name === containerName || v.name[hasHead](`${containerName}-`)) ? v : clearing_1.skip);
|
|
58
|
+
}
|
|
59
|
+
run(args) {
|
|
60
|
+
return args.logger.scope('localStack', {}, async (logger) => {
|
|
61
|
+
// Run a localStack container in docker, enabling `terraform apply` on an aws-like target
|
|
62
|
+
const { image, port, containerName } = this.localStackDocker;
|
|
63
|
+
const awsServices = this.getAwsServices();
|
|
64
|
+
await logger.scope('dockerDeploy', { image, containerName, port }, async (logger) => {
|
|
65
|
+
await (0, nodejs_proc_1.default)('docker info', this.procArgs).catch(({ output }) => Error('docker unavailable')[fire]({ output }));
|
|
66
|
+
logger.log({ $$: 'dockerActive' });
|
|
67
|
+
const containers = await this.getDockerContainers();
|
|
68
|
+
let state = containers.find(c => c.name === containerName)?.state ?? 'nonexistent';
|
|
69
|
+
// First if a container already exists ensure it's compatible with our given config
|
|
70
|
+
if (['running', 'paused', 'exited'][has](state)) {
|
|
71
|
+
const isExistingContainerReusable = await (async () => {
|
|
72
|
+
const { output: inspectJson } = await (0, nodejs_proc_1.default)(`docker inspect ${containerName}`, this.procArgs);
|
|
73
|
+
const [containerInfo] = JSON.parse(inspectJson);
|
|
74
|
+
console.log('DOCKER INSPECT', containerInfo);
|
|
75
|
+
const containerImage = containerInfo.Config.Image;
|
|
76
|
+
const containerEnv = containerInfo.Config.Env[toObj](v => v[cut]('=', 1));
|
|
77
|
+
const containerPort = Number(containerInfo.HostConfig.PortBindings[`${LocalStack.localStackInternalPort}/tcp`]?.[0]?.HostPort ?? 0);
|
|
78
|
+
const services = (containerEnv.SERVICES ?? '').split(',').sort().join(',');
|
|
79
|
+
return true
|
|
80
|
+
&& containerImage === image
|
|
81
|
+
&& containerPort === port
|
|
82
|
+
&& containerEnv.DEFAULT_REGION === this.aws.region
|
|
83
|
+
&& services === awsServices[toArr](v => v).sort().join(',');
|
|
84
|
+
})();
|
|
85
|
+
if (isExistingContainerReusable) {
|
|
86
|
+
if (state === 'paused')
|
|
87
|
+
await (0, nodejs_proc_1.default)(`docker unpause ${containerName}`, this.procArgs);
|
|
88
|
+
if (state === 'exited')
|
|
89
|
+
await (0, nodejs_proc_1.default)(`docker start ${containerName}`, this.procArgs);
|
|
90
|
+
logger.log({ $$: 'containerReused' });
|
|
91
|
+
state = 'running';
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
await this.end({ containers });
|
|
95
|
+
logger.log({ $$: 'previousLocalStackRemoved', containers });
|
|
96
|
+
state = 'nonexistent';
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (state === 'nonexistent') {
|
|
100
|
+
const runCmd = String[baseline](`
|
|
101
|
+
| docker run
|
|
102
|
+
| --rm
|
|
103
|
+
| -d
|
|
104
|
+
| --privileged${'' /* TODO: consider removing? */}
|
|
105
|
+
| --name ${containerName}
|
|
106
|
+
| -p ${port}:${LocalStack.localStackInternalPort}
|
|
107
|
+
| -v /var/run/docker.sock:/var/run/docker.sock
|
|
108
|
+
| -e SERVICES=${awsServices[toArr](v => v).join(',')}
|
|
109
|
+
| -e DEFAULT_REGION=${this.aws.region}
|
|
110
|
+
| ${image}
|
|
111
|
+
`).split('\n')[map](ln => ln.trim() || clearing_1.skip).join(' ');
|
|
112
|
+
await (0, nodejs_proc_1.default)(runCmd, this.procArgs);
|
|
113
|
+
state = 'running';
|
|
114
|
+
}
|
|
115
|
+
if (state !== 'running')
|
|
116
|
+
throw Error('container state unexpected')[mod]({ state });
|
|
117
|
+
});
|
|
118
|
+
const readyEndpoint = {
|
|
119
|
+
$req: null,
|
|
120
|
+
$res: null,
|
|
121
|
+
netProc: { proto: 'http', addr: 'localhost', port },
|
|
122
|
+
path: ['_localstack', 'health'],
|
|
123
|
+
method: 'get'
|
|
124
|
+
};
|
|
125
|
+
const { val: { services } } = await (0, util_retry_1.default)({
|
|
126
|
+
// TODO: If the container already exists, it seems its "s3" and "sts" services become unavailable when we try to reinitialize Soil pointing at it??
|
|
127
|
+
attempts: 20,
|
|
128
|
+
delay: n => Math.min(500, 50 * n),
|
|
129
|
+
fn: async () => {
|
|
130
|
+
// Retry all failures and non-200s
|
|
131
|
+
const res = await (0, util_http_1.default)(readyEndpoint, {}).catch(err => err[fire]({ retry: true }));
|
|
132
|
+
if (res.code !== 200)
|
|
133
|
+
throw Error('unhealthy')[mod]({ retry: true });
|
|
134
|
+
const { ya = [], no = [] } = res.body.services[group](v => v === 'available' ? 'ya' : 'no')[map](group => group[toArr]((v, k) => k));
|
|
135
|
+
const missingServices = no[map](svc => awsServices.has(svc) ? svc : clearing_1.skip);
|
|
136
|
+
if (missingServices.length)
|
|
137
|
+
throw Error('services unavailable')[mod]({ missingServices })[mod]({ retry: true });
|
|
138
|
+
return { services: ya };
|
|
139
|
+
},
|
|
140
|
+
retryable: err => !!err.retry,
|
|
141
|
+
}).catch(err => err[fire]({ numErrs: err.errs.length, errs: null }));
|
|
142
|
+
logger.log({ $$: 'localStackActive', services });
|
|
143
|
+
return {
|
|
144
|
+
aws: { services: [...awsServices], region: this.aws.region, },
|
|
145
|
+
netProc: { proto: 'http', addr: 'localhost', port },
|
|
146
|
+
url: `http://localhost:${port}`
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
async end(args) {
|
|
151
|
+
const containers = args?.containers ?? await this.getDockerContainers();
|
|
152
|
+
await (0, nodejs_proc_1.default)(`docker rm -f ${containers.map(c => c.name).join(' ')}`, this.procArgs)
|
|
153
|
+
.catch(err => {
|
|
154
|
+
console.log('ERROR ENDING LOCALSTACK DOCKER CONTAINER:\n', err.output);
|
|
155
|
+
return;
|
|
156
|
+
});
|
|
157
|
+
return containers;
|
|
158
|
+
}
|
|
159
|
+
async getTerraformPetals(ctx) {
|
|
160
|
+
const { aws } = this;
|
|
161
|
+
const awsServices = [...this.getAwsServices()];
|
|
162
|
+
const netProc = { proto: 'http', addr: 'localhost', port: this.localStackDocker.port };
|
|
163
|
+
const localStackUrl = `${netProc.proto}://${netProc.addr}:${netProc.port}`;
|
|
164
|
+
return {
|
|
165
|
+
boot: () => [
|
|
166
|
+
new main_ts_1.PetalTerraform.Terraform({
|
|
167
|
+
$requiredProviders: {
|
|
168
|
+
aws: {
|
|
169
|
+
source: 'hashicorp/aws',
|
|
170
|
+
version: `~> 5.0`
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}),
|
|
174
|
+
new main_ts_1.PetalTerraform.Provider('aws', {
|
|
175
|
+
region: aws.region,
|
|
176
|
+
skipCredentialsValidation: true,
|
|
177
|
+
skipRequestingAccountId: true,
|
|
178
|
+
s3UsePathStyle: true, // Otherwise requests can go to "bucket.s3.amazonaws.com", outside localStack
|
|
179
|
+
// Note our localStack setup always includes s3 and ddb (required for tf state storage)
|
|
180
|
+
$endpoints: awsServices[toObj](svc => [svc, localStackUrl])
|
|
181
|
+
})
|
|
182
|
+
],
|
|
183
|
+
main: function* (args) {
|
|
184
|
+
yield new main_ts_1.PetalTerraform.Terraform({
|
|
185
|
+
$requiredProviders: {
|
|
186
|
+
aws: {
|
|
187
|
+
source: 'hashicorp/aws',
|
|
188
|
+
version: `~> 5.0` // Consider parameterizing??
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
'$backend.s3': {
|
|
192
|
+
region: aws.region,
|
|
193
|
+
encrypt: true,
|
|
194
|
+
bucket: args.s3Name,
|
|
195
|
+
key: `tf`,
|
|
196
|
+
dynamodbTable: args.ddbName,
|
|
197
|
+
usePathStyle: true,
|
|
198
|
+
// Point the S3 backend at LocalStack when testing
|
|
199
|
+
endpoints: awsServices[toObj](svc => [svc, localStackUrl]),
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
for (const { term } of aws_ts_1.regions)
|
|
203
|
+
yield new main_ts_1.PetalTerraform.Provider('aws', {
|
|
204
|
+
region: term,
|
|
205
|
+
skipCredentialsValidation: true,
|
|
206
|
+
skipRequestingAccountId: true,
|
|
207
|
+
// Omit the alias for the default provider!
|
|
208
|
+
...(term !== aws.region && { alias: term.split('-').join('_') }),
|
|
209
|
+
// Point providers at LocalStack when testing
|
|
210
|
+
s3UsePathStyle: true,
|
|
211
|
+
$endpoints: awsServices[toObj](svc => [svc, localStackUrl])
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
Soil.LocalStack = LocalStack;
|
|
218
|
+
;
|
|
219
|
+
class AwsCloud extends Base {
|
|
220
|
+
aws;
|
|
221
|
+
constructor(args) {
|
|
222
|
+
super(args);
|
|
223
|
+
this.aws = args.aws;
|
|
224
|
+
}
|
|
225
|
+
async getTerraformPetals(ctx) {
|
|
226
|
+
const { aws } = this;
|
|
227
|
+
return {
|
|
228
|
+
boot: function* () {
|
|
229
|
+
const tfAwsCredsFile = new main_ts_1.PetalTerraform.File('creds.ini', String[baseline](`
|
|
230
|
+
| [default]
|
|
231
|
+
| aws_region = ${aws.region}
|
|
232
|
+
| aws_access_key_id = ${aws.accessKey.id}
|
|
233
|
+
| aws_secret_access_key = ${aws.accessKey['!secret']}
|
|
234
|
+
`));
|
|
235
|
+
yield tfAwsCredsFile;
|
|
236
|
+
yield new main_ts_1.PetalTerraform.Terraform({
|
|
237
|
+
$requiredProviders: {
|
|
238
|
+
aws: {
|
|
239
|
+
source: 'hashicorp/aws',
|
|
240
|
+
version: `~> 5.0`
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
yield new main_ts_1.PetalTerraform.Provider('aws', {
|
|
245
|
+
sharedCredentialsFiles: [tfAwsCredsFile.refStr()],
|
|
246
|
+
profile: 'default', // References a section within the credentials file
|
|
247
|
+
region: aws.region,
|
|
248
|
+
});
|
|
249
|
+
},
|
|
250
|
+
main: function* (args) {
|
|
251
|
+
const credFileProfile = 'default';
|
|
252
|
+
const tfAwsCredsFile = new main_ts_1.PetalTerraform.File('creds.ini', String[baseline](`
|
|
253
|
+
| [${credFileProfile}]
|
|
254
|
+
| aws_region = ${aws.region}
|
|
255
|
+
| aws_access_key_id = ${aws.accessKey.id}
|
|
256
|
+
| aws_secret_access_key = ${aws.accessKey['!secret']}
|
|
257
|
+
`));
|
|
258
|
+
yield tfAwsCredsFile;
|
|
259
|
+
yield new main_ts_1.PetalTerraform.Terraform({
|
|
260
|
+
$requiredProviders: {
|
|
261
|
+
aws: {
|
|
262
|
+
source: 'hashicorp/aws',
|
|
263
|
+
version: `~> 5.0` // Consider parameterizing??
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
'$backend.s3': {
|
|
267
|
+
sharedCredentialsFiles: [tfAwsCredsFile.refStr()],
|
|
268
|
+
profile: credFileProfile,
|
|
269
|
+
region: aws.region,
|
|
270
|
+
encrypt: true,
|
|
271
|
+
bucket: args.s3Name,
|
|
272
|
+
key: `tf`,
|
|
273
|
+
dynamodbTable: args.ddbName
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
for (const { term } of aws_ts_1.regions)
|
|
277
|
+
yield new main_ts_1.PetalTerraform.Provider('aws', {
|
|
278
|
+
sharedCredentialsFiles: [tfAwsCredsFile.refStr()],
|
|
279
|
+
profile: credFileProfile,
|
|
280
|
+
region: term,
|
|
281
|
+
// Omit the alias for the default provider!
|
|
282
|
+
...(term !== aws.region && { alias: term.split('-').join('_') }),
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
Soil.AwsCloud = AwsCloud;
|
|
289
|
+
;
|
|
290
|
+
})(Soil || (exports.Soil = Soil = {}));
|
|
291
|
+
;
|
package/cmp/cjs/util/aws.d.ts
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
export declare const capitalKeys: (v: any) => any;
|
|
2
|
-
export declare const regions: {
|
|
3
|
-
term:
|
|
4
|
-
mini:
|
|
5
|
-
}
|
|
2
|
+
export declare const regions: readonly [{
|
|
3
|
+
term: "ca-central-1" | "us-east-1" | "us-east-2" | "us-west-1" | "us-west-2";
|
|
4
|
+
mini: `${"ca" | "us"}${"c" | "u"}${"c" | "u" | "e" | "w"}${"1" | "2"}`;
|
|
5
|
+
}, {
|
|
6
|
+
term: "ca-central-1" | "us-east-1" | "us-east-2" | "us-west-1" | "us-west-2";
|
|
7
|
+
mini: `${"ca" | "us"}${"c" | "u"}${"c" | "u" | "e" | "w"}${"1" | "2"}`;
|
|
8
|
+
}, {
|
|
9
|
+
term: "ca-central-1" | "us-east-1" | "us-east-2" | "us-west-1" | "us-west-2";
|
|
10
|
+
mini: `${"ca" | "us"}${"c" | "u"}${"c" | "u" | "e" | "w"}${"1" | "2"}`;
|
|
11
|
+
}, {
|
|
12
|
+
term: "ca-central-1" | "us-east-1" | "us-east-2" | "us-west-1" | "us-west-2";
|
|
13
|
+
mini: `${"ca" | "us"}${"c" | "u"}${"c" | "u" | "e" | "w"}${"1" | "2"}`;
|
|
14
|
+
}, {
|
|
15
|
+
term: "ca-central-1" | "us-east-1" | "us-east-2" | "us-west-1" | "us-west-2";
|
|
16
|
+
mini: `${"ca" | "us"}${"c" | "u"}${"c" | "u" | "e" | "w"}${"1" | "2"}`;
|
|
17
|
+
}];
|
|
18
|
+
export type RegionTerm = (typeof regions)[number]['term'];
|
|
19
|
+
export type RegionMini = (typeof regions)[number]['mini'];
|
package/cmp/cjs/util/aws.js
CHANGED
|
@@ -57,5 +57,8 @@ exports.regions = [
|
|
|
57
57
|
][map](region => {
|
|
58
58
|
const [c, z, num] = region.split('-');
|
|
59
59
|
const [dir0, dir1 = dir0] = z.match(/central|north|south|east|west/g);
|
|
60
|
-
return {
|
|
60
|
+
return {
|
|
61
|
+
term: region,
|
|
62
|
+
mini: [c, dir0[0], dir1[0], num].join('')
|
|
63
|
+
};
|
|
61
64
|
});
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ProcOpts } from '@gershy/
|
|
3
|
-
type
|
|
4
|
-
declare const _default: (fact: Fact, cmd: string, opts?:
|
|
5
|
-
logDb:
|
|
1
|
+
import { Fact } from '@gershy/disk';
|
|
2
|
+
import { ProcOpts } from '@gershy/nodejs-proc';
|
|
3
|
+
export type ProcTerraformArgs = ProcOpts & {};
|
|
4
|
+
declare const _default: (fact: Fact, cmd: string, opts?: ProcTerraformArgs) => Promise<{
|
|
5
|
+
logDb: Fact;
|
|
6
6
|
output: string;
|
|
7
|
-
}
|
|
7
|
+
}> & {
|
|
8
|
+
proc: import("child_process").ChildProcessWithoutNullStreams;
|
|
9
|
+
};
|
|
8
10
|
export default _default;
|
|
@@ -3,8 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const
|
|
7
|
-
exports.default = (fact, cmd, opts) => {
|
|
6
|
+
const nodejs_proc_1 = __importDefault(require("@gershy/nodejs-proc"));
|
|
7
|
+
exports.default = (fact, cmd, opts = {}) => {
|
|
8
8
|
const numTailingTfLogLines = 20;
|
|
9
9
|
const writeLog = async (result) => {
|
|
10
10
|
const [yr, mo, dy, hr, mn, sc, ms] = new Date().toISOString().match(/([0-9]{4})[-]([0-9]{2})[-]([0-9]{2})[T]([0-9]{2})[:]([0-9]{2})[:]([0-9]{2})[.]([0-9]+)[Z]/).slice(1);
|
|
@@ -13,12 +13,13 @@ exports.default = (fact, cmd, opts) => {
|
|
|
13
13
|
await logDb.setData(result);
|
|
14
14
|
return logDb;
|
|
15
15
|
};
|
|
16
|
-
|
|
16
|
+
const prm = (0, nodejs_proc_1.default)(cmd, {
|
|
17
17
|
timeoutMs: 0,
|
|
18
18
|
...opts,
|
|
19
19
|
cwd: fact,
|
|
20
20
|
env: { TF_DATA_DIR: '' }
|
|
21
|
-
})
|
|
21
|
+
});
|
|
22
|
+
return Object.assign(prm.then(async (result) => {
|
|
22
23
|
const logDb = await writeLog(result.output);
|
|
23
24
|
return { logDb, output: result.output.split('\n').slice(-numTailingTfLogLines).join('\n') };
|
|
24
25
|
}, async (err) => {
|
|
@@ -27,5 +28,5 @@ exports.default = (fact, cmd, opts) => {
|
|
|
27
28
|
logDb,
|
|
28
29
|
...(err.output ? { output: err.output.split('\n').slice(-numTailingTfLogLines).join('\n') } : { cause: err })
|
|
29
30
|
});
|
|
30
|
-
});
|
|
31
|
+
}), { proc: prm.proc });
|
|
31
32
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type SuperIterable<T> = Iterable<T> | Promise<Iterable<T>> | AsyncIterable<T>;
|
package/cmp/mjs/main.d.ts
CHANGED
|
@@ -2,27 +2,22 @@ import '../sideEffects.js';
|
|
|
2
2
|
import { PetalTerraform } from './petal/terraform/terraform.ts';
|
|
3
3
|
import Logger from '@gershy/logger';
|
|
4
4
|
import { Fact } from '@gershy/disk';
|
|
5
|
+
import { Soil } from './soil/soil.ts';
|
|
6
|
+
import { SuperIterable } from './util/superIterable.ts';
|
|
5
7
|
export type Context = {
|
|
6
8
|
name: string;
|
|
7
9
|
logger: Logger;
|
|
8
10
|
fact: Fact;
|
|
9
11
|
patioFact: Fact;
|
|
10
|
-
aws: {
|
|
11
|
-
accountId: string;
|
|
12
|
-
accessKey: {
|
|
13
|
-
id: string;
|
|
14
|
-
'!secret': string;
|
|
15
|
-
};
|
|
16
|
-
region: string;
|
|
17
|
-
};
|
|
18
12
|
maturity: string;
|
|
19
13
|
debug: boolean;
|
|
20
14
|
pfx: string;
|
|
21
15
|
};
|
|
22
16
|
export declare class Flower {
|
|
17
|
+
static getAwsServices(): Soil.LocalStackAwsService[];
|
|
23
18
|
constructor();
|
|
24
19
|
getDependencies(): Generator<Flower>;
|
|
25
|
-
getPetals(ctx: Context):
|
|
20
|
+
getPetals(ctx: Context): SuperIterable<PetalTerraform.Base>;
|
|
26
21
|
}
|
|
27
22
|
type RegistryFlowers<R extends Registry<any>, M extends 'real' | 'test'> = R extends Registry<infer Flowers> ? {
|
|
28
23
|
[K in keyof Flowers]: Flowers[K][M];
|
|
@@ -33,6 +28,7 @@ export declare class Registry<Flowers extends Obj<{
|
|
|
33
28
|
}> = Obj<never>> {
|
|
34
29
|
private flowers;
|
|
35
30
|
constructor(flowers: Flowers);
|
|
31
|
+
getAwsServices(): Soil.LocalStackAwsService[];
|
|
36
32
|
add<MoreFlowers extends Obj<{
|
|
37
33
|
real: typeof Flower;
|
|
38
34
|
test: typeof Flower;
|
|
@@ -41,32 +37,23 @@ export declare class Registry<Flowers extends Obj<{
|
|
|
41
37
|
}
|
|
42
38
|
export declare class Garden<Reg extends Registry<any>> {
|
|
43
39
|
private ctx;
|
|
44
|
-
private
|
|
45
|
-
private
|
|
40
|
+
private reg;
|
|
41
|
+
private def;
|
|
46
42
|
constructor(args: {
|
|
47
|
-
|
|
48
|
-
logger: Logger;
|
|
49
|
-
fact: Fact;
|
|
50
|
-
patioFact: Fact;
|
|
51
|
-
aws: {
|
|
52
|
-
accountId: string;
|
|
53
|
-
accessKey: {
|
|
54
|
-
id: string;
|
|
55
|
-
'!secret': string;
|
|
56
|
-
};
|
|
57
|
-
region: string;
|
|
58
|
-
};
|
|
59
|
-
maturity: string;
|
|
60
|
-
debug: boolean;
|
|
61
|
-
pfx: string;
|
|
43
|
+
context: Context;
|
|
62
44
|
registry: Reg;
|
|
63
|
-
define: Garden<Reg>['
|
|
45
|
+
define: Garden<Reg>['def'];
|
|
64
46
|
});
|
|
65
47
|
private getPetals;
|
|
66
|
-
|
|
48
|
+
genTerraform(deployTarget: Soil.Base): Promise<Obj<Fact>>;
|
|
67
49
|
private terraformInit;
|
|
68
50
|
private terraformPlan;
|
|
69
51
|
private terraformApply;
|
|
70
|
-
grow(
|
|
52
|
+
grow(deploy: {
|
|
53
|
+
type: 'real';
|
|
54
|
+
soil: Soil.Base;
|
|
55
|
+
} | {
|
|
56
|
+
type: 'test';
|
|
57
|
+
}): Promise<void>;
|
|
71
58
|
}
|
|
72
59
|
export * from './petal/terraform/terraform.ts';
|