@toa.io/cli 0.9.2-dev.0 → 0.20.0-alpha.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/package.json +9 -8
- package/readme.md +117 -61
- package/src/commands/build.js +2 -6
- package/src/commands/compose.js +17 -1
- package/src/commands/conceal.js +36 -5
- package/src/commands/env.js +14 -1
- package/src/commands/export/deployment.js +2 -2
- package/src/commands/export/images.js +2 -2
- package/src/commands/key.js +18 -0
- package/src/commands/push.js +19 -0
- package/src/commands/replay.js +23 -0
- package/src/commands/serve.js +2 -3
- package/src/commands/shell.js +22 -0
- package/src/handlers/build.js +2 -2
- package/src/handlers/compose.js +25 -0
- package/src/handlers/conceal.js +52 -2
- package/src/handlers/docker/build.js +61 -0
- package/src/handlers/docker/command.js +23 -0
- package/src/handlers/docker/index.js +9 -0
- package/src/handlers/docker/run.js +39 -0
- package/src/handlers/env.js +61 -9
- package/src/handlers/export/images.js +8 -0
- package/src/handlers/key.js +16 -0
- package/src/handlers/push.js +14 -0
- package/src/handlers/replay.js +24 -3
- package/src/handlers/reveal.js +7 -4
- package/src/handlers/serve.js +5 -4
- package/src/handlers/shell.js +29 -0
- package/src/program.js +10 -3
- package/src/util/find.js +1 -1
- package/src/commands/configure.js +0 -43
- package/src/handlers/.configure/subcommands.js +0 -15
- package/src/handlers/configure.js +0 -46
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0-alpha.0",
|
|
4
4
|
"description": "Toa CLI",
|
|
5
5
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/toa-io/toa#readme",
|
|
@@ -22,14 +22,15 @@
|
|
|
22
22
|
"@toa.io/runtime": "*"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@toa.io/console": "0.
|
|
26
|
-
"@toa.io/generic": "0.
|
|
27
|
-
"@toa.io/kubernetes": "0.
|
|
28
|
-
"@toa.io/norm": "0.
|
|
29
|
-
"@toa.io/yaml": "0.
|
|
30
|
-
"dotenv": "16.
|
|
25
|
+
"@toa.io/console": "0.20.0-alpha.0",
|
|
26
|
+
"@toa.io/generic": "0.20.0-alpha.0",
|
|
27
|
+
"@toa.io/kubernetes": "0.20.0-alpha.0",
|
|
28
|
+
"@toa.io/norm": "0.20.0-alpha.0",
|
|
29
|
+
"@toa.io/yaml": "0.20.0-alpha.0",
|
|
30
|
+
"dotenv": "16.1.1",
|
|
31
31
|
"find-up": "5.0.0",
|
|
32
|
+
"paseto": "3.1.4",
|
|
32
33
|
"yargs": "17.6.2"
|
|
33
34
|
},
|
|
34
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "d047190899218b5249901a01a2a4caec5b34cf09"
|
|
35
36
|
}
|
package/readme.md
CHANGED
|
@@ -1,44 +1,49 @@
|
|
|
1
1
|
# Toa Command Line Interface
|
|
2
2
|
|
|
3
|
+
## Common Options
|
|
4
|
+
|
|
5
|
+
<dl>
|
|
6
|
+
<dt><code>--env</code></dt>
|
|
7
|
+
<dd>Path to the environment variables file (`.env` format)</dd>
|
|
8
|
+
</dl>
|
|
9
|
+
|
|
3
10
|
## Development
|
|
4
11
|
|
|
5
|
-
###
|
|
12
|
+
### compose
|
|
6
13
|
|
|
7
|
-
|
|
8
|
-
with `source /dev/stdin` to apply.
|
|
14
|
+
Run composition.
|
|
9
15
|
|
|
10
16
|
<dl>
|
|
11
|
-
<dt><code>toa
|
|
17
|
+
<dt><code>toa compose [paths]</code></dt>
|
|
12
18
|
<dd>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
<code>--
|
|
16
|
-
<code>--
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
It is assumed you are in the component's directory, use `--path` otherwise.
|
|
19
|
+
<code>paths</code> Glob patterns to look for components.<br/>
|
|
20
|
+
<code>--kill</code> Shutdown composition after it's started<br/>
|
|
21
|
+
<code>--dock</code> Run in Docker using current <code>.env</code>.<br/>
|
|
22
|
+
<code>--context</code> Path to the Context root (default <code>.</code>).<br/>
|
|
23
|
+
<code>--bindnings</code> Override bindings (obsolete).
|
|
24
|
+
</dd>
|
|
25
|
+
</dl>
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
# set new value
|
|
24
|
-
$ toa configure foo 'new value' | source /dev/stdin
|
|
25
|
-
```
|
|
27
|
+
> Note that your `localhost` it is accessible from a container as `host.docker.internal`.
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
# clear key
|
|
29
|
-
$ toa configure bar.baz --reset | source /dev/stdin
|
|
30
|
-
```
|
|
29
|
+
### env
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
<dt><code>toa configure reset</code></dt>
|
|
34
|
-
<dd>Remove Configuration Object.</dd>
|
|
35
|
-
<dt><code>toa configure print</code></dt>
|
|
36
|
-
<dd>Output Configuration Object as YAML.
|
|
31
|
+
Export environment to a `.env` file.
|
|
37
32
|
|
|
38
|
-
<
|
|
33
|
+
<dl>
|
|
34
|
+
<dt><code>toa env [environment]</code></dt>
|
|
35
|
+
<dd>
|
|
36
|
+
<code>environment</code> deployment environment name (default <code>local</code>).<br/>
|
|
37
|
+
<code>--path</code> path to a Context (default <code>.</code>)<br/>
|
|
38
|
+
<code>--as</code> output file path (default <code>.env</code>)<br/>
|
|
39
|
+
<code>--interactive</code> prompt for secret values
|
|
39
40
|
</dd>
|
|
40
41
|
</dl>
|
|
41
42
|
|
|
43
|
+
Credentials specified in the output file are preserved.
|
|
44
|
+
|
|
45
|
+
> It is recommended to add `.env*` to `.gitignore`.
|
|
46
|
+
|
|
42
47
|
### replay
|
|
43
48
|
|
|
44
49
|
[Replay](/extensions/sampling/docs/replay.md) samples. Reports in [TAP](https://testanything.org)
|
|
@@ -47,11 +52,13 @@ format.
|
|
|
47
52
|
<dl>
|
|
48
53
|
<dt><code>toa replay [paths...]</code></dt>
|
|
49
54
|
<dd>
|
|
50
|
-
<code>paths</code>
|
|
51
|
-
<code>--
|
|
52
|
-
<code>--
|
|
53
|
-
<code>--
|
|
54
|
-
<code>--
|
|
55
|
+
<code>paths</code> Path(s) to Component(s) or a Context (default <code>.</code>).<br/>
|
|
56
|
+
<code>--component <id></code> Replay samples for a specified component <code>id</code>.<br/>
|
|
57
|
+
<code>--integration</code> Replay integration tests only.<br/>
|
|
58
|
+
<code>--autonomous</code> Replay autonomous tests only.<br/>
|
|
59
|
+
<code>--operation <name></code> Replay samples for specified operation.<br/>
|
|
60
|
+
<code>--title <regexp></code> Regexp to match sample titles.<br/>
|
|
61
|
+
<code>--dock</code> Run in Docker. Applicable only for component samples.
|
|
55
62
|
</dd>
|
|
56
63
|
</dl>
|
|
57
64
|
|
|
@@ -60,16 +67,15 @@ format.
|
|
|
60
67
|
```shell
|
|
61
68
|
$ toa replay
|
|
62
69
|
$ toa replay ./path/to/component
|
|
63
|
-
$ toa replay ./components/a ./components/b
|
|
70
|
+
$ toa replay ./components/a ./components/b --dock
|
|
64
71
|
$ toa replay ./components/*
|
|
65
72
|
$ toa replay ./path/to/context
|
|
66
73
|
$ toa replay --title "should add numbers"
|
|
67
74
|
```
|
|
68
75
|
|
|
69
|
-
If path is a
|
|
70
|
-
the
|
|
71
|
-
|
|
72
|
-
## Exporting
|
|
76
|
+
If the path is a Context root (containing `context.toa.yaml` file), samples for components within
|
|
77
|
+
the Context will be
|
|
78
|
+
found and replayed sequentially.
|
|
73
79
|
|
|
74
80
|
### export manifest
|
|
75
81
|
|
|
@@ -78,59 +84,109 @@ the context will be found and replayed sequentially.
|
|
|
78
84
|
<dd>Print normalized manifest.
|
|
79
85
|
|
|
80
86
|
<code>--path</code> path to component (default <code>.</code>)<br/>
|
|
81
|
-
<code>--error</code> print errors only
|
|
87
|
+
<code>--error</code> print errors only
|
|
82
88
|
</dd>
|
|
83
89
|
</dl>
|
|
84
90
|
|
|
85
|
-
|
|
91
|
+
## Operations
|
|
86
92
|
|
|
87
|
-
|
|
88
|
-
<dt><code>toa env [environment]</code></dt>
|
|
89
|
-
<dd>Select environment. Set local environment variables to <code>.env</code> file.
|
|
93
|
+
> Some commands use current `kubectl` and `docker` context.
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
<code>--path</code> path to context (default <code>.</code>)<br/>
|
|
93
|
-
</dd>
|
|
94
|
-
</dl>
|
|
95
|
+
### build
|
|
95
96
|
|
|
96
|
-
|
|
97
|
+
Build Docker images.
|
|
97
98
|
|
|
98
|
-
>
|
|
99
|
+
<dl>
|
|
100
|
+
<dt><code>toa build</code></dt>
|
|
101
|
+
<dd>
|
|
102
|
+
<code>--path</code> path to a Context (default <code>.</code>)
|
|
103
|
+
</dd>
|
|
104
|
+
</dl>
|
|
99
105
|
|
|
100
|
-
|
|
106
|
+
### deploy
|
|
101
107
|
|
|
102
|
-
|
|
108
|
+
Deploy a Context.
|
|
103
109
|
|
|
104
|
-
|
|
110
|
+
- Build Docker images.
|
|
111
|
+
- Push Docker images to the registry.
|
|
112
|
+
- Build a Helm chart.
|
|
113
|
+
- Apply the Helm chart to the current Kubernetes context.
|
|
105
114
|
|
|
106
115
|
<dl>
|
|
107
116
|
<dt><code>toa deploy [environment]</code></dt>
|
|
108
|
-
<dd>
|
|
109
|
-
|
|
117
|
+
<dd>
|
|
110
118
|
<code>environment</code> deployment environment name (default <code>default</code>).<br/>
|
|
119
|
+
<code>--path</code> path to a Context (default <code>.</code>)<br/>
|
|
120
|
+
<code>--namespace</code> Kubernetes namespace to apply the Helm chat to<br/>
|
|
121
|
+
<code>--wait</code> wait until all
|
|
122
|
+
Pods [are ready](https://helm.sh/docs/intro/using_helm/#helpful-options-for-installupgraderollback)<br/>
|
|
123
|
+
<code>--dry</code> do not apply the Helm chart
|
|
111
124
|
</dd>
|
|
112
125
|
</dl>
|
|
113
126
|
|
|
114
127
|
### conceal
|
|
115
128
|
|
|
129
|
+
Deploy a generic Kubernetes secret with the prefix `toa-`.
|
|
130
|
+
|
|
131
|
+
<dl>
|
|
132
|
+
<dt><code>toa conceal <secret> <key-values...></code></dt>
|
|
133
|
+
<dd>
|
|
134
|
+
<code>secret</code> Secret name.<br/>
|
|
135
|
+
<code>key-values</code> List of keys and values of the secret as <code>key=value</code>.<br/>
|
|
136
|
+
<code>--namespace</code> Kubernetes namespace where the secret should be deployed.<br/>
|
|
137
|
+
<code>--interactive</code> prompt for secret values<br/>
|
|
138
|
+
<code>--environment</code> environment name for interactive mode<br/>
|
|
139
|
+
<code>--path</code> path to a context for interactive mode
|
|
140
|
+
</dd>
|
|
141
|
+
</dl>
|
|
142
|
+
|
|
143
|
+
> If a secret already exists, then given `key-values` will be added to it.
|
|
144
|
+
|
|
145
|
+
#### Example
|
|
146
|
+
|
|
147
|
+
```shell
|
|
148
|
+
$ toa conceal bindings-amqp-default username=developer password=secret
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### reveal
|
|
152
|
+
|
|
153
|
+
Outputs keys and values of a secret.
|
|
154
|
+
|
|
116
155
|
<dl>
|
|
117
156
|
<dt>
|
|
118
|
-
<code>toa
|
|
119
|
-
<img src="https://img.shields.io/badge/Not_Implemented-red" alt="Not Implemented"/>
|
|
157
|
+
<code>toa reveal <secret></code>
|
|
120
158
|
</dt>
|
|
121
|
-
|
|
159
|
+
</dl>
|
|
160
|
+
|
|
161
|
+
### shell
|
|
122
162
|
|
|
123
|
-
|
|
163
|
+
Run interactive shell inside a disposable pod inside a Kubernetes cluster.
|
|
124
164
|
|
|
125
|
-
<
|
|
126
|
-
<
|
|
165
|
+
<dl>
|
|
166
|
+
<dt>
|
|
167
|
+
<code>toa shell [image]</code>
|
|
168
|
+
</dt>
|
|
169
|
+
<dd>
|
|
170
|
+
<code>image</code> Docker image to Run (default <code>alpine</code>).<br/>
|
|
171
|
+
</dd>
|
|
127
172
|
</dl>
|
|
128
173
|
|
|
129
|
-
|
|
174
|
+
#### Examples
|
|
175
|
+
|
|
176
|
+
```shell
|
|
177
|
+
$ toa shell mongo
|
|
178
|
+
$ toa shell -- ping 1.1 # extra arguments can be passed
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### key
|
|
182
|
+
|
|
183
|
+
Generate a secret PASETO key.
|
|
130
184
|
|
|
131
185
|
<dl>
|
|
132
186
|
<dt>
|
|
133
|
-
<code>toa
|
|
187
|
+
<code>toa key</code>
|
|
134
188
|
</dt>
|
|
135
|
-
<dd>
|
|
189
|
+
<dd>
|
|
190
|
+
<code>--public</code> <code>boolean</code> generate a public/private key pair.<br/>
|
|
191
|
+
</dd>
|
|
136
192
|
</dl>
|
package/src/commands/build.js
CHANGED
|
@@ -4,10 +4,6 @@ const { build } = require('../handlers/build')
|
|
|
4
4
|
|
|
5
5
|
const builder = (yargs) => {
|
|
6
6
|
yargs
|
|
7
|
-
.positional('environment', {
|
|
8
|
-
type: 'string',
|
|
9
|
-
desc: 'Deployment environment'
|
|
10
|
-
})
|
|
11
7
|
.option('path', {
|
|
12
8
|
alias: 'p',
|
|
13
9
|
group: 'Command options:',
|
|
@@ -17,7 +13,7 @@ const builder = (yargs) => {
|
|
|
17
13
|
})
|
|
18
14
|
}
|
|
19
15
|
|
|
20
|
-
exports.command = 'build
|
|
21
|
-
exports.desc = 'Build
|
|
16
|
+
exports.command = 'build'
|
|
17
|
+
exports.desc = 'Build Docker images'
|
|
22
18
|
exports.builder = builder
|
|
23
19
|
exports.handler = build
|
package/src/commands/compose.js
CHANGED
|
@@ -12,10 +12,26 @@ const builder = (yargs) => {
|
|
|
12
12
|
default: '.'
|
|
13
13
|
})
|
|
14
14
|
.array('paths')
|
|
15
|
+
.option('kill', {
|
|
16
|
+
group: 'Command options:',
|
|
17
|
+
type: 'boolean',
|
|
18
|
+
desc: 'Immediate shutdown'
|
|
19
|
+
})
|
|
20
|
+
.option('dock', {
|
|
21
|
+
group: 'Command options:',
|
|
22
|
+
type: 'boolean',
|
|
23
|
+
desc: 'Run in Docker'
|
|
24
|
+
})
|
|
25
|
+
.option('context', {
|
|
26
|
+
group: 'Command options:',
|
|
27
|
+
type: 'string',
|
|
28
|
+
desc: 'Path to the Context (used with --dock)',
|
|
29
|
+
default: '.'
|
|
30
|
+
})
|
|
15
31
|
.option('bindings', {
|
|
16
32
|
group: 'Command options:',
|
|
17
33
|
type: 'string',
|
|
18
|
-
desc: '
|
|
34
|
+
desc: 'OBSOLETE'
|
|
19
35
|
})
|
|
20
36
|
.array('bindings')
|
|
21
37
|
.example([
|
package/src/commands/conceal.js
CHANGED
|
@@ -7,15 +7,46 @@ const builder = (yargs) => {
|
|
|
7
7
|
.positional('secret', {
|
|
8
8
|
type: 'string'
|
|
9
9
|
})
|
|
10
|
-
.positional('key', {
|
|
11
|
-
type: 'string'
|
|
10
|
+
.positional('key-values', {
|
|
11
|
+
type: 'string',
|
|
12
|
+
array: true,
|
|
13
|
+
desc: 'Secret key-value pairs'
|
|
14
|
+
})
|
|
15
|
+
.option('namespace', {
|
|
16
|
+
alias: 'n',
|
|
17
|
+
group: 'Command options:',
|
|
18
|
+
type: 'string',
|
|
19
|
+
desc: 'Target Kubernetes namespace'
|
|
12
20
|
})
|
|
13
|
-
.
|
|
21
|
+
.option('interactive', {
|
|
22
|
+
alias: 'i',
|
|
23
|
+
group: 'Command options:',
|
|
24
|
+
describe: 'Prompt for secrets',
|
|
25
|
+
type: 'boolean',
|
|
26
|
+
default: false
|
|
27
|
+
})
|
|
28
|
+
.option('environment', {
|
|
29
|
+
alias: 'e',
|
|
30
|
+
group: 'Command options:',
|
|
31
|
+
describe: 'Environment name for interactive mode',
|
|
14
32
|
type: 'string'
|
|
15
33
|
})
|
|
34
|
+
.option('path', {
|
|
35
|
+
alias: 'p',
|
|
36
|
+
group: 'Command options:',
|
|
37
|
+
describe: 'Path to a Context for interactive mode',
|
|
38
|
+
type: 'string',
|
|
39
|
+
default: '.'
|
|
40
|
+
})
|
|
41
|
+
.example([
|
|
42
|
+
['$0 conceal -i'],
|
|
43
|
+
['$0 conceal credentials username=developer'],
|
|
44
|
+
['$0 conceal credentials username=developer password=secret'],
|
|
45
|
+
['$0 conceal credentials username=developer --namespace app']
|
|
46
|
+
])
|
|
16
47
|
}
|
|
17
48
|
|
|
18
|
-
exports.command = 'conceal
|
|
19
|
-
exports.desc = 'Deploy a
|
|
49
|
+
exports.command = 'conceal [secret] [key-values...]'
|
|
50
|
+
exports.desc = 'Deploy a secret'
|
|
20
51
|
exports.builder = builder
|
|
21
52
|
exports.handler = conceal
|
package/src/commands/env.js
CHANGED
|
@@ -12,10 +12,23 @@ const builder = (yargs) => {
|
|
|
12
12
|
.option('path', {
|
|
13
13
|
alias: 'p',
|
|
14
14
|
group: 'Command options:',
|
|
15
|
-
describe: 'Path to
|
|
15
|
+
describe: 'Path to a Context',
|
|
16
16
|
type: 'string',
|
|
17
17
|
default: '.'
|
|
18
18
|
})
|
|
19
|
+
.option('as', {
|
|
20
|
+
group: 'Command options:',
|
|
21
|
+
describe: 'Output file path',
|
|
22
|
+
type: 'string',
|
|
23
|
+
default: '.env'
|
|
24
|
+
})
|
|
25
|
+
.option('interactive', {
|
|
26
|
+
alias: 'i',
|
|
27
|
+
group: 'Command options:',
|
|
28
|
+
describe: 'Prompt for secrets',
|
|
29
|
+
type: 'boolean',
|
|
30
|
+
default: false
|
|
31
|
+
})
|
|
19
32
|
}
|
|
20
33
|
|
|
21
34
|
exports.command = 'env [environment]'
|
|
@@ -6,7 +6,7 @@ const builder = (yargs) => {
|
|
|
6
6
|
yargs
|
|
7
7
|
.positional('target', {
|
|
8
8
|
type: 'string',
|
|
9
|
-
desc: '
|
|
9
|
+
desc: 'Path to export to'
|
|
10
10
|
})
|
|
11
11
|
.positional('environment', {
|
|
12
12
|
type: 'string',
|
|
@@ -21,7 +21,7 @@ const builder = (yargs) => {
|
|
|
21
21
|
})
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
exports.command = ['deployment <target>
|
|
24
|
+
exports.command = ['deployment <environment> <target>', 'dep']
|
|
25
25
|
exports.desc = 'Export context deployment'
|
|
26
26
|
exports.builder = builder
|
|
27
27
|
exports.handler = dump
|
|
@@ -6,7 +6,7 @@ const builder = (yargs) => {
|
|
|
6
6
|
yargs
|
|
7
7
|
.positional('target', {
|
|
8
8
|
type: 'string',
|
|
9
|
-
desc: '
|
|
9
|
+
desc: 'Path to export to'
|
|
10
10
|
})
|
|
11
11
|
.option('path', {
|
|
12
12
|
alias: 'p',
|
|
@@ -17,7 +17,7 @@ const builder = (yargs) => {
|
|
|
17
17
|
})
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
exports.command = ['images
|
|
20
|
+
exports.command = ['images <target>', 'img']
|
|
21
21
|
exports.desc = 'Export docker image sources'
|
|
22
22
|
exports.builder = builder
|
|
23
23
|
exports.handler = prepare
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { key } = require('../handlers/key')
|
|
4
|
+
|
|
5
|
+
const builder = (yargs) => {
|
|
6
|
+
yargs
|
|
7
|
+
.option('public', {
|
|
8
|
+
group: 'Command options:',
|
|
9
|
+
describe: 'Generate a public/private key pair',
|
|
10
|
+
type: 'boolean',
|
|
11
|
+
default: false
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
exports.command = 'key'
|
|
16
|
+
exports.desc = 'Generate a secret PASETO key'
|
|
17
|
+
exports.builder = builder
|
|
18
|
+
exports.handler = key
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { push } = require('../handlers/push')
|
|
4
|
+
|
|
5
|
+
const builder = (yargs) => {
|
|
6
|
+
yargs
|
|
7
|
+
.option('path', {
|
|
8
|
+
alias: 'p',
|
|
9
|
+
group: 'Command options:',
|
|
10
|
+
type: 'string',
|
|
11
|
+
desc: 'Path to context',
|
|
12
|
+
default: '.'
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
exports.command = 'push'
|
|
17
|
+
exports.desc = 'Build and push Docker images'
|
|
18
|
+
exports.builder = builder
|
|
19
|
+
exports.handler = push
|
package/src/commands/replay.js
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
const { replay } = require('../handlers/replay')
|
|
6
6
|
|
|
7
|
+
/*
|
|
8
|
+
!!! OPTIONS MUST BE SYNCHRONIZED WITH ../handlers/.replay/args !!!
|
|
9
|
+
*/
|
|
10
|
+
|
|
7
11
|
const builder = (yargs) => {
|
|
8
12
|
yargs
|
|
9
13
|
.positional('paths', {
|
|
@@ -17,6 +21,12 @@ const builder = (yargs) => {
|
|
|
17
21
|
group: 'Command options:',
|
|
18
22
|
describe: 'Replay samples for specified component'
|
|
19
23
|
})
|
|
24
|
+
.option('autonomous', {
|
|
25
|
+
alias: 'a',
|
|
26
|
+
type: 'boolean',
|
|
27
|
+
group: 'Command options:',
|
|
28
|
+
describe: 'Replay autonomous tests only'
|
|
29
|
+
})
|
|
20
30
|
.option('integration', {
|
|
21
31
|
alias: 'i',
|
|
22
32
|
type: 'boolean',
|
|
@@ -35,6 +45,19 @@ const builder = (yargs) => {
|
|
|
35
45
|
group: 'Command options:',
|
|
36
46
|
describe: 'Replay samples with titles matching given regexp'
|
|
37
47
|
})
|
|
48
|
+
.option('dock', {
|
|
49
|
+
alias: 'd',
|
|
50
|
+
type: 'boolean',
|
|
51
|
+
default: false,
|
|
52
|
+
group: 'Command options:',
|
|
53
|
+
describe: 'Replay inside Docker container'
|
|
54
|
+
})
|
|
55
|
+
.option('context', {
|
|
56
|
+
group: 'Command options:',
|
|
57
|
+
type: 'string',
|
|
58
|
+
desc: 'Path to the Context (used with --dock)',
|
|
59
|
+
default: '.'
|
|
60
|
+
})
|
|
38
61
|
}
|
|
39
62
|
|
|
40
63
|
exports.command = 'replay [paths...]'
|
package/src/commands/serve.js
CHANGED
|
@@ -5,15 +5,14 @@ const { serve } = require('../handlers/serve')
|
|
|
5
5
|
const builder = (yargs) => {
|
|
6
6
|
yargs
|
|
7
7
|
.positional('path', {
|
|
8
|
-
alias: 'p',
|
|
9
8
|
group: 'Command options:',
|
|
10
9
|
type: 'string',
|
|
11
|
-
desc: 'Path
|
|
10
|
+
desc: 'Path or a shortcut of an extension',
|
|
12
11
|
default: '.'
|
|
13
12
|
})
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
exports.command = 'serve [path]'
|
|
17
|
-
exports.desc = 'Run service'
|
|
16
|
+
exports.desc = 'Run an extension service'
|
|
18
17
|
exports.builder = builder
|
|
19
18
|
exports.handler = serve
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { shell } = require('../handlers/shell')
|
|
4
|
+
|
|
5
|
+
const builder = (yargs) => {
|
|
6
|
+
yargs
|
|
7
|
+
.positional('image', {
|
|
8
|
+
group: 'Command options:',
|
|
9
|
+
type: 'string',
|
|
10
|
+
desc: 'Docker image',
|
|
11
|
+
default: 'alpine'
|
|
12
|
+
})
|
|
13
|
+
.example([
|
|
14
|
+
['$0 shell'],
|
|
15
|
+
['$0 shell -- ping localhost']
|
|
16
|
+
])
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
exports.command = 'shell [image]'
|
|
20
|
+
exports.desc = 'Run interactive shell from the current Kubernetes context'
|
|
21
|
+
exports.builder = builder
|
|
22
|
+
exports.handler = shell
|
package/src/handlers/build.js
CHANGED
|
@@ -6,9 +6,9 @@ const { context: find } = require('../util/find')
|
|
|
6
6
|
|
|
7
7
|
const build = async (argv) => {
|
|
8
8
|
const path = find(argv.path)
|
|
9
|
-
const
|
|
9
|
+
const registry = await boot.registry(path)
|
|
10
10
|
|
|
11
|
-
await
|
|
11
|
+
await registry.build()
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
exports.build = build
|
package/src/handlers/compose.js
CHANGED
|
@@ -1,14 +1,39 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { pick } = require('@toa.io/generic')
|
|
3
4
|
const boot = require('@toa.io/boot')
|
|
5
|
+
const { version } = require('@toa.io/runtime')
|
|
4
6
|
|
|
7
|
+
const docker = require('./docker')
|
|
5
8
|
const { components: find } = require('../util/find')
|
|
6
9
|
|
|
10
|
+
/**
|
|
11
|
+
* @param {Record<string, string | boolean>} argv
|
|
12
|
+
* @return {Promise<void>}
|
|
13
|
+
*/
|
|
7
14
|
async function compose (argv) {
|
|
15
|
+
console.log('Runtime version:', version)
|
|
16
|
+
|
|
17
|
+
if (argv.dock === true) return dock(argv)
|
|
18
|
+
|
|
8
19
|
const paths = find(argv.paths)
|
|
9
20
|
const composition = await boot.composition(paths, argv)
|
|
10
21
|
|
|
11
22
|
await composition.connect()
|
|
23
|
+
|
|
24
|
+
if (argv.kill === true) await composition.disconnect()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {Record<string, string | string[] | boolean>} argv
|
|
29
|
+
* @return {Promise<void>}
|
|
30
|
+
*/
|
|
31
|
+
async function dock (argv) {
|
|
32
|
+
const repository = await docker.build(argv.context, argv.paths)
|
|
33
|
+
const args = pick(argv, ['kill', 'bindings'])
|
|
34
|
+
const command = docker.command('toa compose *', args)
|
|
35
|
+
|
|
36
|
+
await docker.run(repository, command, argv.env)
|
|
12
37
|
}
|
|
13
38
|
|
|
14
39
|
exports.compose = compose
|
package/src/handlers/conceal.js
CHANGED
|
@@ -1,11 +1,61 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { secrets } = require('@toa.io/kubernetes')
|
|
4
|
+
const boot = require('@toa.io/boot')
|
|
5
|
+
const { context: find } = require('../util/find')
|
|
6
|
+
const { promptSecrets } = require('./env')
|
|
4
7
|
|
|
5
8
|
const conceal = async (argv) => {
|
|
6
|
-
|
|
9
|
+
if (argv.interactive) await concealValues(argv)
|
|
10
|
+
else await concealValue(argv)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function concealValue (argv) {
|
|
14
|
+
if (argv['key-values'].length === 0) throw new Error('Key-values must be passed')
|
|
15
|
+
|
|
16
|
+
const values = argv['key-values'].reduce((values, pair) => {
|
|
17
|
+
const [key, value] = pair.split('=')
|
|
18
|
+
|
|
19
|
+
values[key] = value
|
|
20
|
+
|
|
21
|
+
return values
|
|
22
|
+
}, {})
|
|
23
|
+
|
|
24
|
+
const secret = PREFIX + argv.secret
|
|
25
|
+
|
|
26
|
+
await secrets.upsert(secret, values, argv.namespace)
|
|
27
|
+
}
|
|
7
28
|
|
|
8
|
-
|
|
29
|
+
async function concealValues (argv) {
|
|
30
|
+
const path = find(argv.path)
|
|
31
|
+
const operator = await boot.deployment(path, argv.environment)
|
|
32
|
+
const variables = operator.variables()
|
|
33
|
+
const values = await promptSecrets(variables)
|
|
34
|
+
const groups = groupValues(values)
|
|
35
|
+
|
|
36
|
+
for (const [secret, values] of Object.entries(groups)) {
|
|
37
|
+
await secrets.upsert(secret, values, argv.namespace)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @return {Record<string, Record<string, string>>}
|
|
43
|
+
*/
|
|
44
|
+
function groupValues (values) {
|
|
45
|
+
const secrets = {}
|
|
46
|
+
|
|
47
|
+
for (const [key, value] of Object.entries(values)) {
|
|
48
|
+
const [secret, variable] = key.split('/')
|
|
49
|
+
|
|
50
|
+
if (!(secret in secrets)) secrets[secret] = {}
|
|
51
|
+
|
|
52
|
+
secrets[secret][variable] = value
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return secrets
|
|
9
56
|
}
|
|
10
57
|
|
|
58
|
+
const PREFIX = 'toa-'
|
|
59
|
+
|
|
11
60
|
exports.conceal = conceal
|
|
61
|
+
exports.PREFIX = PREFIX
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { newid } = require('@toa.io/generic')
|
|
4
|
+
const norm = require('@toa.io/norm')
|
|
5
|
+
const { deployment: { Factory } } = require('@toa.io/operations')
|
|
6
|
+
|
|
7
|
+
const find = require('../../util/find')
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {string} contextPath
|
|
11
|
+
* @param {string[]} componentPatterns
|
|
12
|
+
* @return {Promise<string>}
|
|
13
|
+
*/
|
|
14
|
+
async function build (contextPath, componentPatterns) {
|
|
15
|
+
const context = await createContext(contextPath, componentPatterns)
|
|
16
|
+
const factory = new Factory(context)
|
|
17
|
+
const registry = factory.registry()
|
|
18
|
+
|
|
19
|
+
await registry.build()
|
|
20
|
+
|
|
21
|
+
const composition = context.compositions[0].name
|
|
22
|
+
|
|
23
|
+
return `${context.registry.base === undefined ? '' : context.registry.base + '/'}${context.name}/composition-${composition}`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {string} contextPath
|
|
28
|
+
* @param {string[]} componentPatterns
|
|
29
|
+
* @return {Promise<toa.norm.Context>}
|
|
30
|
+
*/
|
|
31
|
+
async function createContext (contextPath, componentPatterns) {
|
|
32
|
+
const contextRoot = find.context(contextPath)
|
|
33
|
+
const context = await norm.context(contextRoot)
|
|
34
|
+
const paths = componentPatterns.map((pattern) => find.components(pattern))
|
|
35
|
+
const components = await loadComponents(paths)
|
|
36
|
+
const rnd = newid().substring(0, 6)
|
|
37
|
+
const name = 'replay-' + rnd
|
|
38
|
+
|
|
39
|
+
context.name += '-' + rnd
|
|
40
|
+
context.compositions = [{ name, components }]
|
|
41
|
+
|
|
42
|
+
return context
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @param {string[]} paths
|
|
47
|
+
* @return {Promise<toa.norm.Component[]>}
|
|
48
|
+
*/
|
|
49
|
+
async function loadComponents (paths) {
|
|
50
|
+
const components = []
|
|
51
|
+
|
|
52
|
+
for (const path of paths) {
|
|
53
|
+
const component = await norm.component(path)
|
|
54
|
+
|
|
55
|
+
components.push(component)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return components
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
exports.build = build
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param {string} command
|
|
5
|
+
* @param {Record<string, any>} args
|
|
6
|
+
*/
|
|
7
|
+
const command = (command, args) => {
|
|
8
|
+
const options = []
|
|
9
|
+
|
|
10
|
+
for (const [name, value] of Object.entries(args)) {
|
|
11
|
+
if (value === undefined) continue
|
|
12
|
+
|
|
13
|
+
options.push('--' + name)
|
|
14
|
+
|
|
15
|
+
if (typeof value !== 'boolean') options.push(`"${value}"`)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const argumentLine = options.join(' ')
|
|
19
|
+
|
|
20
|
+
return command + ' ' + argumentLine
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
exports.command = command
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { spawn, exec } = require('node:child_process')
|
|
4
|
+
const { promisify } = require('node:util')
|
|
5
|
+
|
|
6
|
+
const { promex } = require('@toa.io/generic')
|
|
7
|
+
const { file: { dot } } = require('@toa.io/filesystem')
|
|
8
|
+
|
|
9
|
+
const execute = promisify(exec)
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} repository
|
|
13
|
+
* @param {string} command
|
|
14
|
+
* @param {string} [envFile]
|
|
15
|
+
* @return {Promise<void>}
|
|
16
|
+
*/
|
|
17
|
+
async function run (repository, command, envFile) {
|
|
18
|
+
if (envFile === undefined) envFile = await dot('env')
|
|
19
|
+
|
|
20
|
+
const envArgs = envFile === undefined ? [] : ['--env-file', envFile]
|
|
21
|
+
|
|
22
|
+
const found =
|
|
23
|
+
/** @type {{ stdout: string }} */
|
|
24
|
+
await execute(`docker images -q ${repository} | head -n 1`)
|
|
25
|
+
|
|
26
|
+
const id = found.stdout.trim()
|
|
27
|
+
const args = ['run', '--rm', ...envArgs, id, 'sh', '-c', command]
|
|
28
|
+
const done = promex()
|
|
29
|
+
|
|
30
|
+
const running = await spawn('docker', args, { stdio: 'inherit' })
|
|
31
|
+
|
|
32
|
+
running.on('exit', done.resolve)
|
|
33
|
+
|
|
34
|
+
await done
|
|
35
|
+
|
|
36
|
+
await execute(`docker rmi --force ${id}`)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
exports.run = run
|
package/src/handlers/env.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { join } = require('node:path')
|
|
4
|
+
const readline = require('node:readline/promises')
|
|
5
|
+
const { stdin: input, stdout: output } = require('node:process')
|
|
6
|
+
|
|
4
7
|
const dotenv = require('dotenv')
|
|
5
8
|
const { file } = require('@toa.io/filesystem')
|
|
6
9
|
const boot = require('@toa.io/boot')
|
|
@@ -8,17 +11,20 @@ const { context: find } = require('../util/find')
|
|
|
8
11
|
|
|
9
12
|
async function env (argv) {
|
|
10
13
|
const path = find(argv.path)
|
|
11
|
-
const filepath = join(path,
|
|
14
|
+
const filepath = join(path, argv.as)
|
|
12
15
|
const operator = await boot.deployment(path, argv.environment)
|
|
13
16
|
const variables = operator.variables()
|
|
14
17
|
const currentValues = await read(filepath)
|
|
15
|
-
const values = []
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
const result = merge(variables, currentValues)
|
|
20
|
+
|
|
21
|
+
if (argv.interactive) {
|
|
22
|
+
const secrets = await promptSecrets(result)
|
|
18
23
|
|
|
19
|
-
|
|
24
|
+
mergeSecrets(result, secrets)
|
|
25
|
+
}
|
|
20
26
|
|
|
21
|
-
await write(filepath,
|
|
27
|
+
await write(filepath, result)
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
/**
|
|
@@ -41,25 +47,71 @@ async function read (path) {
|
|
|
41
47
|
* @return {Promise<void>}
|
|
42
48
|
*/
|
|
43
49
|
async function write (path, values) {
|
|
44
|
-
const contents = values.reduce((lines, { name, value }) => lines + `${name}=${value}\n`, '')
|
|
50
|
+
const contents = values.reduce((lines, { name, value }) => lines + `${name}=${value ?? ''}\n`, '')
|
|
45
51
|
|
|
46
52
|
await file.write(path, contents)
|
|
47
53
|
}
|
|
48
54
|
|
|
49
55
|
/**
|
|
50
|
-
* @param {toa.deployment.dependency.Variable[]
|
|
56
|
+
* @param {toa.deployment.dependency.Variable[]} variables
|
|
51
57
|
* @param {Record<string, string>} current
|
|
52
58
|
* @return {toa.deployment.dependency.Variable[]}
|
|
53
59
|
*/
|
|
54
60
|
function merge (variables, current) {
|
|
55
61
|
return variables.map((variable) => {
|
|
56
|
-
if (variable.secret === undefined) return variable
|
|
62
|
+
if (variable.secret === undefined || !current[variable.name]) return variable
|
|
57
63
|
|
|
58
64
|
return {
|
|
59
65
|
name: variable.name,
|
|
60
|
-
value: current[variable.name]
|
|
66
|
+
value: current[variable.name]
|
|
61
67
|
}
|
|
62
68
|
})
|
|
63
69
|
}
|
|
64
70
|
|
|
71
|
+
async function promptSecrets (variables) {
|
|
72
|
+
const rl = readline.createInterface({ input, output })
|
|
73
|
+
const secrets = {}
|
|
74
|
+
|
|
75
|
+
for (const variable of variables) {
|
|
76
|
+
if (variable.secret === undefined) continue
|
|
77
|
+
|
|
78
|
+
const key = getKey(variable.secret)
|
|
79
|
+
|
|
80
|
+
secrets[key] = await promptSecret(key, rl)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
rl.close()
|
|
84
|
+
|
|
85
|
+
return secrets
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function promptSecret (key, rl) {
|
|
89
|
+
if (SECRETS[key] === undefined) SECRETS[key] = await rl.question(`${key}: `)
|
|
90
|
+
|
|
91
|
+
return SECRETS[key]
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {toa.deployment.dependency.Variable[]} variables
|
|
96
|
+
* @param {Record<string, string>} secrets
|
|
97
|
+
*/
|
|
98
|
+
function mergeSecrets (variables, secrets) {
|
|
99
|
+
for (const variable of variables) {
|
|
100
|
+
if (variable.secret === undefined) continue
|
|
101
|
+
|
|
102
|
+
const key = getKey(variable.secret)
|
|
103
|
+
|
|
104
|
+
variable.value = secrets[key]
|
|
105
|
+
|
|
106
|
+
delete variable.secret
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function getKey (secret) {
|
|
111
|
+
return `${secret.name}/${secret.key}`
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const SECRETS = {}
|
|
115
|
+
|
|
65
116
|
exports.env = env
|
|
117
|
+
exports.promptSecrets = promptSecrets
|
|
@@ -13,4 +13,12 @@ const prepare = async (argv) => {
|
|
|
13
13
|
console.log(path)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
// const prepare = async (argv) => {
|
|
17
|
+
// const context = find(argv.path)
|
|
18
|
+
// const registry = await boot.registry(context)
|
|
19
|
+
// const path = await registry.prepare(argv.target)
|
|
20
|
+
//
|
|
21
|
+
// console.log(path)
|
|
22
|
+
// }
|
|
23
|
+
|
|
16
24
|
exports.prepare = prepare
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { V3 } = require('paseto')
|
|
4
|
+
|
|
5
|
+
async function key (argv) {
|
|
6
|
+
const purpose = argv.public ? 'public' : 'local'
|
|
7
|
+
const key = await V3.generateKey(purpose, { format: 'paserk' })
|
|
8
|
+
|
|
9
|
+
if (argv.public) {
|
|
10
|
+
console.log(key.secretKey)
|
|
11
|
+
console.log(key.publicKey)
|
|
12
|
+
} else
|
|
13
|
+
console.log(key)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
exports.key = key
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const boot = require('@toa.io/boot')
|
|
4
|
+
|
|
5
|
+
const { context: find } = require('../util/find')
|
|
6
|
+
|
|
7
|
+
const push = async (argv) => {
|
|
8
|
+
const path = find(argv.path)
|
|
9
|
+
const registry = await boot.registry(path)
|
|
10
|
+
|
|
11
|
+
await registry.push()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
exports.push = push
|
package/src/handlers/replay.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { pick } = require('@toa.io/generic')
|
|
4
|
+
const { context, components } = require('@toa.io/userland/samples')
|
|
5
|
+
|
|
3
6
|
const find = require('../util/find')
|
|
7
|
+
const docker = require('./docker')
|
|
4
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @param {Record<string, string | string[] | boolean>} argv
|
|
11
|
+
* @return {Promise<void>}
|
|
12
|
+
*/
|
|
5
13
|
async function replay (argv) {
|
|
6
|
-
|
|
7
|
-
const { context, components } = require('@toa.io/userland/samples')
|
|
14
|
+
if (argv.dock) return dock(argv)
|
|
8
15
|
|
|
9
16
|
/** @type {boolean} */
|
|
10
17
|
let ok
|
|
@@ -14,9 +21,11 @@ async function replay (argv) {
|
|
|
14
21
|
/** @type {toa.samples.suite.Options} */
|
|
15
22
|
const options = {
|
|
16
23
|
component: argv.component,
|
|
24
|
+
autonomous: argv.autonomous,
|
|
17
25
|
integration: argv.integration,
|
|
18
26
|
operation: argv.operation,
|
|
19
|
-
title: argv.title
|
|
27
|
+
title: argv.title,
|
|
28
|
+
runner: { bail: true }
|
|
20
29
|
}
|
|
21
30
|
|
|
22
31
|
if (paths !== null) {
|
|
@@ -36,6 +45,18 @@ async function replay (argv) {
|
|
|
36
45
|
process.on('beforeExit', () => console.log(message))
|
|
37
46
|
}
|
|
38
47
|
|
|
48
|
+
/**
|
|
49
|
+
* @param {Record<string, string | string[] | boolean>} argv
|
|
50
|
+
* @return {Promise<void>}
|
|
51
|
+
*/
|
|
52
|
+
async function dock (argv) {
|
|
53
|
+
const repository = await docker.build(argv.context, argv.paths)
|
|
54
|
+
const args = pick(argv, ['component', 'operation', 'integration', 'title'])
|
|
55
|
+
const command = docker.command('toa replay *', args)
|
|
56
|
+
|
|
57
|
+
await docker.run(repository, command, argv.env)
|
|
58
|
+
}
|
|
59
|
+
|
|
39
60
|
const GREEN = '\x1b[32m'
|
|
40
61
|
const RED = '\x1b[31m'
|
|
41
62
|
const RESET = '\x1b[0m'
|
package/src/handlers/reveal.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { secrets } = require('@toa.io/kubernetes')
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
const { PREFIX } = require('./conceal')
|
|
5
6
|
|
|
6
7
|
const reveal = async (argv) => {
|
|
7
|
-
const
|
|
8
|
-
const
|
|
8
|
+
const prefixed = PREFIX + argv.secret
|
|
9
|
+
const data = await secrets.get(prefixed)
|
|
10
|
+
|
|
11
|
+
if (data === null) return
|
|
9
12
|
|
|
10
|
-
for (const [key, value] of Object.entries(
|
|
13
|
+
for (const [key, value] of Object.entries(data)) {
|
|
11
14
|
const line = `${key}: ${value}`
|
|
12
15
|
|
|
13
16
|
console.log(line)
|
package/src/handlers/serve.js
CHANGED
|
@@ -3,21 +3,22 @@
|
|
|
3
3
|
const boot = require('@toa.io/boot')
|
|
4
4
|
const { shortcuts } = require('@toa.io/norm')
|
|
5
5
|
const { directory: { find } } = require('@toa.io/filesystem')
|
|
6
|
+
const { version } = require('@toa.io/runtime')
|
|
6
7
|
|
|
7
8
|
const serve = async (argv) => {
|
|
9
|
+
console.log('Runtime version:', version)
|
|
10
|
+
|
|
8
11
|
argv.path = shortcuts.resolve(argv.path)
|
|
9
12
|
|
|
10
13
|
const module = find(argv.path, process.cwd())
|
|
11
14
|
|
|
12
15
|
const { Factory } = require(module)
|
|
13
16
|
|
|
14
|
-
/** @type {toa.core.extensions.Factory} */
|
|
15
17
|
const factory = new Factory(boot)
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
const service = factory.service()
|
|
19
|
+
if (factory.service === undefined) throw new Error(`Service is not implemented by ${argv.path}`)
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
const service = factory.service()
|
|
21
22
|
|
|
22
23
|
await service.connect()
|
|
23
24
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { spawn } = require('node:child_process')
|
|
4
|
+
const { newid } = require('@toa.io/generic')
|
|
5
|
+
|
|
6
|
+
const shell = async (argv) => {
|
|
7
|
+
const rnd = newid().substring(0, 6)
|
|
8
|
+
|
|
9
|
+
const args = [
|
|
10
|
+
'run',
|
|
11
|
+
'shell-' + rnd,
|
|
12
|
+
'--rm',
|
|
13
|
+
'-i',
|
|
14
|
+
'--tty',
|
|
15
|
+
'--image',
|
|
16
|
+
argv.image,
|
|
17
|
+
'--restart=Never',
|
|
18
|
+
'--'
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
const extra = argv._.splice(1)
|
|
22
|
+
|
|
23
|
+
if (extra.length > 0) args.push(...extra)
|
|
24
|
+
else args.push('sh')
|
|
25
|
+
|
|
26
|
+
await spawn('kubectl', args, { stdio: 'inherit' })
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
exports.shell = shell
|
package/src/program.js
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
'use strict'
|
|
4
4
|
|
|
5
|
-
if (!('TOA_ENV' in process.env)) require('dotenv').config()
|
|
6
|
-
|
|
7
5
|
const yargs = require('yargs/yargs')
|
|
8
6
|
|
|
9
7
|
const { console } = require('@toa.io/console')
|
|
@@ -18,16 +16,25 @@ yargs(process.argv.slice(2))
|
|
|
18
16
|
|
|
19
17
|
console.level(argv.log)
|
|
20
18
|
})
|
|
19
|
+
.middleware(async (argv) => {
|
|
20
|
+
if (argv.env === undefined) return
|
|
21
|
+
|
|
22
|
+
require('dotenv').config({ path: /** @type {string} */ argv.env })
|
|
23
|
+
})
|
|
21
24
|
.fail((msg, err) => {
|
|
22
25
|
const actual = err || new Error(msg)
|
|
23
26
|
|
|
24
|
-
console.error(
|
|
27
|
+
console.error(actual)
|
|
25
28
|
|
|
26
29
|
process.exit(actual.exitCode > 0 ? actual.exitCode : 1)
|
|
27
30
|
})
|
|
28
31
|
.option('log', {
|
|
29
32
|
describe: 'Log level'
|
|
30
33
|
})
|
|
34
|
+
.option('env', {
|
|
35
|
+
type: 'string',
|
|
36
|
+
describe: 'Path to environment variables file (.env format)'
|
|
37
|
+
})
|
|
31
38
|
.commandDir('./commands')
|
|
32
39
|
.demandCommand(1, 'A command is required. Pass --help to see all available commands and options.')
|
|
33
40
|
.strict()
|
package/src/util/find.js
CHANGED
|
@@ -17,7 +17,7 @@ const find = (from, filename, test) => {
|
|
|
17
17
|
|
|
18
18
|
if (found.size === 0) {
|
|
19
19
|
if (test === true) return null
|
|
20
|
-
else throw new Error(`File '${filename}' is found in ${from.join(', ')}`)
|
|
20
|
+
else throw new Error(`File '${filename}' is not found in ${from.join(', ')}`)
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
return [...found]
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { configure } = require('../handlers/configure')
|
|
4
|
-
|
|
5
|
-
const builder = (yargs) => {
|
|
6
|
-
yargs
|
|
7
|
-
.positional('key', {
|
|
8
|
-
type: 'string',
|
|
9
|
-
desc: 'Configuration Object key'
|
|
10
|
-
})
|
|
11
|
-
.positional('value', {
|
|
12
|
-
type: 'string',
|
|
13
|
-
desc: 'Key value'
|
|
14
|
-
})
|
|
15
|
-
.option('path', {
|
|
16
|
-
alias: 'p',
|
|
17
|
-
group: 'Command options:',
|
|
18
|
-
describe: 'Path to component',
|
|
19
|
-
type: 'string',
|
|
20
|
-
default: '.'
|
|
21
|
-
})
|
|
22
|
-
.option('reset', {
|
|
23
|
-
group: 'Command options:',
|
|
24
|
-
type: 'boolean',
|
|
25
|
-
desc: 'Remove Configuration Object key'
|
|
26
|
-
})
|
|
27
|
-
.option('json', {
|
|
28
|
-
group: 'Command options:',
|
|
29
|
-
type: 'boolean',
|
|
30
|
-
desc: 'Print as JSON'
|
|
31
|
-
})
|
|
32
|
-
.example([
|
|
33
|
-
['$0 configure myKey \'new value\' | source /dev/stdin'],
|
|
34
|
-
['$0 configure myObject.myKey --reset | source /dev/stdin'],
|
|
35
|
-
['$0 configure reset | source /dev/stdin'],
|
|
36
|
-
['$0 configure print --json']
|
|
37
|
-
])
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
exports.command = 'configure [key] [value]'
|
|
41
|
-
exports.desc = 'Output shell command to update local environment Configuration Object'
|
|
42
|
-
exports.builder = builder
|
|
43
|
-
exports.handler = configure
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { dump } = require('@toa.io/yaml')
|
|
4
|
-
|
|
5
|
-
const reset = (provider) => console.log('unset ' + provider.key)
|
|
6
|
-
|
|
7
|
-
const print = async (provider, argv) => {
|
|
8
|
-
await provider.connect()
|
|
9
|
-
|
|
10
|
-
const formatter = argv.json ? JSON.stringify : dump
|
|
11
|
-
|
|
12
|
-
console.log(formatter(provider.object))
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
exports.subcommands = { print, reset }
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const boot = require('@toa.io/boot')
|
|
4
|
-
|
|
5
|
-
const { Factory } = require('@toa.io/extensions.configuration')
|
|
6
|
-
|
|
7
|
-
const { subcommands } = require('./.configure/subcommands')
|
|
8
|
-
const { components: find } = require('../util/find')
|
|
9
|
-
|
|
10
|
-
async function configure (argv) {
|
|
11
|
-
const path = find(argv.path)
|
|
12
|
-
const manifest = await boot.manifest(path)
|
|
13
|
-
const factory = new Factory()
|
|
14
|
-
const provider = factory.provider(manifest)
|
|
15
|
-
|
|
16
|
-
if (argv.value === undefined && subcommands[argv.key] !== undefined) {
|
|
17
|
-
await subcommands[argv.key](provider, argv)
|
|
18
|
-
|
|
19
|
-
return
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
await provider.connect()
|
|
23
|
-
|
|
24
|
-
let key = argv.key
|
|
25
|
-
let value = argv.value
|
|
26
|
-
|
|
27
|
-
// :(
|
|
28
|
-
if (key !== undefined) {
|
|
29
|
-
if (value === undefined && key.includes('=')) [key, value] = key.split('=')
|
|
30
|
-
|
|
31
|
-
if (value === undefined) {
|
|
32
|
-
if (argv.reset !== true) throw new Error('Key value expected')
|
|
33
|
-
else provider.unset(key)
|
|
34
|
-
} else provider.set(key, value)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
let command
|
|
38
|
-
const exported = provider.export()
|
|
39
|
-
|
|
40
|
-
if (exported === undefined) command = `unset ${provider.key}`
|
|
41
|
-
else command = `export ${provider.key}=` + exported
|
|
42
|
-
|
|
43
|
-
console.log(command)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
exports.configure = configure
|