@agilecustoms/envctl 0.35.2 → 0.36.0
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/EnvApiClient.js +13 -0
- package/dist/client/TerraformAdapter.js +7 -0
- package/dist/commands/createEphemeral.js +2 -2
- package/dist/commands/delete.js +2 -2
- package/dist/commands/deploy.js +2 -2
- package/dist/commands/destroy.js +2 -2
- package/dist/commands/index.js +1 -0
- package/dist/commands/logs.js +16 -0
- package/dist/commands/plan.js +2 -2
- package/dist/commands/status.js +2 -2
- package/dist/container.js +5 -3
- package/dist/index.js +2 -1
- package/dist/service/{EnvCtl.js → EnvService.js} +15 -21
- package/dist/service/LogService.js +34 -0
- package/dist/service/index.js +1 -1
- package/package.json +5 -1
|
@@ -58,4 +58,17 @@ export class EnvApiClient {
|
|
|
58
58
|
env.status = EnvStatus.Deleting;
|
|
59
59
|
console.log(result.statusText);
|
|
60
60
|
}
|
|
61
|
+
async getLogs(key) {
|
|
62
|
+
let result;
|
|
63
|
+
try {
|
|
64
|
+
result = await this.httpClient.fetch(`/ci/env/${key}/logs`);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
if (error instanceof NotFoundException) {
|
|
68
|
+
throw new KnownException(`Environment ${key} is not found`);
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
return result.url;
|
|
73
|
+
}
|
|
61
74
|
}
|
|
@@ -33,6 +33,13 @@ export class TerraformAdapter {
|
|
|
33
33
|
throw new KnownException(`Failed to read terraform lock file: ${lockPath}`, { cause: err });
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
+
getKey(key, cwd) {
|
|
37
|
+
if (!key) {
|
|
38
|
+
console.log('Key is not provided, inferring from state file');
|
|
39
|
+
key = this.getTerraformBackend(cwd).getKey();
|
|
40
|
+
}
|
|
41
|
+
return key;
|
|
42
|
+
}
|
|
36
43
|
getTerraformBackend(cwd) {
|
|
37
44
|
if (this.backend) {
|
|
38
45
|
return this.backend;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import {
|
|
2
|
+
import { envService } from '../container.js';
|
|
3
3
|
import { _keys } from './_keys.js';
|
|
4
4
|
import { wrap } from './_utils.js';
|
|
5
5
|
export function createEphemeral(program) {
|
|
@@ -11,6 +11,6 @@ export function createEphemeral(program) {
|
|
|
11
11
|
}
|
|
12
12
|
async function handler(options) {
|
|
13
13
|
const { key } = options;
|
|
14
|
-
const token = await
|
|
14
|
+
const token = await envService.createEphemeral(key);
|
|
15
15
|
console.log(token);
|
|
16
16
|
}
|
package/dist/commands/delete.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import {
|
|
2
|
+
import { envService } from '../container.js';
|
|
3
3
|
import { _keys } from './_keys.js';
|
|
4
4
|
import { wrap } from './_utils.js';
|
|
5
5
|
export function deleteIt(program) {
|
|
@@ -13,5 +13,5 @@ export function deleteIt(program) {
|
|
|
13
13
|
}
|
|
14
14
|
async function handler(options) {
|
|
15
15
|
const { key, force, cwd } = options;
|
|
16
|
-
await
|
|
16
|
+
await envService.delete(Boolean(force), key, cwd);
|
|
17
17
|
}
|
package/dist/commands/deploy.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import { awsCredsHelper,
|
|
2
|
+
import { awsCredsHelper, envService } from '../container.js';
|
|
3
3
|
import { _keys } from './_keys.js';
|
|
4
4
|
import { wrap } from './_utils.js';
|
|
5
5
|
export function deploy(program) {
|
|
@@ -14,5 +14,5 @@ export function deploy(program) {
|
|
|
14
14
|
async function handler(tfArgs, options) {
|
|
15
15
|
await awsCredsHelper.ensureCredentials();
|
|
16
16
|
const { cwd } = options;
|
|
17
|
-
await
|
|
17
|
+
await envService.deploy(tfArgs, cwd);
|
|
18
18
|
}
|
package/dist/commands/destroy.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import {
|
|
2
|
+
import { envService } from '../container.js';
|
|
3
3
|
import { _keys } from './_keys.js';
|
|
4
4
|
import { wrap } from './_utils.js';
|
|
5
5
|
export function destroy(program) {
|
|
@@ -17,5 +17,5 @@ export function destroy(program) {
|
|
|
17
17
|
}
|
|
18
18
|
async function handler(tfArgs, options) {
|
|
19
19
|
const { force, cwd } = options;
|
|
20
|
-
await
|
|
20
|
+
await envService.destroy(tfArgs, Boolean(force), cwd);
|
|
21
21
|
}
|
package/dist/commands/index.js
CHANGED
|
@@ -3,5 +3,6 @@ export { createEphemeral } from './createEphemeral.js';
|
|
|
3
3
|
export { deleteIt } from './delete.js';
|
|
4
4
|
export { deploy } from './deploy.js';
|
|
5
5
|
export { destroy } from './destroy.js';
|
|
6
|
+
export { logs } from './logs.js';
|
|
6
7
|
export { plan } from './plan.js';
|
|
7
8
|
export { status } from './status.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { logService } from '../container.js';
|
|
3
|
+
import { _keys } from './_keys.js';
|
|
4
|
+
import { wrap } from './_utils.js';
|
|
5
|
+
export function logs(program) {
|
|
6
|
+
program
|
|
7
|
+
.command('logs')
|
|
8
|
+
.description('Get most recent env destroy logs')
|
|
9
|
+
.option('--key <key>', _keys.KEY)
|
|
10
|
+
.option('--cwd <cwd>', _keys.CWD)
|
|
11
|
+
.action(wrap(handler));
|
|
12
|
+
}
|
|
13
|
+
async function handler(options) {
|
|
14
|
+
const { key, cwd } = options;
|
|
15
|
+
await logService.getLogs(key, cwd);
|
|
16
|
+
}
|
package/dist/commands/plan.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import { awsCredsHelper,
|
|
2
|
+
import { awsCredsHelper, envService } from '../container.js';
|
|
3
3
|
import { _keys } from './_keys.js';
|
|
4
4
|
import { wrap } from './_utils.js';
|
|
5
5
|
export function plan(program) {
|
|
@@ -15,5 +15,5 @@ export function plan(program) {
|
|
|
15
15
|
async function handler(tfArgs, options) {
|
|
16
16
|
await awsCredsHelper.ensureCredentials();
|
|
17
17
|
const { cwd } = options;
|
|
18
|
-
await
|
|
18
|
+
await envService.plan(tfArgs, cwd);
|
|
19
19
|
}
|
package/dist/commands/status.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import {
|
|
2
|
+
import { envService } from '../container.js';
|
|
3
3
|
import { _keys } from './_keys.js';
|
|
4
4
|
import { wrap } from './_utils.js';
|
|
5
5
|
export function status(program) {
|
|
@@ -12,5 +12,5 @@ export function status(program) {
|
|
|
12
12
|
}
|
|
13
13
|
async function handler(options) {
|
|
14
14
|
const { key, cwd } = options;
|
|
15
|
-
await
|
|
15
|
+
await envService.status(key, cwd);
|
|
16
16
|
}
|
package/dist/container.js
CHANGED
|
@@ -2,7 +2,8 @@ import { S3Backend } from './backend/S3Backend.js';
|
|
|
2
2
|
import { AwsCredsHelper } from './client/AwsCredsHelper.js';
|
|
3
3
|
import { CliHelper, EnvApiClient, HttpClient, TerraformAdapter } from './client/index.js';
|
|
4
4
|
import { ProcessRunner } from './client/ProcessRunner.js';
|
|
5
|
-
import { ConfigService,
|
|
5
|
+
import { ConfigService, EnvService } from './service/index.js';
|
|
6
|
+
import { LogService } from './service/LogService.js';
|
|
6
7
|
const cliHelper = new CliHelper();
|
|
7
8
|
const configService = new ConfigService();
|
|
8
9
|
const awsCredsHelper = new AwsCredsHelper();
|
|
@@ -13,5 +14,6 @@ const httpClient = new HttpClient(awsCredsHelper);
|
|
|
13
14
|
const envApiClient = new EnvApiClient(httpClient);
|
|
14
15
|
const processRunner = new ProcessRunner();
|
|
15
16
|
const terraformAdapter = new TerraformAdapter(processRunner, cliHelper, backends);
|
|
16
|
-
const
|
|
17
|
-
|
|
17
|
+
const envService = new EnvService(cliHelper, envApiClient, terraformAdapter);
|
|
18
|
+
const logService = new LogService(envApiClient, terraformAdapter);
|
|
19
|
+
export { awsCredsHelper, configService, envService, logService };
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import updateNotifier from 'update-notifier';
|
|
5
|
-
import { configure, createEphemeral, deleteIt, deploy, destroy, plan, status } from './commands/index.js';
|
|
5
|
+
import { configure, createEphemeral, deleteIt, deploy, destroy, logs, plan, status } from './commands/index.js';
|
|
6
6
|
const require = createRequire(import.meta.url);
|
|
7
7
|
const pkg = require('../package.json');
|
|
8
8
|
updateNotifier({ pkg, updateCheckInterval: 0 }).notify();
|
|
@@ -16,6 +16,7 @@ createEphemeral(program);
|
|
|
16
16
|
deleteIt(program);
|
|
17
17
|
deploy(program);
|
|
18
18
|
destroy(program);
|
|
19
|
+
logs(program);
|
|
19
20
|
plan(program);
|
|
20
21
|
status(program);
|
|
21
22
|
program.parse(process.argv);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { KnownException } from '../exceptions.js';
|
|
2
2
|
import { EnvStatus, } from '../model/index.js';
|
|
3
|
-
export class
|
|
3
|
+
export class EnvService {
|
|
4
4
|
cliHelper;
|
|
5
5
|
envApi;
|
|
6
6
|
terraformAdapter;
|
|
@@ -9,15 +9,8 @@ export class EnvCtl {
|
|
|
9
9
|
this.envApi = envApi;
|
|
10
10
|
this.terraformAdapter = terraformAdapter;
|
|
11
11
|
}
|
|
12
|
-
getKey(key, cwd) {
|
|
13
|
-
if (!key) {
|
|
14
|
-
console.log('Key is not provided, inferring from state file');
|
|
15
|
-
key = this.terraformAdapter.getTerraformBackend(cwd).getKey();
|
|
16
|
-
}
|
|
17
|
-
return key;
|
|
18
|
-
}
|
|
19
12
|
async status(key, cwd) {
|
|
20
|
-
key = this.getKey(key, cwd);
|
|
13
|
+
key = this.terraformAdapter.getKey(key, cwd);
|
|
21
14
|
console.log(`Retrieve env ${key}`);
|
|
22
15
|
const env = await this.envApi.get(key);
|
|
23
16
|
if (env === null) {
|
|
@@ -25,17 +18,18 @@ export class EnvCtl {
|
|
|
25
18
|
return;
|
|
26
19
|
}
|
|
27
20
|
console.log(`Env ${key} status: ${env.status}`);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
21
|
+
if (env.status !== EnvStatus.Deleting && env.status !== EnvStatus.DeleteError) {
|
|
22
|
+
const date = new Date(env.ttl * 1000);
|
|
23
|
+
const formattedDate = date.toLocaleString(undefined, {
|
|
24
|
+
month: 'short',
|
|
25
|
+
day: '2-digit',
|
|
26
|
+
hour: '2-digit',
|
|
27
|
+
minute: '2-digit',
|
|
28
|
+
second: '2-digit',
|
|
29
|
+
hour12: false,
|
|
30
|
+
});
|
|
31
|
+
console.log(`Expires at ${formattedDate}`);
|
|
32
|
+
}
|
|
39
33
|
if (env.kind) {
|
|
40
34
|
const kind = this.cliHelper.getKind(cwd);
|
|
41
35
|
if (env.kind !== kind) {
|
|
@@ -149,7 +143,7 @@ export class EnvCtl {
|
|
|
149
143
|
await this.envApi.activate(env);
|
|
150
144
|
}
|
|
151
145
|
async delete(force, key, cwd) {
|
|
152
|
-
key = this.getKey(key, cwd);
|
|
146
|
+
key = this.terraformAdapter.getKey(key, cwd);
|
|
153
147
|
const env = await this.get(key);
|
|
154
148
|
if (env.status === EnvStatus.Init) {
|
|
155
149
|
await this.envApi.delete(env);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createWriteStream } from 'node:fs';
|
|
2
|
+
import { mkdir } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { basename, join } from 'node:path';
|
|
5
|
+
import { Readable } from 'node:stream';
|
|
6
|
+
import { pipeline } from 'node:stream/promises';
|
|
7
|
+
import { TerraformAdapter } from '../client/index.js';
|
|
8
|
+
import { KnownException } from '../exceptions.js';
|
|
9
|
+
export class LogService {
|
|
10
|
+
envApi;
|
|
11
|
+
terraformAdapter;
|
|
12
|
+
constructor(envApi, terraformAdapter) {
|
|
13
|
+
this.envApi = envApi;
|
|
14
|
+
this.terraformAdapter = terraformAdapter;
|
|
15
|
+
}
|
|
16
|
+
async getLogs(key, cwd) {
|
|
17
|
+
key = this.terraformAdapter.getKey(key, cwd);
|
|
18
|
+
const url = await this.envApi.getLogs(key);
|
|
19
|
+
console.log(`Downloading logs from: ${url}`);
|
|
20
|
+
const outDir = join(tmpdir(), 'envctl');
|
|
21
|
+
await mkdir(outDir, { recursive: true });
|
|
22
|
+
const urlPath = new URL(url).pathname;
|
|
23
|
+
const gzName = basename(urlPath);
|
|
24
|
+
const outName = gzName.slice(0, -3);
|
|
25
|
+
const outPath = join(outDir, outName);
|
|
26
|
+
const res = await fetch(url);
|
|
27
|
+
if (!res.ok) {
|
|
28
|
+
const msg = await res.text();
|
|
29
|
+
throw new KnownException(`Failed to download logs: ${res.status} ${res.statusText}${msg ? ` - ${msg}` : ''}`);
|
|
30
|
+
}
|
|
31
|
+
await pipeline(Readable.fromWeb(res.body), createWriteStream(outPath, { flags: 'w' }));
|
|
32
|
+
console.log(`Logs saved to: ${outPath}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
package/dist/service/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { EnvService } from './EnvService.js';
|
|
2
2
|
export { ConfigService } from './ConfigService.js';
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agilecustoms/envctl",
|
|
3
3
|
"description": "node.js CLI client for manage environments",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.36.0",
|
|
5
5
|
"author": "Alex Chekulaev",
|
|
6
6
|
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22.0.0"
|
|
9
|
+
},
|
|
7
10
|
"bin": {
|
|
8
11
|
"envctl": "dist/index.js"
|
|
9
12
|
},
|
|
@@ -35,6 +38,7 @@
|
|
|
35
38
|
"run-core-deploy": " tsc --sourceMap true && npm run run -- deploy --cwd ../tt-core -var=\"env_size=min\"",
|
|
36
39
|
"run-core-delete": " tsc --sourceMap true && npm run run -- delete --cwd ../tt-core",
|
|
37
40
|
"run-core-destroy": "tsc --sourceMap true && npm run run -- destroy --cwd ../tt-core",
|
|
41
|
+
"run-core-logs": "tsc --sourceMap true && npm run run -- logs --cwd ../tt-core",
|
|
38
42
|
"*": "",
|
|
39
43
|
"run-init": "cd ../tt-gitops && terraform init -upgrade -backend-config=key=laxa1986 -reconfigure",
|
|
40
44
|
"run-status": " tsc --sourceMap true && npm run run -- status --cwd ../tt-gitops",
|