@toa.io/operations 0.2.0-dev.3 → 0.2.1-dev.3
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 -3
- package/src/deployment/.deployment/.describe/components.js +19 -0
- package/src/deployment/.deployment/.describe/dependencies.js +18 -0
- package/src/deployment/.deployment/.describe/index.js +9 -0
- package/src/deployment/.deployment/.describe/variables.js +27 -0
- package/src/deployment/.deployment/declare.js +29 -0
- package/src/deployment/.deployment/describe.js +28 -0
- package/src/deployment/.deployment/index.js +9 -0
- package/src/deployment/.deployment/merge.js +42 -0
- package/src/deployment/{assets/chart → chart}/Chart.yaml +1 -1
- package/src/deployment/chart/templates/compositions.yaml +38 -0
- package/src/deployment/chart/templates/proxies.yaml +10 -0
- package/src/deployment/chart/templates/services.yaml +63 -0
- package/src/deployment/chart/templates/variables.yaml +12 -0
- package/src/deployment/chart/values.yaml +47 -0
- package/src/deployment/composition.js +18 -5
- package/src/deployment/deployment.js +55 -49
- package/src/deployment/factory.js +78 -15
- package/src/deployment/images/composition.Dockerfile +14 -0
- package/src/deployment/images/composition.js +50 -0
- package/src/deployment/images/factory.js +39 -0
- package/src/deployment/images/image.js +91 -0
- package/src/deployment/images/index.js +7 -0
- package/src/deployment/images/registry.js +102 -0
- package/src/deployment/images/service.Dockerfile +12 -0
- package/src/deployment/images/service.js +70 -0
- package/src/deployment/operator.js +85 -0
- package/src/deployment/service.js +25 -0
- package/src/process.js +25 -0
- package/test/deployment/deployment.fixtures.js +18 -0
- package/test/deployment/deployment.test.js +41 -0
- package/test/deployment/images/image.fixtures.js +33 -0
- package/test/deployment/images/image.test.js +25 -0
- package/types/deployment/composition.d.ts +13 -0
- package/types/deployment/dependency.d.ts +77 -0
- package/types/deployment/deployment.d.ts +67 -0
- package/types/deployment/factory.d.ts +12 -0
- package/types/deployment/images/factory.d.ts +17 -0
- package/types/deployment/images/image.d.ts +14 -0
- package/types/deployment/images/registry.d.ts +20 -0
- package/types/deployment/index.d.ts +1 -0
- package/types/deployment/operator.d.ts +21 -0
- package/types/deployment/service.d.ts +20 -0
- package/types/process.d.ts +13 -0
- package/LICENSE +0 -22
- package/src/deployment/assets/Dockerfile +0 -10
- package/src/deployment/assets/chart/templates/deployment.yaml +0 -23
- package/src/deployment/assets/chart/values.yaml +0 -18
- package/src/deployment/chart.js +0 -79
- package/src/deployment/compositions.js +0 -60
- package/src/deployment/copy.js +0 -7
- package/src/deployment/directory.js +0 -19
- package/src/deployment/image.js +0 -67
- package/test/deployment/compositions.test.js +0 -31
- package/test/deployment/copositions.fixtures.js +0 -42
- package/test/deployment/image.fixtures.js +0 -26
- package/test/deployment/image.test.js +0 -22
- /package/src/deployment/{assets/chart/templates/service.yaml → chart/templates/components.yaml} +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// noinspection JSUnusedGlobalSymbols,ES6UnusedImports
|
|
2
|
+
|
|
3
|
+
import { Service } from './service'
|
|
4
|
+
import { dependencies } from '@toa.io/norm/types/context'
|
|
5
|
+
|
|
6
|
+
declare namespace toa.deployment {
|
|
7
|
+
|
|
8
|
+
namespace dependency {
|
|
9
|
+
|
|
10
|
+
type Constructor = (instances: dependencies.Instance[], annotation: any) => Declaration
|
|
11
|
+
|
|
12
|
+
type Reference = {
|
|
13
|
+
name: string
|
|
14
|
+
version: string
|
|
15
|
+
repository?: string
|
|
16
|
+
alias?: string
|
|
17
|
+
values?: Object
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type Service = {
|
|
21
|
+
group: string
|
|
22
|
+
name: string
|
|
23
|
+
version: string
|
|
24
|
+
port: number
|
|
25
|
+
ingress?: {
|
|
26
|
+
host: string
|
|
27
|
+
class: string
|
|
28
|
+
annotations?: object
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type Proxy = {
|
|
33
|
+
name: string
|
|
34
|
+
target: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type Variable = {
|
|
38
|
+
name: string
|
|
39
|
+
value?: string | number
|
|
40
|
+
secret?: {
|
|
41
|
+
name: string,
|
|
42
|
+
key: string
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
type Variables = {
|
|
47
|
+
[key: string]: Variable[]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type Declaration = {
|
|
51
|
+
references?: Reference[]
|
|
52
|
+
services?: Service[] // dependency.Service
|
|
53
|
+
proxies?: Proxy[]
|
|
54
|
+
variables?: Variables
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
type Dependency = {
|
|
60
|
+
references?: dependency.Reference[]
|
|
61
|
+
services?: Service[] // deployment.Service
|
|
62
|
+
proxies?: dependency.Proxy[]
|
|
63
|
+
variables?: dependency.Variables
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export namespace dependency {
|
|
69
|
+
export type Declaration = toa.deployment.dependency.Declaration
|
|
70
|
+
export type Reference = toa.deployment.dependency.Reference
|
|
71
|
+
export type Service = toa.deployment.dependency.Service
|
|
72
|
+
export type Proxy = toa.deployment.dependency.Proxy
|
|
73
|
+
export type Variables = toa.deployment.dependency.Variables
|
|
74
|
+
export type Variable = toa.deployment.dependency.Variable
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export type Dependency = toa.deployment.Dependency
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// noinspection ES6UnusedImports,JSUnusedGlobalSymbols
|
|
2
|
+
|
|
3
|
+
import type { Composition } from './composition'
|
|
4
|
+
import type { Service } from './service'
|
|
5
|
+
import type { dependency } from './dependency'
|
|
6
|
+
|
|
7
|
+
declare namespace toa.deployment {
|
|
8
|
+
|
|
9
|
+
interface Declaration {
|
|
10
|
+
apiVersion: string
|
|
11
|
+
type: string
|
|
12
|
+
name: string
|
|
13
|
+
description?: string
|
|
14
|
+
version: string
|
|
15
|
+
appVersion: string
|
|
16
|
+
dependencies: dependency.Reference[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface Contents {
|
|
20
|
+
compositions?: Composition[]
|
|
21
|
+
components?: string[]
|
|
22
|
+
services?: Service[]
|
|
23
|
+
proxies?: dependency.Proxy[]
|
|
24
|
+
variables?: dependency.Variables
|
|
25
|
+
[key: string]: Object
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
namespace installation {
|
|
29
|
+
|
|
30
|
+
interface Options {
|
|
31
|
+
wait?: boolean
|
|
32
|
+
target?: string
|
|
33
|
+
namespace?: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
namespace template {
|
|
39
|
+
interface Options {
|
|
40
|
+
namespace: string
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface Deployable {
|
|
45
|
+
name: string
|
|
46
|
+
image: string
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface Deployment {
|
|
50
|
+
export(target: string): Promise<void>
|
|
51
|
+
|
|
52
|
+
install(options: installation.Options): Promise<void>
|
|
53
|
+
|
|
54
|
+
template(options: template.Options): Promise<string>
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export namespace installation {
|
|
60
|
+
export type Options = toa.deployment.installation.Options
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export namespace template {
|
|
64
|
+
export type Options = toa.deployment.template.Options
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type Deployable = toa.deployment.Deployable
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// noinspection ES6UnusedImports
|
|
2
|
+
|
|
3
|
+
import type { Composition } from '@toa.io/norm/types'
|
|
4
|
+
import type { Image } from './image'
|
|
5
|
+
import type { dependency } from '../dependency'
|
|
6
|
+
|
|
7
|
+
declare namespace toa.deployment.images {
|
|
8
|
+
|
|
9
|
+
interface Factory {
|
|
10
|
+
composition(composition: Composition): Image
|
|
11
|
+
|
|
12
|
+
service(path: string, service: dependency.Service): Image
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type Factory = toa.deployment.images.Factory
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
declare namespace toa.deployment.images {
|
|
2
|
+
|
|
3
|
+
export interface Image {
|
|
4
|
+
readonly reference: string
|
|
5
|
+
readonly context: string
|
|
6
|
+
|
|
7
|
+
tag(base: string): void
|
|
8
|
+
|
|
9
|
+
prepare(root: string): Promise<string>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type Image = toa.deployment.images.Image
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// noinspection ES6UnusedImports
|
|
2
|
+
|
|
3
|
+
import type { Composition } from '@toa.io/norm'
|
|
4
|
+
import type { dependency } from '../dependency'
|
|
5
|
+
import type { Image } from "./image"
|
|
6
|
+
|
|
7
|
+
declare namespace toa.deployment.images {
|
|
8
|
+
|
|
9
|
+
interface Registry {
|
|
10
|
+
composition(composition: Composition): Image
|
|
11
|
+
|
|
12
|
+
service(path: string, service: dependency.Service): Image
|
|
13
|
+
|
|
14
|
+
prepare(target: string): Promise<void>
|
|
15
|
+
|
|
16
|
+
push(): Promise<void>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Dependency, dependency } from './dependency'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// noinspection ES6UnusedImports
|
|
2
|
+
|
|
3
|
+
import { installation, template } from './deployment'
|
|
4
|
+
|
|
5
|
+
declare namespace toa.deployment {
|
|
6
|
+
|
|
7
|
+
interface Operator {
|
|
8
|
+
export(path?: string): Promise<string>
|
|
9
|
+
|
|
10
|
+
prepare(path?: string): Promise<string>
|
|
11
|
+
|
|
12
|
+
build(): Promise<void>
|
|
13
|
+
|
|
14
|
+
install(options?: installation.Options): Promise<void>
|
|
15
|
+
|
|
16
|
+
template(options?: template.Options): Promise<string>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type Operator = toa.deployment.Operator
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// noinspection ES6UnusedImports
|
|
2
|
+
|
|
3
|
+
import type { Deployable } from './deployment'
|
|
4
|
+
|
|
5
|
+
declare namespace toa.deployment {
|
|
6
|
+
|
|
7
|
+
interface Ingress {
|
|
8
|
+
host: string
|
|
9
|
+
class: string
|
|
10
|
+
annotations?: object
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface Service extends Deployable {
|
|
14
|
+
port: number
|
|
15
|
+
ingress?: Ingress
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type Service = toa.deployment.Service
|
package/LICENSE
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
Copyright (c) 2020-present Artem Gurtovoi
|
|
2
|
-
|
|
3
|
-
MIT License
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
-
a copy of this software and associated documentation files (the
|
|
7
|
-
"Software"), to deal in the Software without restriction, including
|
|
8
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
-
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
-
the following conditions:
|
|
12
|
-
|
|
13
|
-
The above copyright notice and this permission notice shall be
|
|
14
|
-
included in all copies or substantial portions of the Software.
|
|
15
|
-
|
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
{{- range .Values.compositions }}
|
|
2
|
-
apiVersion: apps/v1
|
|
3
|
-
kind: Deployment
|
|
4
|
-
metadata:
|
|
5
|
-
name: composition-{{ required "deployment name is required" .name }}
|
|
6
|
-
spec:
|
|
7
|
-
replicas: {{ .replicas | default 2 }}
|
|
8
|
-
selector:
|
|
9
|
-
matchLabels:
|
|
10
|
-
toa.io/composition: {{ .name }}
|
|
11
|
-
template:
|
|
12
|
-
metadata:
|
|
13
|
-
labels:
|
|
14
|
-
toa.io/composition: {{ .name }}
|
|
15
|
-
{{- range .components }}
|
|
16
|
-
{{ . }}: "1"
|
|
17
|
-
{{- end }}
|
|
18
|
-
spec:
|
|
19
|
-
containers:
|
|
20
|
-
- name: {{ .name }}
|
|
21
|
-
image: {{ .image }}
|
|
22
|
-
---
|
|
23
|
-
{{- end }}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# This file just helps with IDE autocompletion and helm debugging. Actually dynamically replaced by ../values.js.
|
|
2
|
-
compositions:
|
|
3
|
-
- name: todos
|
|
4
|
-
image: localhost:5000/todos:0.0.0
|
|
5
|
-
replicas: 2
|
|
6
|
-
components:
|
|
7
|
-
- todos-tasks
|
|
8
|
-
- todos-stats
|
|
9
|
-
- name: messages
|
|
10
|
-
image: localhost:5000/messages:0.0.0
|
|
11
|
-
replicas: 2
|
|
12
|
-
components:
|
|
13
|
-
- users-users
|
|
14
|
-
# TODO: create services only if sync binding is being used by a component
|
|
15
|
-
components:
|
|
16
|
-
- todos-tasks
|
|
17
|
-
- todos-stats
|
|
18
|
-
- users-users
|
package/src/deployment/chart.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
class Chart {
|
|
4
|
-
name
|
|
5
|
-
|
|
6
|
-
#context
|
|
7
|
-
#compositions
|
|
8
|
-
#dependencies
|
|
9
|
-
|
|
10
|
-
constructor (context, compositions) {
|
|
11
|
-
this.name = context.name
|
|
12
|
-
|
|
13
|
-
this.#context = context
|
|
14
|
-
this.#compositions = compositions
|
|
15
|
-
this.#dependencies = Chart.dependencies(context)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
get declaration () {
|
|
19
|
-
const { name, description, version } = this.#context
|
|
20
|
-
const dependencies = this.#dependencies.map((dependency) => dependency.chart)
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
apiVersion: 'v2',
|
|
24
|
-
type: 'application',
|
|
25
|
-
name,
|
|
26
|
-
description,
|
|
27
|
-
version,
|
|
28
|
-
appVersion: version,
|
|
29
|
-
dependencies
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
get values () {
|
|
34
|
-
const result = {}
|
|
35
|
-
|
|
36
|
-
result.compositions = this.#deployments()
|
|
37
|
-
result.components = this.#context.components.map((component) => component.domain + '-' + component.name)
|
|
38
|
-
|
|
39
|
-
for (const { chart, values } of this.#dependencies) result[chart.alias || chart.name] = values
|
|
40
|
-
|
|
41
|
-
return result
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
#deployments () {
|
|
45
|
-
return Array.from(this.#compositions).map((composition) => {
|
|
46
|
-
const { name, components, replicas, image: { tag: image } } = composition
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
name,
|
|
50
|
-
components: components.map((component) => component.locator.label),
|
|
51
|
-
replicas,
|
|
52
|
-
image
|
|
53
|
-
}
|
|
54
|
-
})
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
static dependencies (context) {
|
|
58
|
-
const map = (map) => {
|
|
59
|
-
const list = []
|
|
60
|
-
|
|
61
|
-
for (const [key, values] of Object.entries(map)) {
|
|
62
|
-
const dependency = require(key)
|
|
63
|
-
|
|
64
|
-
if (dependency.deployments !== undefined) list.push(...dependency.deployments(values))
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return list
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const dependencies = []
|
|
71
|
-
|
|
72
|
-
if (context.connectors !== undefined) dependencies.push(...map(context.connectors))
|
|
73
|
-
if (context.extensions !== undefined) dependencies.push(...map(context.extensions))
|
|
74
|
-
|
|
75
|
-
return dependencies
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
exports.Chart = Chart
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
class Compositions {
|
|
4
|
-
#compositions
|
|
5
|
-
|
|
6
|
-
constructor (context, instantiate) {
|
|
7
|
-
if (context.compositions === undefined) context.compositions = []
|
|
8
|
-
|
|
9
|
-
Compositions.#resolve(context)
|
|
10
|
-
Compositions.#complete(context)
|
|
11
|
-
|
|
12
|
-
this.#compositions = context.compositions.map(instantiate)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
[Symbol.iterator] = () => this.#compositions.values()
|
|
16
|
-
|
|
17
|
-
static #resolve (context) {
|
|
18
|
-
const map = {}
|
|
19
|
-
|
|
20
|
-
for (const component of context.components) {
|
|
21
|
-
const id = component.locator.id
|
|
22
|
-
|
|
23
|
-
map[id] = component
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
for (const composition of context.compositions) {
|
|
27
|
-
composition.components = composition.components.map((id) => {
|
|
28
|
-
const component = map[id]
|
|
29
|
-
|
|
30
|
-
if (component === undefined) {
|
|
31
|
-
throw new Error(`Unknown component '${id}' within composition '${composition.name}'`)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return component
|
|
35
|
-
})
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
static #complete (context) {
|
|
40
|
-
const composed = new Set(context.compositions.map((composition) =>
|
|
41
|
-
composition.components.map((component) => component.locator.id)
|
|
42
|
-
).flat())
|
|
43
|
-
|
|
44
|
-
const names = new Set(context.compositions.map((composition) => composition.name))
|
|
45
|
-
|
|
46
|
-
for (const component of context.components) {
|
|
47
|
-
const { id, label } = component.locator
|
|
48
|
-
|
|
49
|
-
if (composed.has(id)) continue
|
|
50
|
-
if (names.has(label)) throw new Error(`Duplicate composition name '${label}'`)
|
|
51
|
-
|
|
52
|
-
context.compositions.push({
|
|
53
|
-
name: label,
|
|
54
|
-
components: [component]
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
exports.Compositions = Compositions
|
package/src/deployment/copy.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const fs = require('node:fs/promises')
|
|
4
|
-
const { join } = require('node:path')
|
|
5
|
-
const { tmpdir } = require('node:os')
|
|
6
|
-
|
|
7
|
-
const directory = async (path) => {
|
|
8
|
-
await fs.mkdir(path, { recursive: true })
|
|
9
|
-
|
|
10
|
-
const entries = await fs.readdir(path)
|
|
11
|
-
|
|
12
|
-
if (entries.length > 0) throw new Error('Target directory must be empty')
|
|
13
|
-
|
|
14
|
-
return path
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
directory.temp = async (type) => await fs.mkdtemp(join(tmpdir(), `toa-${type}-`))
|
|
18
|
-
|
|
19
|
-
exports.directory = directory
|
package/src/deployment/image.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { join } = require('node:path')
|
|
4
|
-
const { readFile: read, writeFile: write, rm: remove } = require('node:fs/promises')
|
|
5
|
-
const execa = require('execa')
|
|
6
|
-
|
|
7
|
-
const { hash } = require('@toa.io/gears')
|
|
8
|
-
const { directory } = require('./directory')
|
|
9
|
-
const { copy } = require('./copy')
|
|
10
|
-
|
|
11
|
-
class Image {
|
|
12
|
-
tag
|
|
13
|
-
|
|
14
|
-
#composition
|
|
15
|
-
#registry
|
|
16
|
-
#runtime
|
|
17
|
-
|
|
18
|
-
constructor (composition, context) {
|
|
19
|
-
this.#composition = composition
|
|
20
|
-
this.#registry = context.registry
|
|
21
|
-
this.#runtime = context.runtime
|
|
22
|
-
|
|
23
|
-
this.tag = context.registry + '/' + composition.name + ':' + Image.#tag(composition)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async build () {
|
|
27
|
-
const path = await this.#context()
|
|
28
|
-
const build = execa('docker', ['build', path, '-t', this.tag])
|
|
29
|
-
|
|
30
|
-
build.stdout.pipe(process.stdout)
|
|
31
|
-
|
|
32
|
-
await build
|
|
33
|
-
|
|
34
|
-
await remove(path, { recursive: true })
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async push () {
|
|
38
|
-
const push = execa('docker', ['push', this.tag])
|
|
39
|
-
|
|
40
|
-
push.stdout.pipe(process.stdout)
|
|
41
|
-
|
|
42
|
-
await push
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async #context () {
|
|
46
|
-
const path = await directory.temp('composition')
|
|
47
|
-
const dockerfile = (await read(DOCKERFILE, 'utf-8')).replace('{{version}}', this.#runtime)
|
|
48
|
-
|
|
49
|
-
for (const component of this.#composition.components) {
|
|
50
|
-
await copy(component.path, join(path, component.locator.id))
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
await write(join(path, 'Dockerfile'), dockerfile)
|
|
54
|
-
|
|
55
|
-
return path
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
static #tag (composition) {
|
|
59
|
-
const components = composition.components.map((component) => component.locator.id).join(';')
|
|
60
|
-
|
|
61
|
-
return hash(components)
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const DOCKERFILE = join(__dirname, 'assets/Dockerfile')
|
|
66
|
-
|
|
67
|
-
exports.Image = Image
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const fixtures = require('./copositions.fixtures')
|
|
4
|
-
const { Compositions } = require('../../src/deployment/compositions')
|
|
5
|
-
|
|
6
|
-
const clone = require('clone-deep')
|
|
7
|
-
|
|
8
|
-
let context, compositions
|
|
9
|
-
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
context = clone(fixtures.context)
|
|
12
|
-
compositions = new Compositions(context, fixtures.instantiate)
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
it('should instantiate', () => {
|
|
16
|
-
expect(fixtures.instantiate).toHaveBeenCalledTimes(context.compositions.length)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
it('should be iterable over instances', () => {
|
|
20
|
-
expect(Symbol.iterator in compositions).toEqual(true)
|
|
21
|
-
|
|
22
|
-
for (const composition of compositions) expect(fixtures.instantiate).toHaveReturnedWith(composition)
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
it('should complete compositions', () => {
|
|
26
|
-
expect(context.compositions.length).toBeGreaterThan(fixtures.context.compositions.length)
|
|
27
|
-
|
|
28
|
-
const used = new Set(context.compositions.map((composition) => composition.components).flat())
|
|
29
|
-
|
|
30
|
-
expect(used.size).toEqual(context.components.length)
|
|
31
|
-
})
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { repeat, random } = require('@toa.io/gears')
|
|
4
|
-
const { generate } = require('randomstring')
|
|
5
|
-
|
|
6
|
-
const components = repeat(() => ({
|
|
7
|
-
domain: generate(),
|
|
8
|
-
name: generate(),
|
|
9
|
-
locator: {
|
|
10
|
-
id: generate(),
|
|
11
|
-
label: generate()
|
|
12
|
-
},
|
|
13
|
-
version: random(10) + '.' + random(20) + '.' + random(30)
|
|
14
|
-
}), random(10) + 5)
|
|
15
|
-
|
|
16
|
-
const context = {
|
|
17
|
-
registry: generate(),
|
|
18
|
-
components,
|
|
19
|
-
compositions: []
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
let unused = components.length
|
|
23
|
-
|
|
24
|
-
while (1) {
|
|
25
|
-
const use = random(3) + 1
|
|
26
|
-
const index = components.length - unused
|
|
27
|
-
|
|
28
|
-
if (use >= unused) break
|
|
29
|
-
|
|
30
|
-
context.compositions.push({
|
|
31
|
-
name: generate(),
|
|
32
|
-
components: components.slice(index, index + use)
|
|
33
|
-
.map((component) => component.locator.id)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
unused -= use
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const instantiate = jest.fn(() => generate())
|
|
40
|
-
|
|
41
|
-
exports.context = context
|
|
42
|
-
exports.instantiate = instantiate
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { newid, random, repeat } = require('@toa.io/gears')
|
|
4
|
-
const { join } = require('node:path')
|
|
5
|
-
const { generate } = require('randomstring')
|
|
6
|
-
|
|
7
|
-
const mock = {
|
|
8
|
-
execa: jest.fn(() => ({ stdout: { pipe: jest.fn() } }))
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const composition = {
|
|
12
|
-
name: generate(),
|
|
13
|
-
components: repeat(() => ({ locator: { id: newid() } }), random(5) + 5)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const context = {
|
|
17
|
-
registry: `registry-${newid()}:${random(999) + 5000}`,
|
|
18
|
-
runtime: `${random(9)}.${random(9)}.${random(20)}`
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const DOCKERFILE = join(__dirname, '../src/images/Dockerfile')
|
|
22
|
-
|
|
23
|
-
exports.mock = mock
|
|
24
|
-
exports.composition = composition
|
|
25
|
-
exports.context = context
|
|
26
|
-
exports.DOCKERFILE = DOCKERFILE
|