@agilecustoms/envctl 1.15.0 → 1.15.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/dist/client/Cli.js +8 -8
- package/dist/service/TerraformAdapter.js +14 -32
- package/package.json +1 -1
package/dist/client/Cli.js
CHANGED
|
@@ -14,15 +14,15 @@ export const NO_TIMEOUT = 0;
|
|
|
14
14
|
export class Cli {
|
|
15
15
|
constructor() {
|
|
16
16
|
}
|
|
17
|
-
async run(command, args,
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
};
|
|
17
|
+
async run(command, args, options = {}) {
|
|
18
|
+
const timeoutMs = options.timeoutMs ?? NO_TIMEOUT;
|
|
19
|
+
const interactive = options.interactive ?? !!options.inScanner;
|
|
20
|
+
const stdio = [interactive ? 'pipe' : 'ignore', 'pipe', 'pipe'];
|
|
21
|
+
const spawnOptions = { stdio };
|
|
22
22
|
const child = spawn(command, args, spawnOptions);
|
|
23
23
|
child.stdout.setEncoding('utf8');
|
|
24
24
|
child.stderr.setEncoding('utf8');
|
|
25
|
-
const rl =
|
|
25
|
+
const rl = interactive
|
|
26
26
|
? readline.createInterface({
|
|
27
27
|
input: process.stdin,
|
|
28
28
|
output: process.stdout,
|
|
@@ -53,13 +53,13 @@ export class Cli {
|
|
|
53
53
|
on('SIGTERM');
|
|
54
54
|
on('SIGHUP');
|
|
55
55
|
rl?.on('line', (line) => {
|
|
56
|
-
|
|
56
|
+
options.inScanner?.(line);
|
|
57
57
|
if (child.stdin.writable) {
|
|
58
58
|
child.stdin.write(line + '\n');
|
|
59
59
|
}
|
|
60
60
|
});
|
|
61
61
|
function processLine(line) {
|
|
62
|
-
|
|
62
|
+
options.outScanner?.(line);
|
|
63
63
|
console.log(line);
|
|
64
64
|
}
|
|
65
65
|
let buffer = '';
|
|
@@ -2,7 +2,7 @@ import fs from 'fs';
|
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { confirm } from '@inquirer/prompts';
|
|
5
|
-
import {
|
|
5
|
+
import {} from '../client/Cli.js';
|
|
6
6
|
import { AbortedException, KnownException, ProcessException, TimeoutException } from '../exceptions.js';
|
|
7
7
|
import { logger } from '../logger.js';
|
|
8
8
|
import { LocalStateService } from './LocalStateService.js';
|
|
@@ -188,32 +188,14 @@ export class TerraformAdapter {
|
|
|
188
188
|
});
|
|
189
189
|
return result;
|
|
190
190
|
}
|
|
191
|
-
async plan(env, args
|
|
191
|
+
async plan(env, args) {
|
|
192
192
|
args = this.tfArgs(env, args);
|
|
193
|
-
await this._plan(args,
|
|
193
|
+
await this._plan(args, 1);
|
|
194
194
|
}
|
|
195
|
-
async _plan(args,
|
|
196
|
-
let inputTfVariable = false;
|
|
197
|
-
let tfVarName = '';
|
|
198
|
-
function out_scanner(line) {
|
|
199
|
-
inputTfVariable = false;
|
|
200
|
-
const match = line.match(/var\.([a-zA-Z_0-9]+)/);
|
|
201
|
-
if (match) {
|
|
202
|
-
tfVarName = match[1];
|
|
203
|
-
}
|
|
204
|
-
else if (line.includes('Enter a value:')) {
|
|
205
|
-
inputTfVariable = true;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
function in_scanner(line) {
|
|
209
|
-
if (inputTfVariable && tfVarName) {
|
|
210
|
-
onDemandVars[tfVarName] = line;
|
|
211
|
-
tfVarName = '';
|
|
212
|
-
}
|
|
213
|
-
}
|
|
195
|
+
async _plan(args, attemptNo) {
|
|
214
196
|
logger.info('Running: terraform plan ' + args.join(' ') + '\n');
|
|
215
197
|
try {
|
|
216
|
-
await this.cli.run('terraform', ['plan', ...args],
|
|
198
|
+
await this.cli.run('terraform', ['plan', ...args], { interactive: true });
|
|
217
199
|
}
|
|
218
200
|
catch (error) {
|
|
219
201
|
if (!(error instanceof ProcessException)) {
|
|
@@ -221,13 +203,13 @@ export class TerraformAdapter {
|
|
|
221
203
|
}
|
|
222
204
|
if (attemptNo < MAX_ATTEMPTS && RETRYABLE_ERRORS.some(err => error.message.includes(err))) {
|
|
223
205
|
logger.warn(`Retrying terraform plan due to error: ${error.message}`);
|
|
224
|
-
return this._plan(args,
|
|
206
|
+
return this._plan(args, attemptNo + 1);
|
|
225
207
|
}
|
|
226
208
|
const lockId = this.lockId(error, attemptNo);
|
|
227
209
|
if (lockId) {
|
|
228
210
|
await this.promptUnlock(lockId);
|
|
229
211
|
logger.info('State unlocked, retrying terraform plan');
|
|
230
|
-
return this._plan(args,
|
|
212
|
+
return this._plan(args, attemptNo + 1);
|
|
231
213
|
}
|
|
232
214
|
throw new KnownException(`terraform plan failed with code ${error.code}:\n${error.message}`, { cause: error });
|
|
233
215
|
}
|
|
@@ -250,13 +232,13 @@ export class TerraformAdapter {
|
|
|
250
232
|
this.printTime();
|
|
251
233
|
const nowUtcSeconds = Math.floor(this.now() / 1000);
|
|
252
234
|
const gracePeriod = 10;
|
|
253
|
-
const
|
|
254
|
-
if (
|
|
235
|
+
const timeoutMs = (ttl - nowUtcSeconds - gracePeriod) * 1000;
|
|
236
|
+
if (timeoutMs <= 0) {
|
|
255
237
|
throw new KnownException('TTL expired before terraform apply could start');
|
|
256
238
|
}
|
|
257
|
-
logger.debug('timeout(ms): ' +
|
|
239
|
+
logger.debug('timeout(ms): ' + timeoutMs);
|
|
258
240
|
try {
|
|
259
|
-
await this.cli.run('terraform', ['apply', ...args],
|
|
241
|
+
await this.cli.run('terraform', ['apply', ...args], { timeoutMs });
|
|
260
242
|
this.printTime();
|
|
261
243
|
}
|
|
262
244
|
catch (error) {
|
|
@@ -282,14 +264,14 @@ export class TerraformAdapter {
|
|
|
282
264
|
}
|
|
283
265
|
async _destroy(args, force, attemptNo = 1) {
|
|
284
266
|
let wrongDir = false;
|
|
285
|
-
const
|
|
267
|
+
const outScanner = (line) => {
|
|
286
268
|
if (line.includes('Either you have not created any objects yet or the existing objects were')) {
|
|
287
269
|
wrongDir = true;
|
|
288
270
|
}
|
|
289
271
|
};
|
|
290
|
-
logger.info('Running: terraform destroy -auto-approve' + args.join(' ') + '\n');
|
|
272
|
+
logger.info('Running: terraform destroy -auto-approve ' + args.join(' ') + '\n');
|
|
291
273
|
try {
|
|
292
|
-
await this.cli.run('terraform', ['destroy', '-auto-approve', ...args],
|
|
274
|
+
await this.cli.run('terraform', ['destroy', '-auto-approve', ...args], { outScanner, interactive: true });
|
|
293
275
|
}
|
|
294
276
|
catch (error) {
|
|
295
277
|
if (!(error instanceof ProcessException)) {
|