@enspirit/emb 0.10.1 → 0.12.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/README.md +72 -1
- package/dist/src/cli/abstract/BaseCommand.js +2 -0
- package/dist/src/cli/abstract/KubernetesCommand.d.ts +7 -0
- package/dist/src/cli/abstract/KubernetesCommand.js +15 -0
- package/dist/src/cli/abstract/index.d.ts +1 -0
- package/dist/src/cli/abstract/index.js +1 -0
- package/dist/src/cli/commands/kubernetes/logs.d.ts +14 -0
- package/dist/src/cli/commands/kubernetes/logs.js +53 -0
- package/dist/src/cli/commands/kubernetes/ps.d.ts +10 -0
- package/dist/src/cli/commands/kubernetes/ps.js +41 -0
- package/dist/src/cli/commands/kubernetes/restart.d.ts +10 -0
- package/dist/src/cli/commands/kubernetes/restart.js +22 -0
- package/dist/src/cli/commands/resources/index.js +2 -2
- package/dist/src/cli/commands/restart.js +3 -7
- package/dist/src/docker/compose/client.js +4 -0
- package/dist/src/kubernetes/client.d.ts +6 -0
- package/dist/src/kubernetes/client.js +10 -0
- package/dist/src/kubernetes/index.d.ts +2 -0
- package/dist/src/kubernetes/index.js +2 -0
- package/dist/src/kubernetes/operations/GetDeploymentPodsOperation.d.ts +12 -0
- package/dist/src/kubernetes/operations/GetDeploymentPodsOperation.js +20 -0
- package/dist/src/kubernetes/operations/RestartPodsOperation.d.ts +13 -0
- package/dist/src/kubernetes/operations/RestartPodsOperation.js +50 -0
- package/dist/src/kubernetes/operations/index.d.ts +1 -0
- package/dist/src/kubernetes/operations/index.js +1 -0
- package/dist/src/monorepo/plugins/AutoDockerPlugin.js +4 -2
- package/dist/src/monorepo/plugins/EmbfileLoaderPlugin.js +1 -0
- package/dist/src/monorepo/resources/FileResourceBuilder.d.ts +3 -1
- package/dist/src/monorepo/resources/FileResourceBuilder.js +13 -1
- package/dist/src/types.d.ts +6 -0
- package/dist/src/utils/time.d.ts +1 -1
- package/dist/src/utils/time.js +28 -17
- package/oclif.manifest.json +161 -1
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ $ npm install -g @enspirit/emb
|
|
|
14
14
|
$ emb COMMAND
|
|
15
15
|
running command...
|
|
16
16
|
$ emb (--version)
|
|
17
|
-
@enspirit/emb/0.
|
|
17
|
+
@enspirit/emb/0.12.0 darwin-x64 node-v22.18.0
|
|
18
18
|
$ emb --help [COMMAND]
|
|
19
19
|
USAGE
|
|
20
20
|
$ emb COMMAND
|
|
@@ -37,6 +37,9 @@ USAGE
|
|
|
37
37
|
* [`emb images delete`](#emb-images-delete)
|
|
38
38
|
* [`emb images prune`](#emb-images-prune)
|
|
39
39
|
* [`emb images push`](#emb-images-push)
|
|
40
|
+
* [`emb kubernetes logs COMPONENT`](#emb-kubernetes-logs-component)
|
|
41
|
+
* [`emb kubernetes ps`](#emb-kubernetes-ps)
|
|
42
|
+
* [`emb kubernetes restart [DEPLOYMENT]`](#emb-kubernetes-restart-deployment)
|
|
40
43
|
* [`emb logs COMPONENT`](#emb-logs-component)
|
|
41
44
|
* [`emb ps`](#emb-ps)
|
|
42
45
|
* [`emb resources`](#emb-resources)
|
|
@@ -379,6 +382,74 @@ EXAMPLES
|
|
|
379
382
|
$ emb images push --registry my.registry.io --retag newtag
|
|
380
383
|
```
|
|
381
384
|
|
|
385
|
+
## `emb kubernetes logs COMPONENT`
|
|
386
|
+
|
|
387
|
+
Follow kubernetes logs.
|
|
388
|
+
|
|
389
|
+
```
|
|
390
|
+
USAGE
|
|
391
|
+
$ emb kubernetes logs COMPONENT -n <value> [--verbose] [-f]
|
|
392
|
+
|
|
393
|
+
ARGUMENTS
|
|
394
|
+
COMPONENT The component you want to see the logs of
|
|
395
|
+
|
|
396
|
+
FLAGS
|
|
397
|
+
-f, --[no-]follow Follow log output
|
|
398
|
+
-n, --namespace=<value> (required) The Kubernetes namespace to target
|
|
399
|
+
--[no-]verbose
|
|
400
|
+
|
|
401
|
+
DESCRIPTION
|
|
402
|
+
Follow kubernetes logs.
|
|
403
|
+
|
|
404
|
+
ALIASES
|
|
405
|
+
$ emb logs
|
|
406
|
+
|
|
407
|
+
EXAMPLES
|
|
408
|
+
$ emb kubernetes logs
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## `emb kubernetes ps`
|
|
412
|
+
|
|
413
|
+
Show running pods.
|
|
414
|
+
|
|
415
|
+
```
|
|
416
|
+
USAGE
|
|
417
|
+
$ emb kubernetes ps -n <value> [--verbose] [--watch]
|
|
418
|
+
|
|
419
|
+
FLAGS
|
|
420
|
+
-n, --namespace=<value> (required) The Kubernetes namespace to target
|
|
421
|
+
--[no-]verbose
|
|
422
|
+
--[no-]watch
|
|
423
|
+
|
|
424
|
+
DESCRIPTION
|
|
425
|
+
Show running pods.
|
|
426
|
+
|
|
427
|
+
EXAMPLES
|
|
428
|
+
$ emb kubernetes ps
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## `emb kubernetes restart [DEPLOYMENT]`
|
|
432
|
+
|
|
433
|
+
Restart pods of an instance.
|
|
434
|
+
|
|
435
|
+
```
|
|
436
|
+
USAGE
|
|
437
|
+
$ emb kubernetes restart [DEPLOYMENT...] -n <value> [--verbose]
|
|
438
|
+
|
|
439
|
+
ARGUMENTS
|
|
440
|
+
DEPLOYMENT... The deployment(s) to restart
|
|
441
|
+
|
|
442
|
+
FLAGS
|
|
443
|
+
-n, --namespace=<value> (required) The Kubernetes namespace to target
|
|
444
|
+
--[no-]verbose
|
|
445
|
+
|
|
446
|
+
DESCRIPTION
|
|
447
|
+
Restart pods of an instance.
|
|
448
|
+
|
|
449
|
+
EXAMPLES
|
|
450
|
+
$ emb kubernetes restart
|
|
451
|
+
```
|
|
452
|
+
|
|
382
453
|
## `emb logs COMPONENT`
|
|
383
454
|
|
|
384
455
|
Get components logs.
|
|
@@ -2,6 +2,7 @@ import { DockerComposeClient, getContext, setContext } from '../../index.js';
|
|
|
2
2
|
import { Command, Flags } from '@oclif/core';
|
|
3
3
|
import Dockerode from 'dockerode';
|
|
4
4
|
import { loadConfig } from '../../config/index.js';
|
|
5
|
+
import { createKubernetesClient } from '../../kubernetes/client.js';
|
|
5
6
|
import { Monorepo } from '../../monorepo/monorepo.js';
|
|
6
7
|
import { withMarker } from '../utils.js';
|
|
7
8
|
export class BaseCommand extends Command {
|
|
@@ -31,6 +32,7 @@ export class BaseCommand extends Command {
|
|
|
31
32
|
docker: new Dockerode(),
|
|
32
33
|
monorepo,
|
|
33
34
|
compose,
|
|
35
|
+
kubernetes: createKubernetesClient(),
|
|
34
36
|
});
|
|
35
37
|
}
|
|
36
38
|
catch (error) {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { BaseCommand } from './BaseCommand.js';
|
|
2
|
+
export declare abstract class KubernetesCommand extends BaseCommand {
|
|
3
|
+
static baseFlags: {
|
|
4
|
+
namespace: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
5
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { BaseCommand } from './BaseCommand.js';
|
|
3
|
+
export class KubernetesCommand extends BaseCommand {
|
|
4
|
+
static baseFlags = {
|
|
5
|
+
...BaseCommand.baseFlags,
|
|
6
|
+
namespace: Flags.string({
|
|
7
|
+
name: 'namespace',
|
|
8
|
+
description: 'The Kubernetes namespace to target',
|
|
9
|
+
aliases: ['ns'],
|
|
10
|
+
char: 'n',
|
|
11
|
+
required: true,
|
|
12
|
+
env: 'K8S_NAMESPACE',
|
|
13
|
+
}),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { KubernetesCommand } from '../../index.js';
|
|
2
|
+
export default class KubernetesLogs extends KubernetesCommand {
|
|
3
|
+
static aliases: string[];
|
|
4
|
+
static description: string;
|
|
5
|
+
static enableJsonFlag: boolean;
|
|
6
|
+
static examples: string[];
|
|
7
|
+
static flags: {
|
|
8
|
+
follow: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
};
|
|
10
|
+
static args: {
|
|
11
|
+
component: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Log } from '@kubernetes/client-node';
|
|
2
|
+
import { Args, Flags } from '@oclif/core';
|
|
3
|
+
import { PassThrough } from 'node:stream';
|
|
4
|
+
import { KubernetesCommand } from '../../index.js';
|
|
5
|
+
import { GetDeploymentPodsOperation } from '../../../kubernetes/operations/GetDeploymentPodsOperation.js';
|
|
6
|
+
export default class KubernetesLogs extends KubernetesCommand {
|
|
7
|
+
static aliases = ['logs'];
|
|
8
|
+
static description = 'Follow kubernetes logs.';
|
|
9
|
+
static enableJsonFlag = false;
|
|
10
|
+
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
11
|
+
static flags = {
|
|
12
|
+
follow: Flags.boolean({
|
|
13
|
+
name: 'follow',
|
|
14
|
+
char: 'f',
|
|
15
|
+
allowNo: true,
|
|
16
|
+
description: 'Follow log output',
|
|
17
|
+
default: true,
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
static args = {
|
|
21
|
+
component: Args.string({
|
|
22
|
+
name: 'component',
|
|
23
|
+
description: 'The component you want to see the logs of',
|
|
24
|
+
required: true,
|
|
25
|
+
}),
|
|
26
|
+
};
|
|
27
|
+
async run() {
|
|
28
|
+
const { flags, args } = await this.parse(KubernetesLogs);
|
|
29
|
+
const { monorepo, kubernetes } = this.context;
|
|
30
|
+
// Check the component name is valid (would raise otherwise)
|
|
31
|
+
monorepo.component(args.component);
|
|
32
|
+
const pods = await monorepo.run(new GetDeploymentPodsOperation(), {
|
|
33
|
+
namespace: flags.namespace,
|
|
34
|
+
deployment: args.component,
|
|
35
|
+
});
|
|
36
|
+
if (pods.length === 0) {
|
|
37
|
+
throw new Error(`No running pod found for component ${args.component}`);
|
|
38
|
+
}
|
|
39
|
+
const k8sLogs = new Log(kubernetes.config);
|
|
40
|
+
const transform = new PassThrough();
|
|
41
|
+
transform.on('data', (chunk) => {
|
|
42
|
+
process.stdout.write(chunk);
|
|
43
|
+
});
|
|
44
|
+
const pod = pods[0];
|
|
45
|
+
const container = pod.spec.containers[0];
|
|
46
|
+
await k8sLogs.log(flags.namespace, pod.metadata.name, container.name, transform, {
|
|
47
|
+
follow: flags.follow,
|
|
48
|
+
tailLines: 50,
|
|
49
|
+
pretty: false,
|
|
50
|
+
timestamps: true,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { KubernetesCommand } from '../../index.js';
|
|
2
|
+
export default class KPSCommand extends KubernetesCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
watch: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
};
|
|
8
|
+
static strict: boolean;
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { printTable } from '@oclif/table';
|
|
3
|
+
import { getContext, KubernetesCommand, TABLE_DEFAULTS } from '../../index.js';
|
|
4
|
+
import { timeAgo } from '../../../utils/time.js';
|
|
5
|
+
export default class KPSCommand extends KubernetesCommand {
|
|
6
|
+
static description = 'Show running pods.';
|
|
7
|
+
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
8
|
+
static flags = {
|
|
9
|
+
watch: Flags.boolean({
|
|
10
|
+
name: 'watch',
|
|
11
|
+
allowNo: true,
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
14
|
+
static strict = false;
|
|
15
|
+
async run() {
|
|
16
|
+
const { flags } = await this.parse(KPSCommand);
|
|
17
|
+
const { kubernetes } = getContext();
|
|
18
|
+
const { items } = await kubernetes.core.listNamespacedPod({
|
|
19
|
+
namespace: flags.namespace,
|
|
20
|
+
});
|
|
21
|
+
const pods = items.map((i) => {
|
|
22
|
+
const restarts = i.status?.containerStatuses
|
|
23
|
+
?.filter((s) => s.restartCount > 0)
|
|
24
|
+
.map((c) => ({
|
|
25
|
+
count: c.restartCount,
|
|
26
|
+
ago: timeAgo(c.lastState?.terminated?.finishedAt),
|
|
27
|
+
})) || [];
|
|
28
|
+
const restart = restarts.length > 0 ? restarts[0] : null;
|
|
29
|
+
return {
|
|
30
|
+
name: i.metadata?.name,
|
|
31
|
+
status: i.status?.phase,
|
|
32
|
+
restarts: restart ? `${restart?.count} (${restart?.ago} ago)` : '',
|
|
33
|
+
age: timeAgo(i.status?.startTime),
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
printTable({
|
|
37
|
+
...TABLE_DEFAULTS,
|
|
38
|
+
data: pods,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { KubernetesCommand } from '../../index.js';
|
|
2
|
+
export default class KRestartCommand extends KubernetesCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
deployment: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static strict: boolean;
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Args } from '@oclif/core';
|
|
2
|
+
import { getContext, KubernetesCommand } from '../../index.js';
|
|
3
|
+
import { PodsRestartOperation } from '../../../kubernetes/index.js';
|
|
4
|
+
export default class KRestartCommand extends KubernetesCommand {
|
|
5
|
+
static description = 'Restart pods of an instance.';
|
|
6
|
+
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
7
|
+
static args = {
|
|
8
|
+
deployment: Args.string({
|
|
9
|
+
name: 'deployment',
|
|
10
|
+
description: 'The deployment(s) to restart',
|
|
11
|
+
}),
|
|
12
|
+
};
|
|
13
|
+
static strict = false;
|
|
14
|
+
async run() {
|
|
15
|
+
const { flags, argv } = await this.parse(KRestartCommand);
|
|
16
|
+
const { monorepo } = getContext();
|
|
17
|
+
await monorepo.run(new PodsRestartOperation(), {
|
|
18
|
+
namespace: flags.namespace,
|
|
19
|
+
deployments: argv.length > 0 ? argv : undefined,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -24,10 +24,10 @@ export default class ResourcesIndex extends FlavoredCommand {
|
|
|
24
24
|
if (!flags.json) {
|
|
25
25
|
printTable({
|
|
26
26
|
...TABLE_DEFAULTS,
|
|
27
|
-
columns: ['
|
|
27
|
+
columns: ['id', 'name', 'type', 'reference'],
|
|
28
28
|
data: resources,
|
|
29
29
|
sort: {
|
|
30
|
-
|
|
30
|
+
id: 'asc',
|
|
31
31
|
},
|
|
32
32
|
});
|
|
33
33
|
}
|
|
@@ -23,13 +23,9 @@ export default class RestartComand extends BaseCommand {
|
|
|
23
23
|
async run() {
|
|
24
24
|
const { flags, argv } = await this.parse(RestartComand);
|
|
25
25
|
const { monorepo } = getContext();
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
components
|
|
29
|
-
argv.length > 0
|
|
30
|
-
? argv.map((name) => monorepo.component(name))
|
|
31
|
-
: monorepo.components;
|
|
32
|
-
}
|
|
26
|
+
const components = argv.length > 0
|
|
27
|
+
? argv.map((name) => monorepo.component(name))
|
|
28
|
+
: monorepo.components;
|
|
33
29
|
await monorepo.run(new ComposeRestartOperation(), {
|
|
34
30
|
noDeps: flags['no-deps'],
|
|
35
31
|
services: components?.map((c) => c.name),
|
|
@@ -51,6 +51,10 @@ export class DockerComposeClient {
|
|
|
51
51
|
const { stdout } = await execa({
|
|
52
52
|
cwd: this.monorepo.rootDir,
|
|
53
53
|
}) `docker compose ps -a --format json`;
|
|
54
|
+
if (!stdout.trim()) {
|
|
55
|
+
this.services = services;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
54
58
|
this.services = stdout
|
|
55
59
|
.split('\n')
|
|
56
60
|
.map((l) => JSON.parse(l))
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AppsV1Api, CoreV1Api, KubeConfig } from '@kubernetes/client-node';
|
|
2
|
+
export const createKubernetesClient = () => {
|
|
3
|
+
const kc = new KubeConfig();
|
|
4
|
+
kc.loadFromDefault();
|
|
5
|
+
return {
|
|
6
|
+
config: kc,
|
|
7
|
+
core: kc.makeApiClient(CoreV1Api),
|
|
8
|
+
apps: kc.makeApiClient(AppsV1Api),
|
|
9
|
+
};
|
|
10
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { V1Pod } from '@kubernetes/client-node';
|
|
2
|
+
import * as z from 'zod';
|
|
3
|
+
import { AbstractOperation } from '../../operations/index.js';
|
|
4
|
+
declare const schema: z.ZodObject<{
|
|
5
|
+
namespace: z.ZodString;
|
|
6
|
+
deployment: z.ZodString;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
export declare class GetDeploymentPodsOperation extends AbstractOperation<typeof schema, Array<V1Pod>> {
|
|
9
|
+
constructor();
|
|
10
|
+
protected _run(input: z.input<typeof schema>): Promise<Array<V1Pod>>;
|
|
11
|
+
}
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { getContext } from '../../index.js';
|
|
2
|
+
import * as z from 'zod';
|
|
3
|
+
import { AbstractOperation } from '../../operations/index.js';
|
|
4
|
+
const schema = z.object({
|
|
5
|
+
namespace: z.string().describe('The namespace in which to restart pods'),
|
|
6
|
+
deployment: z.string(),
|
|
7
|
+
});
|
|
8
|
+
export class GetDeploymentPodsOperation extends AbstractOperation {
|
|
9
|
+
constructor() {
|
|
10
|
+
super(schema);
|
|
11
|
+
}
|
|
12
|
+
async _run(input) {
|
|
13
|
+
const { kubernetes } = getContext();
|
|
14
|
+
const res = await kubernetes.core.listNamespacedPod({
|
|
15
|
+
namespace: input.namespace,
|
|
16
|
+
labelSelector: `component=${input.deployment}`,
|
|
17
|
+
});
|
|
18
|
+
return res.items;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
import { AbstractOperation } from '../../operations/index.js';
|
|
3
|
+
declare const schema: z.ZodObject<{
|
|
4
|
+
namespace: z.ZodString;
|
|
5
|
+
deployments: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
export declare class PodsRestartOperation extends AbstractOperation<typeof schema, void> {
|
|
8
|
+
constructor();
|
|
9
|
+
protected _run(input: z.input<typeof schema>): Promise<void>;
|
|
10
|
+
private patchDeployment;
|
|
11
|
+
private listDeployments;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { getContext } from '../../index.js';
|
|
2
|
+
import * as z from 'zod';
|
|
3
|
+
import { AbstractOperation } from '../../operations/index.js';
|
|
4
|
+
const schema = z.object({
|
|
5
|
+
namespace: z.string().describe('The namespace in which to restart pods'),
|
|
6
|
+
deployments: z
|
|
7
|
+
.array(z.string())
|
|
8
|
+
.optional()
|
|
9
|
+
.describe('The list of deployments to restart'),
|
|
10
|
+
});
|
|
11
|
+
export class PodsRestartOperation extends AbstractOperation {
|
|
12
|
+
constructor() {
|
|
13
|
+
super(schema);
|
|
14
|
+
}
|
|
15
|
+
async _run(input) {
|
|
16
|
+
const { monorepo } = getContext();
|
|
17
|
+
const manager = monorepo.taskManager();
|
|
18
|
+
const deployments = input?.deployments || (await this.listDeployments(input.namespace));
|
|
19
|
+
const tasks = deployments.map((name) => {
|
|
20
|
+
return {
|
|
21
|
+
title: `Restart ${name}`,
|
|
22
|
+
task: async () => {
|
|
23
|
+
return this.patchDeployment(input.namespace, name);
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
manager.add(tasks);
|
|
28
|
+
await manager.runAll();
|
|
29
|
+
}
|
|
30
|
+
async patchDeployment(namespace, name) {
|
|
31
|
+
const patch = [
|
|
32
|
+
{
|
|
33
|
+
op: 'add',
|
|
34
|
+
path: '/spec/template/metadata/annotations/kubectl.kubernetes.io~1restartedAt',
|
|
35
|
+
value: new Date().toISOString(),
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
return this.context.kubernetes.apps.patchNamespacedDeployment({
|
|
39
|
+
namespace,
|
|
40
|
+
name,
|
|
41
|
+
body: patch,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async listDeployments(namespace) {
|
|
45
|
+
const { items } = await this.context.kubernetes.apps.listNamespacedDeployment({
|
|
46
|
+
namespace,
|
|
47
|
+
});
|
|
48
|
+
return items.map((i) => i.metadata?.name);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './RestartPodsOperation.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './RestartPodsOperation.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import deepmerge from '@fastify/deepmerge';
|
|
2
2
|
import { glob } from 'glob';
|
|
3
|
-
import { dirname } from 'node:path';
|
|
3
|
+
import { basename, dirname } from 'node:path';
|
|
4
4
|
import { MonorepoConfig } from '../index.js';
|
|
5
5
|
import { AbstractPlugin } from './plugin.js';
|
|
6
6
|
export const AutoDockerPluginDefaultOptions = {
|
|
@@ -22,9 +22,11 @@ export class AutoDockerPlugin extends AbstractPlugin {
|
|
|
22
22
|
cwd: this.monorepo.rootDir,
|
|
23
23
|
});
|
|
24
24
|
const overrides = files.reduce((cmps, path) => {
|
|
25
|
-
const
|
|
25
|
+
const rootDir = dirname(path);
|
|
26
|
+
const name = basename(rootDir);
|
|
26
27
|
const component = config.components[name];
|
|
27
28
|
const cfg = {
|
|
29
|
+
rootDir,
|
|
28
30
|
resources: {
|
|
29
31
|
image: {
|
|
30
32
|
type: 'docker/image',
|
|
@@ -24,6 +24,7 @@ export class EmbfileLoaderPlugin extends AbstractPlugin {
|
|
|
24
24
|
const files = await glob(this.config.glob, {
|
|
25
25
|
...this.config,
|
|
26
26
|
cwd: this.monorepo.rootDir,
|
|
27
|
+
follow: true,
|
|
27
28
|
});
|
|
28
29
|
const newConfig = await files.reduce(async (pConfig, path) => {
|
|
29
30
|
const config = await pConfig;
|
|
@@ -2,10 +2,12 @@ import { Writable } from 'node:stream';
|
|
|
2
2
|
import { CreateFileOperation, IResourceBuilder, ResourceInfo } from '../index.js';
|
|
3
3
|
import { OpInput, OpOutput } from '../../operations/index.js';
|
|
4
4
|
import { ResourceBuildContext } from './ResourceFactory.js';
|
|
5
|
-
export declare class FileResourceBuilder implements IResourceBuilder<OpInput<CreateFileOperation>, OpOutput<CreateFileOperation>,
|
|
5
|
+
export declare class FileResourceBuilder implements IResourceBuilder<OpInput<CreateFileOperation>, OpOutput<CreateFileOperation>, boolean> {
|
|
6
6
|
protected context: ResourceBuildContext<OpInput<CreateFileOperation>>;
|
|
7
7
|
constructor(context: ResourceBuildContext<OpInput<CreateFileOperation>>);
|
|
8
8
|
getReference(): Promise<string>;
|
|
9
|
+
getPath(): Promise<string>;
|
|
10
|
+
mustBuild(): Promise<true | undefined>;
|
|
9
11
|
build(resource: ResourceInfo<OpInput<CreateFileOperation>>, out?: Writable): Promise<{
|
|
10
12
|
input: {
|
|
11
13
|
path: string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { statfs } from 'node:fs/promises';
|
|
1
2
|
import { CreateFileOperation, } from '../index.js';
|
|
2
3
|
import { ResourceFactory } from './ResourceFactory.js';
|
|
3
4
|
export class FileResourceBuilder {
|
|
@@ -8,9 +9,20 @@ export class FileResourceBuilder {
|
|
|
8
9
|
async getReference() {
|
|
9
10
|
return this.context.component.relative(this.context.config.params?.path || this.context.config.name);
|
|
10
11
|
}
|
|
12
|
+
async getPath() {
|
|
13
|
+
return this.context.component.join(this.context.config.params?.path || this.context.config.name);
|
|
14
|
+
}
|
|
15
|
+
async mustBuild() {
|
|
16
|
+
try {
|
|
17
|
+
await statfs(await this.getPath());
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
11
23
|
async build(resource, out) {
|
|
12
24
|
const input = {
|
|
13
|
-
path: await this.
|
|
25
|
+
path: await this.getPath(),
|
|
14
26
|
script: resource.params?.script,
|
|
15
27
|
cwd: this.context.component.join('./'),
|
|
16
28
|
};
|
package/dist/src/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type Docker from 'dockerode';
|
|
2
|
+
import { AppsV1Api, CoreV1Api, KubeConfig } from '@kubernetes/client-node';
|
|
2
3
|
import { Monorepo } from './monorepo/index.js';
|
|
3
4
|
import { DockerComposeClient } from './docker/index.js';
|
|
4
5
|
/**
|
|
@@ -11,5 +12,10 @@ import { DockerComposeClient } from './docker/index.js';
|
|
|
11
12
|
export interface EmbContext {
|
|
12
13
|
compose: DockerComposeClient;
|
|
13
14
|
docker: Docker;
|
|
15
|
+
kubernetes: {
|
|
16
|
+
config: KubeConfig;
|
|
17
|
+
apps: AppsV1Api;
|
|
18
|
+
core: CoreV1Api;
|
|
19
|
+
};
|
|
14
20
|
monorepo: Monorepo;
|
|
15
21
|
}
|
package/dist/src/utils/time.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { DateTime } from 'luxon';
|
|
2
|
-
export declare const timeAgo: (date: Date | DateTime) => string;
|
|
2
|
+
export declare const timeAgo: (date: Date | DateTime | null | undefined) => string;
|
package/dist/src/utils/time.js
CHANGED
|
@@ -1,19 +1,30 @@
|
|
|
1
|
-
import { DateTime } from 'luxon';
|
|
2
|
-
const units = [
|
|
3
|
-
'year',
|
|
4
|
-
'month',
|
|
5
|
-
'week',
|
|
6
|
-
'day',
|
|
7
|
-
'hour',
|
|
8
|
-
'minute',
|
|
9
|
-
'second',
|
|
10
|
-
];
|
|
11
1
|
export const timeAgo = (date) => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
2
|
+
if (!date) {
|
|
3
|
+
return '';
|
|
4
|
+
}
|
|
5
|
+
const now = Date.now();
|
|
6
|
+
const then = date instanceof Date ? date.getTime() : date.toJSDate().getTime();
|
|
7
|
+
const diff = Math.max(0, now - then); // in ms
|
|
8
|
+
let seconds = Math.floor(diff / 1000);
|
|
9
|
+
const units = [
|
|
10
|
+
{ label: 'y', secs: 60 * 60 * 24 * 365 },
|
|
11
|
+
{ label: 'mo', secs: 60 * 60 * 24 * 30 },
|
|
12
|
+
{ label: 'w', secs: 60 * 60 * 24 * 7 },
|
|
13
|
+
{ label: 'd', secs: 60 * 60 * 24 },
|
|
14
|
+
{ label: 'h', secs: 60 * 60 },
|
|
15
|
+
{ label: 'm', secs: 60 },
|
|
16
|
+
{ label: 's', secs: 1 },
|
|
17
|
+
];
|
|
18
|
+
const parts = [];
|
|
19
|
+
for (const { label, secs } of units) {
|
|
20
|
+
const value = Math.floor(seconds / secs);
|
|
21
|
+
if (value > 0) {
|
|
22
|
+
parts.push(`${value}${label}`);
|
|
23
|
+
seconds -= value * secs;
|
|
24
|
+
}
|
|
25
|
+
if (parts.length === 2) {
|
|
26
|
+
break;
|
|
27
|
+
} // only 2 units max
|
|
28
|
+
}
|
|
29
|
+
return parts.join('');
|
|
19
30
|
};
|
package/oclif.manifest.json
CHANGED
|
@@ -777,6 +777,166 @@
|
|
|
777
777
|
"push.js"
|
|
778
778
|
]
|
|
779
779
|
},
|
|
780
|
+
"kubernetes:logs": {
|
|
781
|
+
"aliases": [
|
|
782
|
+
"logs"
|
|
783
|
+
],
|
|
784
|
+
"args": {
|
|
785
|
+
"component": {
|
|
786
|
+
"description": "The component you want to see the logs of",
|
|
787
|
+
"name": "component",
|
|
788
|
+
"required": true
|
|
789
|
+
}
|
|
790
|
+
},
|
|
791
|
+
"description": "Follow kubernetes logs.",
|
|
792
|
+
"examples": [
|
|
793
|
+
"<%= config.bin %> <%= command.id %>"
|
|
794
|
+
],
|
|
795
|
+
"flags": {
|
|
796
|
+
"verbose": {
|
|
797
|
+
"name": "verbose",
|
|
798
|
+
"allowNo": true,
|
|
799
|
+
"type": "boolean"
|
|
800
|
+
},
|
|
801
|
+
"namespace": {
|
|
802
|
+
"aliases": [
|
|
803
|
+
"ns"
|
|
804
|
+
],
|
|
805
|
+
"char": "n",
|
|
806
|
+
"description": "The Kubernetes namespace to target",
|
|
807
|
+
"env": "K8S_NAMESPACE",
|
|
808
|
+
"name": "namespace",
|
|
809
|
+
"required": true,
|
|
810
|
+
"hasDynamicHelp": false,
|
|
811
|
+
"multiple": false,
|
|
812
|
+
"type": "option"
|
|
813
|
+
},
|
|
814
|
+
"follow": {
|
|
815
|
+
"char": "f",
|
|
816
|
+
"description": "Follow log output",
|
|
817
|
+
"name": "follow",
|
|
818
|
+
"allowNo": true,
|
|
819
|
+
"type": "boolean"
|
|
820
|
+
}
|
|
821
|
+
},
|
|
822
|
+
"hasDynamicHelp": false,
|
|
823
|
+
"hiddenAliases": [],
|
|
824
|
+
"id": "kubernetes:logs",
|
|
825
|
+
"pluginAlias": "@enspirit/emb",
|
|
826
|
+
"pluginName": "@enspirit/emb",
|
|
827
|
+
"pluginType": "core",
|
|
828
|
+
"strict": true,
|
|
829
|
+
"enableJsonFlag": false,
|
|
830
|
+
"isESM": true,
|
|
831
|
+
"relativePath": [
|
|
832
|
+
"dist",
|
|
833
|
+
"src",
|
|
834
|
+
"cli",
|
|
835
|
+
"commands",
|
|
836
|
+
"kubernetes",
|
|
837
|
+
"logs.js"
|
|
838
|
+
]
|
|
839
|
+
},
|
|
840
|
+
"kubernetes:ps": {
|
|
841
|
+
"aliases": [],
|
|
842
|
+
"args": {},
|
|
843
|
+
"description": "Show running pods.",
|
|
844
|
+
"examples": [
|
|
845
|
+
"<%= config.bin %> <%= command.id %>"
|
|
846
|
+
],
|
|
847
|
+
"flags": {
|
|
848
|
+
"verbose": {
|
|
849
|
+
"name": "verbose",
|
|
850
|
+
"allowNo": true,
|
|
851
|
+
"type": "boolean"
|
|
852
|
+
},
|
|
853
|
+
"namespace": {
|
|
854
|
+
"aliases": [
|
|
855
|
+
"ns"
|
|
856
|
+
],
|
|
857
|
+
"char": "n",
|
|
858
|
+
"description": "The Kubernetes namespace to target",
|
|
859
|
+
"env": "K8S_NAMESPACE",
|
|
860
|
+
"name": "namespace",
|
|
861
|
+
"required": true,
|
|
862
|
+
"hasDynamicHelp": false,
|
|
863
|
+
"multiple": false,
|
|
864
|
+
"type": "option"
|
|
865
|
+
},
|
|
866
|
+
"watch": {
|
|
867
|
+
"name": "watch",
|
|
868
|
+
"allowNo": true,
|
|
869
|
+
"type": "boolean"
|
|
870
|
+
}
|
|
871
|
+
},
|
|
872
|
+
"hasDynamicHelp": false,
|
|
873
|
+
"hiddenAliases": [],
|
|
874
|
+
"id": "kubernetes:ps",
|
|
875
|
+
"pluginAlias": "@enspirit/emb",
|
|
876
|
+
"pluginName": "@enspirit/emb",
|
|
877
|
+
"pluginType": "core",
|
|
878
|
+
"strict": false,
|
|
879
|
+
"enableJsonFlag": false,
|
|
880
|
+
"isESM": true,
|
|
881
|
+
"relativePath": [
|
|
882
|
+
"dist",
|
|
883
|
+
"src",
|
|
884
|
+
"cli",
|
|
885
|
+
"commands",
|
|
886
|
+
"kubernetes",
|
|
887
|
+
"ps.js"
|
|
888
|
+
]
|
|
889
|
+
},
|
|
890
|
+
"kubernetes:restart": {
|
|
891
|
+
"aliases": [],
|
|
892
|
+
"args": {
|
|
893
|
+
"deployment": {
|
|
894
|
+
"description": "The deployment(s) to restart",
|
|
895
|
+
"name": "deployment"
|
|
896
|
+
}
|
|
897
|
+
},
|
|
898
|
+
"description": "Restart pods of an instance.",
|
|
899
|
+
"examples": [
|
|
900
|
+
"<%= config.bin %> <%= command.id %>"
|
|
901
|
+
],
|
|
902
|
+
"flags": {
|
|
903
|
+
"verbose": {
|
|
904
|
+
"name": "verbose",
|
|
905
|
+
"allowNo": true,
|
|
906
|
+
"type": "boolean"
|
|
907
|
+
},
|
|
908
|
+
"namespace": {
|
|
909
|
+
"aliases": [
|
|
910
|
+
"ns"
|
|
911
|
+
],
|
|
912
|
+
"char": "n",
|
|
913
|
+
"description": "The Kubernetes namespace to target",
|
|
914
|
+
"env": "K8S_NAMESPACE",
|
|
915
|
+
"name": "namespace",
|
|
916
|
+
"required": true,
|
|
917
|
+
"hasDynamicHelp": false,
|
|
918
|
+
"multiple": false,
|
|
919
|
+
"type": "option"
|
|
920
|
+
}
|
|
921
|
+
},
|
|
922
|
+
"hasDynamicHelp": false,
|
|
923
|
+
"hiddenAliases": [],
|
|
924
|
+
"id": "kubernetes:restart",
|
|
925
|
+
"pluginAlias": "@enspirit/emb",
|
|
926
|
+
"pluginName": "@enspirit/emb",
|
|
927
|
+
"pluginType": "core",
|
|
928
|
+
"strict": false,
|
|
929
|
+
"enableJsonFlag": false,
|
|
930
|
+
"isESM": true,
|
|
931
|
+
"relativePath": [
|
|
932
|
+
"dist",
|
|
933
|
+
"src",
|
|
934
|
+
"cli",
|
|
935
|
+
"commands",
|
|
936
|
+
"kubernetes",
|
|
937
|
+
"restart.js"
|
|
938
|
+
]
|
|
939
|
+
},
|
|
780
940
|
"resources:build": {
|
|
781
941
|
"aliases": [],
|
|
782
942
|
"args": {
|
|
@@ -998,5 +1158,5 @@
|
|
|
998
1158
|
]
|
|
999
1159
|
}
|
|
1000
1160
|
},
|
|
1001
|
-
"version": "0.
|
|
1161
|
+
"version": "0.12.0"
|
|
1002
1162
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enspirit/emb",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.12.0",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"monorepo",
|
|
7
7
|
"docker",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@fastify/deepmerge": "^3.1.0",
|
|
44
|
+
"@kubernetes/client-node": "1.3.0",
|
|
44
45
|
"@listr2/manager": "^3.0.1",
|
|
45
46
|
"@oclif/core": "^4.5.2",
|
|
46
47
|
"@oclif/plugin-autocomplete": "^3.2.34",
|
|
@@ -48,6 +49,7 @@
|
|
|
48
49
|
"@oclif/plugin-update": "^4.7.3",
|
|
49
50
|
"@oclif/table": "^0.4.12",
|
|
50
51
|
"ajv": "^8.17.1",
|
|
52
|
+
"ansi-escapes": "^7.0.0",
|
|
51
53
|
"colorette": "^2.0.20",
|
|
52
54
|
"docker-compose": "^1.2.0",
|
|
53
55
|
"dockerode": "^4.0.7",
|
|
@@ -140,6 +142,9 @@
|
|
|
140
142
|
},
|
|
141
143
|
"tasks": {
|
|
142
144
|
"description": "List and run tasks"
|
|
145
|
+
},
|
|
146
|
+
"kubernetes": {
|
|
147
|
+
"description": "Manage project instances on kubernetes"
|
|
143
148
|
}
|
|
144
149
|
}
|
|
145
150
|
},
|