@toa.io/operations 0.8.0-dev.0 → 0.8.0-dev.4
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 +5 -5
- package/readme.md +30 -0
- package/src/deployment/factory.js +1 -1
- package/src/deployment/images/composition.Dockerfile +7 -3
- package/src/deployment/images/composition.js +7 -5
- package/src/deployment/images/factory.js +19 -5
- package/src/deployment/images/image.fixtures.js +6 -0
- package/src/deployment/images/image.js +54 -14
- package/src/deployment/images/image.test.js +3 -5
- package/src/deployment/images/service.Dockerfile +3 -3
- package/src/deployment/images/service.js +3 -2
- package/src/deployment/registry.js +4 -1
- package/types/deployment/images/image.d.ts +6 -6
- package/types/deployment/registry.d.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/operations",
|
|
3
|
-
"version": "0.8.0-dev.
|
|
3
|
+
"version": "0.8.0-dev.4",
|
|
4
4
|
"description": "Toa Deployment",
|
|
5
5
|
"homepage": "https://toa.io",
|
|
6
6
|
"author": {
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@toa.io/filesystem": "1.1.0-dev.
|
|
30
|
-
"@toa.io/generic": "0.11.0-dev.
|
|
31
|
-
"@toa.io/yaml": "0.
|
|
29
|
+
"@toa.io/filesystem": "1.1.0-dev.4",
|
|
30
|
+
"@toa.io/generic": "0.11.0-dev.3",
|
|
31
|
+
"@toa.io/yaml": "0.8.0-dev.4",
|
|
32
32
|
"execa": "5.1.1"
|
|
33
33
|
},
|
|
34
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "24d68d70a56717f2f4441cc9884a60f9fee0863e"
|
|
35
35
|
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Toa Operations
|
|
2
|
+
|
|
3
|
+
## Context
|
|
4
|
+
|
|
5
|
+
### Container Registry
|
|
6
|
+
|
|
7
|
+
#### Build Options
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
# context.toa.yaml
|
|
11
|
+
|
|
12
|
+
registry:
|
|
13
|
+
build:
|
|
14
|
+
arguments: [NPM_TOKEN]
|
|
15
|
+
run: echo //npm.pkg.github.com/:_authToken=${NPM_TOKEN} > .npmrc
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`arguments` is a list of environemt varialbes to be passed to `docker build`.
|
|
19
|
+
|
|
20
|
+
`run` is a command(s) to be executed during build. Multiline is supported.
|
|
21
|
+
|
|
22
|
+
```yaml
|
|
23
|
+
# context.toa.yaml
|
|
24
|
+
|
|
25
|
+
registry:
|
|
26
|
+
build:
|
|
27
|
+
run: |
|
|
28
|
+
echo test > .test
|
|
29
|
+
rm .test
|
|
30
|
+
```
|
|
@@ -34,7 +34,7 @@ class Factory {
|
|
|
34
34
|
this.#context = context
|
|
35
35
|
this.#process = new Process()
|
|
36
36
|
|
|
37
|
-
const imagesFactory = new ImagesFactory(context.name, context.runtime)
|
|
37
|
+
const imagesFactory = new ImagesFactory(context.name, context.runtime, context.registry)
|
|
38
38
|
|
|
39
39
|
this.#registry = new Registry(context.registry, imagesFactory, this.#process)
|
|
40
40
|
this.#compositions = context.compositions.map((composition) => this.#composition(composition))
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
FROM node:18.16.0-alpine3.17
|
|
2
2
|
|
|
3
|
+
{{build.arguments}}
|
|
4
|
+
|
|
3
5
|
ENV NODE_ENV=production
|
|
4
|
-
RUN if [ {{registry}} != undefined ]; then npm set registry {{registry}}; fi
|
|
5
|
-
RUN if [ {{proxy}} != undefined ]; then npm set proxy {{proxy}}; fi
|
|
6
|
-
RUN npm i -g @toa.io/runtime@{{version}}
|
|
6
|
+
RUN if [ {{runtime.registry}} != undefined ]; then npm set registry {{runtime.registry}}; fi
|
|
7
|
+
RUN if [ {{runtime.proxy}} != undefined ]; then npm set proxy {{runtime.proxy}}; fi
|
|
8
|
+
RUN npm i -g @toa.io/runtime@{{runtime.version}}
|
|
7
9
|
|
|
8
10
|
WORKDIR /composition
|
|
9
11
|
ADD . .
|
|
@@ -11,4 +13,6 @@ ADD . .
|
|
|
11
13
|
# run 'npm i' in each component
|
|
12
14
|
RUN find . -maxdepth 1 -type d \( ! -name . \) -exec /bin/sh -c "cd '{}' && if [ -f package.json ]; then npm i; fi" \;
|
|
13
15
|
|
|
16
|
+
{{build.run}}
|
|
17
|
+
|
|
14
18
|
CMD toa compose *
|
|
@@ -11,16 +11,18 @@ class Composition extends Image {
|
|
|
11
11
|
|
|
12
12
|
/** @type {string} */
|
|
13
13
|
#name
|
|
14
|
+
|
|
14
15
|
/** @type {toa.norm.Component[]} */
|
|
15
16
|
#components
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
|
-
* @param
|
|
19
|
-
* @param
|
|
20
|
-
* @param
|
|
19
|
+
* @param {string} scope
|
|
20
|
+
* @param {toa.norm.context.Runtime} runtime
|
|
21
|
+
* @param {toa.norm.context.Registry} registry
|
|
22
|
+
* @param {toa.norm.context.Composition} composition
|
|
21
23
|
*/
|
|
22
|
-
constructor (scope, runtime, composition) {
|
|
23
|
-
super(scope, runtime)
|
|
24
|
+
constructor (scope, runtime, registry, composition) {
|
|
25
|
+
super(scope, runtime, registry)
|
|
24
26
|
|
|
25
27
|
this.#name = composition.name
|
|
26
28
|
this.#components = composition.components
|
|
@@ -9,30 +9,44 @@ const { Service } = require('./service')
|
|
|
9
9
|
class Factory {
|
|
10
10
|
/** @type {string} */
|
|
11
11
|
#scope
|
|
12
|
+
|
|
12
13
|
/** @type {toa.norm.context.Runtime} */
|
|
13
14
|
#runtime
|
|
14
15
|
|
|
16
|
+
/** @type {toa.norm.context.Registry} */
|
|
17
|
+
#registry
|
|
18
|
+
|
|
15
19
|
/**
|
|
16
|
-
* @param
|
|
17
|
-
* @param
|
|
20
|
+
* @param {string} scope
|
|
21
|
+
* @param {toa.norm.context.Runtime} runtime
|
|
22
|
+
* @param {toa.norm.context.Registry} registry
|
|
18
23
|
*/
|
|
19
|
-
constructor (scope, runtime) {
|
|
24
|
+
constructor (scope, runtime, registry) {
|
|
20
25
|
this.#scope = scope
|
|
21
26
|
this.#runtime = runtime
|
|
27
|
+
this.#registry = registry
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
/**
|
|
25
31
|
* @returns {Composition}
|
|
26
32
|
*/
|
|
27
33
|
composition (composition) {
|
|
28
|
-
|
|
34
|
+
const instance = new Composition(this.#scope, this.#runtime, this.#registry, composition)
|
|
35
|
+
|
|
36
|
+
instance.tag()
|
|
37
|
+
|
|
38
|
+
return instance
|
|
29
39
|
}
|
|
30
40
|
|
|
31
41
|
/**
|
|
32
42
|
* @returns {Service}
|
|
33
43
|
*/
|
|
34
44
|
service (path, service) {
|
|
35
|
-
|
|
45
|
+
const instance = new Service(this.#scope, this.#runtime, this.#registry, path, service)
|
|
46
|
+
|
|
47
|
+
instance.tag()
|
|
48
|
+
|
|
49
|
+
return instance
|
|
36
50
|
}
|
|
37
51
|
}
|
|
38
52
|
|
|
@@ -25,9 +25,15 @@ const runtime = {
|
|
|
25
25
|
version: generate()
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/** @type {toa.norm.context.Registry} */
|
|
29
|
+
const registry = {
|
|
30
|
+
base: generate()
|
|
31
|
+
}
|
|
32
|
+
|
|
28
33
|
exports.scope = generate()
|
|
29
34
|
exports.name = name
|
|
30
35
|
exports.version = hash(runtime.version + ';' + version)
|
|
31
36
|
exports.Class = Class
|
|
32
37
|
exports.runtime = runtime
|
|
38
|
+
exports.registry = registry
|
|
33
39
|
exports.process = process
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const { join, posix } = require('node:path')
|
|
4
4
|
const { readFile: read, writeFile: write } = require('node:fs/promises')
|
|
5
5
|
|
|
6
|
-
const { hash } = require('@toa.io/generic')
|
|
6
|
+
const { hash, overwrite } = require('@toa.io/generic')
|
|
7
7
|
const { directory } = require('@toa.io/filesystem')
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -22,19 +22,37 @@ class Image {
|
|
|
22
22
|
|
|
23
23
|
/** @type {string} */
|
|
24
24
|
#scope
|
|
25
|
+
|
|
26
|
+
/** @type {toa.norm.context.Registry} */
|
|
27
|
+
#registry
|
|
28
|
+
|
|
25
29
|
/** @type {toa.norm.context.Runtime} */
|
|
26
30
|
#runtime
|
|
31
|
+
|
|
27
32
|
/** @type {string} */
|
|
28
33
|
#type
|
|
29
34
|
|
|
35
|
+
/** @type {{ runtime?: Partial<toa.norm.context.Runtime>, build: object }} */
|
|
36
|
+
#values = { build: { command: 'echo hello' } }
|
|
37
|
+
|
|
30
38
|
/**
|
|
31
|
-
* @param
|
|
32
|
-
* @param
|
|
39
|
+
* @param {string} scope
|
|
40
|
+
* @param {toa.norm.context.Runtime} runtime
|
|
41
|
+
* @param {toa.norm.context.Registry} registry
|
|
33
42
|
*/
|
|
34
|
-
constructor (scope, runtime) {
|
|
43
|
+
constructor (scope, runtime, registry) {
|
|
35
44
|
this.#scope = scope
|
|
45
|
+
this.#registry = registry
|
|
36
46
|
this.#runtime = runtime
|
|
37
47
|
this.#type = this.constructor.name.toLowerCase()
|
|
48
|
+
|
|
49
|
+
this.#setValues()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
tag () {
|
|
53
|
+
const tag = hash(this.#runtime?.version + ';' + this.version)
|
|
54
|
+
|
|
55
|
+
this.reference = posix.join(this.#registry.base ?? '', this.#scope, `${this.#type}-${this.name}:${tag}`)
|
|
38
56
|
}
|
|
39
57
|
|
|
40
58
|
/**
|
|
@@ -51,12 +69,6 @@ class Image {
|
|
|
51
69
|
*/
|
|
52
70
|
get version () {}
|
|
53
71
|
|
|
54
|
-
tag (base) {
|
|
55
|
-
const tag = hash(this.#runtime?.version + ';' + this.version)
|
|
56
|
-
|
|
57
|
-
this.reference = posix.join(base ?? '', this.#scope, `${this.#type}-${this.name}:${tag}`)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
72
|
async prepare (root) {
|
|
61
73
|
if (this.dockerfile === undefined) throw new Error('Dockerfile isn\'t specified')
|
|
62
74
|
|
|
@@ -65,7 +77,7 @@ class Image {
|
|
|
65
77
|
await directory.ensure(path)
|
|
66
78
|
|
|
67
79
|
const template = await read(this.dockerfile, 'utf-8')
|
|
68
|
-
const contents = template.replace(/{{(
|
|
80
|
+
const contents = template.replace(/{{(\S{1,32})}}/g, (_, key) => this.#value(key))
|
|
69
81
|
const ignore = 'Dockerfile'
|
|
70
82
|
|
|
71
83
|
await write(join(path, 'Dockerfile'), contents)
|
|
@@ -76,16 +88,44 @@ class Image {
|
|
|
76
88
|
return path
|
|
77
89
|
}
|
|
78
90
|
|
|
91
|
+
#setValues () {
|
|
92
|
+
this.#values.runtime = this.#runtime
|
|
93
|
+
this.#values.build = overwrite(this.#values.build, this.#registry.build)
|
|
94
|
+
|
|
95
|
+
if (this.#values.build.arguments !== undefined) this.#values.build.arguments = createArguments(this.#values.build.arguments)
|
|
96
|
+
if (this.#values.build.run !== undefined) this.#values.build.run = createRunCommands(this.#values.build.run)
|
|
97
|
+
}
|
|
98
|
+
|
|
79
99
|
/**
|
|
80
100
|
* @param key {string}
|
|
81
101
|
* @returns {string}
|
|
82
102
|
*/
|
|
83
103
|
#value (key) {
|
|
84
|
-
const [, property] = key.split('.')
|
|
104
|
+
const [source, property] = key.split('.')
|
|
105
|
+
|
|
106
|
+
return this.#values[source]?.[property] ?? ''
|
|
107
|
+
}
|
|
108
|
+
}
|
|
85
109
|
|
|
86
|
-
|
|
87
|
-
|
|
110
|
+
function createRunCommands (input) {
|
|
111
|
+
const lines = input.split('\n')
|
|
112
|
+
|
|
113
|
+
return lines.reduce((commands, command) => {
|
|
114
|
+
commands += '\nRUN ' + command
|
|
115
|
+
|
|
116
|
+
return commands
|
|
117
|
+
}, '')
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function createArguments (variables) {
|
|
121
|
+
const args = []
|
|
122
|
+
|
|
123
|
+
for (const variable of variables) {
|
|
124
|
+
args.push('ARG ' + variable)
|
|
125
|
+
args.push(`ENV ${variable}=$${variable}`)
|
|
88
126
|
}
|
|
127
|
+
|
|
128
|
+
return args.join('\n')
|
|
89
129
|
}
|
|
90
130
|
|
|
91
131
|
exports.Image = Image
|
|
@@ -7,15 +7,13 @@ const { generate } = require('randomstring')
|
|
|
7
7
|
let instance
|
|
8
8
|
|
|
9
9
|
beforeEach(() => {
|
|
10
|
-
instance = new fixtures.Class(fixtures.scope, fixtures.runtime)
|
|
10
|
+
instance = new fixtures.Class(fixtures.scope, fixtures.runtime, fixtures.registry)
|
|
11
11
|
})
|
|
12
12
|
|
|
13
13
|
it('should assign url', () => {
|
|
14
|
-
|
|
14
|
+
instance.tag()
|
|
15
15
|
|
|
16
|
-
instance.
|
|
17
|
-
|
|
18
|
-
expect(instance.reference).toEqual(`${registry}/${fixtures.scope}/class-${fixtures.name}:${fixtures.version}`)
|
|
16
|
+
expect(instance.reference).toEqual(`${fixtures.registry.base}/${fixtures.scope}/class-${fixtures.name}:${fixtures.version}`)
|
|
19
17
|
})
|
|
20
18
|
|
|
21
19
|
describe('prepare', () => {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
FROM node:18.16.0-alpine3.17
|
|
2
2
|
|
|
3
3
|
ENV NODE_ENV=production
|
|
4
|
-
RUN if [ {{registry}} != undefined ]; then npm set registry {{registry}}; fi
|
|
5
|
-
RUN if [ {{proxy}} != undefined ]; then npm set proxy {{proxy}}; fi
|
|
6
|
-
RUN npm i -g @toa.io/runtime@{{version}}
|
|
4
|
+
RUN if [ {{runtime.registry}} != undefined ]; then npm set registry {{runtime.registry}}; fi
|
|
5
|
+
RUN if [ {{runtime.proxy}} != undefined ]; then npm set proxy {{runtime.proxy}}; fi
|
|
6
|
+
RUN npm i -g @toa.io/runtime@{{runtime.version}}
|
|
7
7
|
|
|
8
8
|
WORKDIR /service
|
|
9
9
|
ADD . .
|
|
@@ -28,11 +28,12 @@ class Service extends Image {
|
|
|
28
28
|
/**
|
|
29
29
|
* @param {string} scope
|
|
30
30
|
* @param {toa.norm.context.Runtime} runtime
|
|
31
|
+
* @param {toa.norm.context.Registry} registry
|
|
31
32
|
* @param {string} reference
|
|
32
33
|
* @param {toa.deployment.dependency.Service} service
|
|
33
34
|
*/
|
|
34
|
-
constructor (scope, runtime, reference, service) {
|
|
35
|
-
super(scope, runtime)
|
|
35
|
+
constructor (scope, runtime, registry, reference, service) {
|
|
36
|
+
super(scope, runtime, registry)
|
|
36
37
|
|
|
37
38
|
this.service = service.name
|
|
38
39
|
|
|
@@ -65,7 +65,6 @@ class Registry {
|
|
|
65
65
|
#create (type, ...args) {
|
|
66
66
|
const image = this.#factory[type](...args)
|
|
67
67
|
|
|
68
|
-
image.tag(this.#registry?.base)
|
|
69
68
|
this.#images.push(image)
|
|
70
69
|
|
|
71
70
|
return image
|
|
@@ -85,6 +84,10 @@ class Registry {
|
|
|
85
84
|
|
|
86
85
|
const multiarch = this.#registry.platforms !== null
|
|
87
86
|
|
|
87
|
+
if (this.#registry.build?.arguments !== undefined) {
|
|
88
|
+
for (const arg of this.#registry.build.arguments) args.push('--build-arg', `${arg}=${process.env[arg]}`)
|
|
89
|
+
}
|
|
90
|
+
|
|
88
91
|
if (multiarch) {
|
|
89
92
|
const platform = this.#registry.platforms.join(',')
|
|
90
93
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
declare namespace toa.deployment.images {
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
export interface Image {
|
|
4
|
+
readonly reference: string
|
|
5
|
+
readonly context: string
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
tag(): void
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
prepare(root: string): Promise<string>
|
|
10
|
+
}
|
|
11
11
|
|
|
12
12
|
}
|
|
13
13
|
|