@ossy/deployment-tools 0.0.44 → 0.0.46
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 +30 -4
- package/cdk.context.json +37 -0
- package/cdk.json +40 -0
- package/package.json +18 -8
- package/src/aws-credentials/aws-credentials.js +74 -0
- package/src/aws-credentials/cli.js +28 -0
- package/src/aws-credentials/index.js +1 -0
- package/src/config/index.js +1 -0
- package/src/{platform-config.js → config/platform-config.js} +24 -5
- package/src/{cli-commands/deploy-handler.js → deploy/cli.js} +12 -6
- package/src/deploy/platform-deployment.js +74 -0
- package/src/{deployment-queue-client.js → deployment-queue/deployment-queue.js} +20 -16
- package/src/deployment-queue/index.js +1 -0
- package/src/index.js +5 -3
- package/src/infrastructure/cli.js +30 -0
- package/src/infrastructure/container-server/aws-profile.js +22 -0
- package/src/infrastructure/container-server/caddy.service.js +69 -0
- package/src/infrastructure/container-server/container-server.js +175 -0
- package/src/infrastructure/container-server/deployment-tools.service.js +37 -0
- package/src/infrastructure/container-server/index.js +3 -0
- package/src/infrastructure/container-server/user-data-commands.js +32 -0
- package/src/infrastructure/establish-trust-stack.js +65 -0
- package/src/infrastructure/platform-stack.js +53 -0
- package/src/log.js +9 -3
- package/src/{caddy-client.js → server/caddy.js} +14 -10
- package/src/server/cli.js +34 -0
- package/src/{docker-client.js → server/docker.js} +16 -16
- package/src/server/platform-server.js +37 -0
- package/src/{ci-rest-api.js → server/rest-api.js} +8 -4
- package/src/template/cli.js +22 -0
- package/src/template/index.js +1 -0
- package/src/{platform-template.js → template/platform-template.js} +9 -5
- package/src/types.js +0 -33
- package/src/aws-credentials-client.js +0 -43
- package/src/cli-commands/index.js +0 -23
- package/src/cli-commands/start-handler.js +0 -24
- package/src/cli-commands/status-handler.js +0 -7
- package/src/cli-commands/stop-handler.js +0 -7
- package/src/platform-cli.js +0 -7
- package/src/platform-client.js +0 -95
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
const { CfnOutput } = require('aws-cdk-lib')
|
|
2
|
+
const { Construct } = require('constructs')
|
|
3
|
+
const {
|
|
4
|
+
Instance,
|
|
5
|
+
InstanceType,
|
|
6
|
+
InstanceClass,
|
|
7
|
+
InstanceSize,
|
|
8
|
+
GenericLinuxImage,
|
|
9
|
+
Vpc,
|
|
10
|
+
SecurityGroup,
|
|
11
|
+
Peer,
|
|
12
|
+
Port,
|
|
13
|
+
UserData
|
|
14
|
+
} = require('aws-cdk-lib/aws-ec2')
|
|
15
|
+
const { HostedZone, ARecord, RecordTarget } = require('aws-cdk-lib/aws-route53')
|
|
16
|
+
const { Role, ServicePrincipal, Policy, PolicyStatement, Effect } = require('aws-cdk-lib/aws-iam')
|
|
17
|
+
const {
|
|
18
|
+
getInstallNodeJs,
|
|
19
|
+
getInstallNpm,
|
|
20
|
+
getInstallDocker
|
|
21
|
+
} = require('./user-data-commands')
|
|
22
|
+
const { CaddyService } = require('./caddy.service')
|
|
23
|
+
const { DeploymentToolsService } = require('./deployment-tools.service')
|
|
24
|
+
const { AwsProfile } = require('./aws-profile')
|
|
25
|
+
const { SupportedRegions } = require('../../config')
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Platform template definition
|
|
29
|
+
* @namespace ContainerServer
|
|
30
|
+
* @typedef {Object} ContainerServerProps
|
|
31
|
+
* @property {PlatformConfig} platformConfig - platform config
|
|
32
|
+
* @property {Bucket} platformConfigBucket - aws bucket
|
|
33
|
+
*/
|
|
34
|
+
const InstanceImages = {
|
|
35
|
+
UBUNTU: 'ami-092cce4a19b438926'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
class ContainerServer extends Construct {
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* EC2 Instance that docker containers are served on
|
|
42
|
+
*
|
|
43
|
+
* @param {object} scope - scope
|
|
44
|
+
* @param {string} id - id
|
|
45
|
+
* @param {ContainerServerProps} props - ContainerServerProps
|
|
46
|
+
*/
|
|
47
|
+
constructor(scope, id, props) {
|
|
48
|
+
super(scope, id)
|
|
49
|
+
|
|
50
|
+
const hostedZone = HostedZone.fromLookup(this, 'HostedZone', { domainName: props.platformConfig.domain })
|
|
51
|
+
|
|
52
|
+
const vpc = Vpc.fromLookup(this, 'VPC', {
|
|
53
|
+
isDefault: true
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const securityGroup = new SecurityGroup(this, 'SecurityGroup', {
|
|
57
|
+
vpc,
|
|
58
|
+
allowAllOutbound: true
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
securityGroup.addIngressRule(
|
|
62
|
+
Peer.anyIpv4(),
|
|
63
|
+
Port.tcp(22),
|
|
64
|
+
'allow SSH access from anywhere'
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
securityGroup.addIngressRule(
|
|
68
|
+
Peer.anyIpv4(),
|
|
69
|
+
Port.tcp(80),
|
|
70
|
+
'allow HTTP traffic from anywhere'
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
securityGroup.addIngressRule(
|
|
74
|
+
Peer.anyIpv4(),
|
|
75
|
+
Port.tcp(443),
|
|
76
|
+
'allow HTTPS traffic from anywhere'
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
const role = new Role(this, 'role', {
|
|
80
|
+
assumedBy: new ServicePrincipal('ec2.amazonaws.com')
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
role.attachInlinePolicy(new Policy(this, 'policy', {
|
|
84
|
+
statements: [
|
|
85
|
+
new PolicyStatement({
|
|
86
|
+
effect: Effect.ALLOW,
|
|
87
|
+
actions: [
|
|
88
|
+
'route53:ListResourceRecordSets',
|
|
89
|
+
'route53:GetChange',
|
|
90
|
+
'route53:ChangeResourceRecordSets'
|
|
91
|
+
],
|
|
92
|
+
resources: [
|
|
93
|
+
`arn:aws:route53:::hostedzone/${hostedZone.hostedZoneId}`,
|
|
94
|
+
'arn:aws:route53:::change/*'
|
|
95
|
+
]
|
|
96
|
+
}),
|
|
97
|
+
new PolicyStatement({
|
|
98
|
+
effect: Effect.ALLOW,
|
|
99
|
+
actions: [
|
|
100
|
+
'route53:ListHostedZonesByName',
|
|
101
|
+
'route53:ListHostedZones'
|
|
102
|
+
],
|
|
103
|
+
resources: ['*']
|
|
104
|
+
})
|
|
105
|
+
]
|
|
106
|
+
}))
|
|
107
|
+
|
|
108
|
+
const userData = UserData.forLinux()
|
|
109
|
+
|
|
110
|
+
userData.addCommands(
|
|
111
|
+
'sudo apt update -y',
|
|
112
|
+
...getInstallNodeJs(),
|
|
113
|
+
...getInstallNpm(),
|
|
114
|
+
...getInstallDocker(),
|
|
115
|
+
'sudo apt-get install awscli --yes',
|
|
116
|
+
...AwsProfile.writeFile(role.roleArn, SupportedRegions.North),
|
|
117
|
+
...CaddyService.install(),
|
|
118
|
+
...DeploymentToolsService.install()
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
userData.addS3DownloadCommand({
|
|
122
|
+
bucket: props.platformConfigBucket,
|
|
123
|
+
bucketKey: 'platform-config.json',
|
|
124
|
+
localFile: '/home/ubuntu/platform-config.json'
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
userData.addCommands(
|
|
128
|
+
'sudo systemctl daemon-reload',
|
|
129
|
+
...CaddyService.enable(),
|
|
130
|
+
...DeploymentToolsService.enable(),
|
|
131
|
+
...CaddyService.start(),
|
|
132
|
+
...DeploymentToolsService.start()
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
const ec2Instance = new Instance(this, 'Ec2Instance', {
|
|
136
|
+
vpc,
|
|
137
|
+
securityGroup,
|
|
138
|
+
userData,
|
|
139
|
+
role,
|
|
140
|
+
instanceType: InstanceType.of(
|
|
141
|
+
InstanceClass.T3,
|
|
142
|
+
InstanceSize.MICRO
|
|
143
|
+
),
|
|
144
|
+
machineImage: new GenericLinuxImage({
|
|
145
|
+
[SupportedRegions.North]: InstanceImages.UBUNTU
|
|
146
|
+
}),
|
|
147
|
+
keyName: props.platformConfig.awsKeyPairName
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
props.platformConfigBucket.grantRead(ec2Instance, '*')
|
|
151
|
+
|
|
152
|
+
// const hostedZone = !!props.createNewHostedZone
|
|
153
|
+
// ? new PublicHostedZone(this, 'HostedZone', { zoneName: props.domain })
|
|
154
|
+
// : HostedZone.fromLookup(this, 'HostedZone', { domainName: props.domain });
|
|
155
|
+
|
|
156
|
+
// eslint-disable-next-line no-new
|
|
157
|
+
new ARecord(this, 'WildcardRecord', {
|
|
158
|
+
zone: hostedZone,
|
|
159
|
+
recordName: `*.${props.platformConfig.activeEnvironment}.${props.platformConfig.domain}`,
|
|
160
|
+
target: RecordTarget.fromIpAddresses(ec2Instance.instancePublicIp)
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
// eslint-disable-next-line no-new
|
|
164
|
+
new CfnOutput(this, 'Intance Ip', {
|
|
165
|
+
value: ec2Instance.instancePublicIp,
|
|
166
|
+
description: 'Public ip of the ec2 instance',
|
|
167
|
+
exportName: 'instanceIp'
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
module.exports = {
|
|
174
|
+
ContainerServer
|
|
175
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const systemdServiceFile = `
|
|
2
|
+
[Unit]
|
|
3
|
+
Description=D
|
|
4
|
+
After=network.target caddy-route53.service
|
|
5
|
+
|
|
6
|
+
[Service]
|
|
7
|
+
EnvironmentFile=/etc/environment
|
|
8
|
+
User=caddy
|
|
9
|
+
Group=caddy
|
|
10
|
+
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
|
11
|
+
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
|
12
|
+
ExecStart=/usr/bin/npx --yes @ossy/deployment-tools start --platforms /home/ubuntu/deployment-platform.json
|
|
13
|
+
Restart=on-failure
|
|
14
|
+
|
|
15
|
+
[Install]
|
|
16
|
+
WantedBy=multi-user.target cloud-init.target
|
|
17
|
+
`
|
|
18
|
+
|
|
19
|
+
class DeploymentToolsService {
|
|
20
|
+
|
|
21
|
+
static install() {
|
|
22
|
+
return [`sudo echo "${systemdServiceFile}" >> /etc/systemd/system/deployment-tools.service`]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static enable() {
|
|
26
|
+
return ['sudo systemctl enable deployment-tools.service']
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static start() {
|
|
30
|
+
return ['sudo systemctl start deployment-tools.service']
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
DeploymentToolsService
|
|
37
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
const getInstallDocker = () => [
|
|
3
|
+
'apt-get remove docker docker-engine docker.io containerd runc',
|
|
4
|
+
`apt-get install \
|
|
5
|
+
apt-transport-https \
|
|
6
|
+
ca-certificates \
|
|
7
|
+
curl \
|
|
8
|
+
gnupg-agent \
|
|
9
|
+
software-properties-common -y`,
|
|
10
|
+
'curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -',
|
|
11
|
+
`sudo add-apt-repository \
|
|
12
|
+
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
|
|
13
|
+
$(lsb_release -cs) \
|
|
14
|
+
stable"`,
|
|
15
|
+
'sudo apt-get update',
|
|
16
|
+
'sudo apt-get install docker-ce docker-ce-cli containerd.io -y'
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
const getInstallNodeJs = () => [
|
|
20
|
+
'curl -sL https://deb.nodesource.com/setup_16.x | sudo bash -',
|
|
21
|
+
'sudo apt-get -y install nodejs'
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
const getInstallNpm = () => [
|
|
25
|
+
'sudo apt install npm'
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
module.exports = {
|
|
29
|
+
getInstallDocker,
|
|
30
|
+
getInstallNodeJs,
|
|
31
|
+
getInstallNpm
|
|
32
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const { Stack, Duration } = require('aws-cdk-lib')
|
|
2
|
+
const {
|
|
3
|
+
OpenIdConnectProvider,
|
|
4
|
+
OpenIdConnectPrincipal,
|
|
5
|
+
Role,
|
|
6
|
+
Effect,
|
|
7
|
+
PolicyDocument,
|
|
8
|
+
PolicyStatement
|
|
9
|
+
} = require('aws-cdk-lib/aws-iam')
|
|
10
|
+
|
|
11
|
+
class EstablishTrustStack extends Stack {
|
|
12
|
+
/**
|
|
13
|
+
* Establishes trust between GithHub and Amazon Web Services.
|
|
14
|
+
* This is needed so that we can interact with Amazon Web Services through
|
|
15
|
+
* GitHub Actions without having to manually provide credentials every time we
|
|
16
|
+
* run a workflow
|
|
17
|
+
*
|
|
18
|
+
* @param {object} scope - scope
|
|
19
|
+
* @param {string} id - id
|
|
20
|
+
* @param {PlatformTemplate} props - PlatformTemplate
|
|
21
|
+
*/
|
|
22
|
+
constructor(scope, id, props) {
|
|
23
|
+
super(scope, id, props)
|
|
24
|
+
|
|
25
|
+
const provider = new OpenIdConnectProvider(this, 'GitHubProvider', {
|
|
26
|
+
url: 'https://token.actions.githubusercontent.com',
|
|
27
|
+
clientIds: ['sts.amazonaws.com']
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const GitHubPrincipal = new OpenIdConnectPrincipal(provider)
|
|
31
|
+
.withConditions({
|
|
32
|
+
StringLike: {
|
|
33
|
+
'token.actions.githubusercontent.com:sub':
|
|
34
|
+
`repo:${props.config.ciGithubActionsRepo}:*`
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
// eslint-disable-next-line no-new
|
|
39
|
+
new Role(this, 'GitHubActionsRole', {
|
|
40
|
+
assumedBy: GitHubPrincipal,
|
|
41
|
+
description: 'Role assumed by GitHubPrincipal for deploying from CI using aws cdk',
|
|
42
|
+
roleName: props.config.awsRoleToAssume,
|
|
43
|
+
maxSessionDuration: Duration.hours(1),
|
|
44
|
+
inlinePolicies: {
|
|
45
|
+
CdkDeploymentPolicy: new PolicyDocument({
|
|
46
|
+
assignSids: true,
|
|
47
|
+
statements: [
|
|
48
|
+
new PolicyStatement({
|
|
49
|
+
effect: Effect.ALLOW,
|
|
50
|
+
actions: ['sts:AssumeRole'],
|
|
51
|
+
resources: [
|
|
52
|
+
`arn:aws:iam::${props.config.awsAccountId}:role/cdk-*`,
|
|
53
|
+
`arn:aws:sqs:${props.config.awsRegion}:${props.config.awsAccountId}:*`
|
|
54
|
+
]
|
|
55
|
+
})
|
|
56
|
+
]
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = {
|
|
64
|
+
EstablishTrustStack
|
|
65
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/* eslint-disable no-new */
|
|
2
|
+
const { Stack, Duration, RemovalPolicy } = require('aws-cdk-lib')
|
|
3
|
+
const { Queue } = require('aws-cdk-lib/aws-sqs')
|
|
4
|
+
const { Bucket, BucketEncryption, BlockPublicAccess } = require('aws-cdk-lib/aws-s3')
|
|
5
|
+
const { Source, BucketDeployment } = require('aws-cdk-lib/aws-s3-deployment')
|
|
6
|
+
|
|
7
|
+
const { ContainerServer } = require('./container-server')
|
|
8
|
+
|
|
9
|
+
const { SupportedDeploymentTypes } = require('../config')
|
|
10
|
+
|
|
11
|
+
class PlatformStack extends Stack {
|
|
12
|
+
constructor(scope, id, props) {
|
|
13
|
+
super(scope, id, props)
|
|
14
|
+
|
|
15
|
+
if (!props?.config) {
|
|
16
|
+
throw ('[PlatformStack] No template config provided')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const isContainerDeploymentsEnabled = props.config.supportedDeploymentTypes.includes(SupportedDeploymentTypes.Container)
|
|
20
|
+
|
|
21
|
+
if (isContainerDeploymentsEnabled) {
|
|
22
|
+
|
|
23
|
+
new Queue(this, 'DeploymentQueue', {
|
|
24
|
+
queueName: `${props.config.platformName}-${props.config.activeEnvironment}`,
|
|
25
|
+
receiveMessageWaitTime: Duration.seconds(20)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const platformConfigBucket = new Bucket(this, 'PlatformConfig', {
|
|
29
|
+
bucketName: `${props.config.platformName}-${props.config.activeEnvironment}`,
|
|
30
|
+
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
|
|
31
|
+
encryption: BucketEncryption.S3_MANAGED,
|
|
32
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
33
|
+
autoDeleteObjects: true
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const platformConfigDeployment = new BucketDeployment(this, 'PlatformConfigDeployment', {
|
|
37
|
+
sources: [Source.jsonData('platform-config.json', props.config)],
|
|
38
|
+
destinationBucket: platformConfigBucket
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
new ContainerServer(this, 'ContainerServer', {
|
|
42
|
+
platformConfig: props.config,
|
|
43
|
+
platformConfigBucket: platformConfigDeployment.deployedBucket
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = {
|
|
52
|
+
PlatformStack
|
|
53
|
+
}
|
package/src/log.js
CHANGED
|
@@ -14,21 +14,27 @@ const TypeOfMessage = {
|
|
|
14
14
|
const log = (...params) => { console.log(...params) }
|
|
15
15
|
const prefixTo = (prefix, message) => `[${prefix}]${message.startsWith('[') ? '' : ': '}`
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
const logInfo = logInput => {
|
|
18
18
|
const messagePrefix = prefixTo(TypeOfMessage.Info, logInput.message)
|
|
19
19
|
log(`${messagePrefix}${logInput.message}`)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
const logError = logInput => {
|
|
23
23
|
const messagePrefix = prefixTo(TypeOfMessage.Error, logInput.message)
|
|
24
24
|
log(`${messagePrefix}${logInput.message}`)
|
|
25
25
|
logInput.error && log('\n[Reason]:', logInput.error, '\n')
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
const logDebug = logInput => {
|
|
29
29
|
const isDebugOn = process.env.DEBUG || false
|
|
30
30
|
if (!isDebugOn) return
|
|
31
31
|
const messagePrefix = prefixTo(TypeOfMessage.Debug, logInput.message)
|
|
32
32
|
log(`${messagePrefix}${logInput.message}`)
|
|
33
33
|
logInput.data && log('\n[Debug data]:', logInput.data, '\n')
|
|
34
34
|
}
|
|
35
|
+
|
|
36
|
+
module.exports = {
|
|
37
|
+
logInfo,
|
|
38
|
+
logError,
|
|
39
|
+
logDebug
|
|
40
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
const fetch = require('node-fetch')
|
|
2
|
+
const { logInfo, logError } = require('../log')
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
const Matchers = {
|
|
5
5
|
host: host => ({ host: [host] }),
|
|
6
6
|
path: path => ({ path: [path] })
|
|
7
7
|
}
|
|
@@ -17,13 +17,13 @@ const Handlers = {
|
|
|
17
17
|
})
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
class CaddyService {
|
|
21
21
|
|
|
22
|
-
static
|
|
22
|
+
static addDeployment(platformConfig, deploymentRequest) {
|
|
23
23
|
|
|
24
24
|
const url = `${deploymentRequest.subdomain}.${platformConfig.activeEnvironment}.${platformConfig.domain}`
|
|
25
25
|
|
|
26
|
-
logInfo({ message: `[
|
|
26
|
+
logInfo({ message: `[CaddyService] Updating caddy config to route ${url} to localhost:${deploymentRequest.hostPort}` })
|
|
27
27
|
|
|
28
28
|
return fetch(`http://localhost:2019/config/apps/http/servers/${platformConfig.ciServerName}/routes/0/handle`, {
|
|
29
29
|
method: 'POST',
|
|
@@ -35,11 +35,11 @@ export class CaddyClient {
|
|
|
35
35
|
}
|
|
36
36
|
]))
|
|
37
37
|
})
|
|
38
|
-
.catch(error => logError({ message: `[
|
|
38
|
+
.catch(error => logError({ message: `[CaddyService] Could not update caddy config to include ${url}`, error }))
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
static
|
|
42
|
-
logInfo({ message: '[
|
|
41
|
+
static applyDefaultConfig(platformConfig) {
|
|
42
|
+
logInfo({ message: '[CaddyService] Applying default caddy config' })
|
|
43
43
|
return fetch('http://localhost:2019/load', {
|
|
44
44
|
method: 'POST',
|
|
45
45
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -101,7 +101,11 @@ export class CaddyClient {
|
|
|
101
101
|
}
|
|
102
102
|
})
|
|
103
103
|
})
|
|
104
|
-
.catch(error => logError({ message: '[
|
|
104
|
+
.catch(error => logError({ message: '[CaddyService] Could not apply default caddy config', error }))
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
}
|
|
108
|
+
|
|
109
|
+
module.exports = {
|
|
110
|
+
CaddyService
|
|
111
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const arg = require('arg')
|
|
3
|
+
const { exec } = require('child_process')
|
|
4
|
+
const { PlatformClient } = require('./platform-server')
|
|
5
|
+
|
|
6
|
+
const { logInfo, logError } = require('../log')
|
|
7
|
+
|
|
8
|
+
//eslint-disable-next-line no-unused-vars
|
|
9
|
+
const [_, __, command, ...restArgs] = process.argv
|
|
10
|
+
|
|
11
|
+
const start = cliArgs => {
|
|
12
|
+
logInfo({ message: 'Running start command' })
|
|
13
|
+
|
|
14
|
+
const parsedArgs = arg({
|
|
15
|
+
'--platforms': String,
|
|
16
|
+
'-p': '--platforms'
|
|
17
|
+
}, { argv: cliArgs })
|
|
18
|
+
|
|
19
|
+
PlatformClient.start(parsedArgs['--platforms'])
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const status = () => {
|
|
23
|
+
logInfo({ message: 'Running status command' })
|
|
24
|
+
exec('systemctl status deployment-tools.service')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const stop = () => {
|
|
28
|
+
logInfo({ message: 'Running stop command' })
|
|
29
|
+
exec('systemctl stop deployment-tools.service')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
!!command
|
|
33
|
+
? { start, status, stop }[command]()
|
|
34
|
+
: logError({ message: 'No command provided' })
|
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import path from 'path'
|
|
5
|
-
import { fileURLToPath } from 'url'
|
|
6
|
-
import { logInfo, logError } from './log.js'
|
|
1
|
+
const { exec } = require('child_process')
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
const { nanoid } = require('nanoid')
|
|
7
4
|
|
|
8
|
-
const
|
|
9
|
-
const __dirname = path.dirname(__filename)
|
|
5
|
+
const { logInfo, logError } = require('../log')
|
|
10
6
|
|
|
11
|
-
|
|
7
|
+
class DockerService {
|
|
12
8
|
|
|
13
9
|
static createDockerNetworkForContainerManagerServer(platformConfig) {
|
|
14
|
-
logInfo({ message: '[
|
|
10
|
+
logInfo({ message: '[DockerService] Creating docker network for comunication between containers' })
|
|
15
11
|
exec(`sudo docker network create ${platformConfig.ciDockerNetworkName}`)
|
|
16
12
|
}
|
|
17
13
|
|
|
@@ -46,9 +42,9 @@ export class DockerClient {
|
|
|
46
42
|
logInfo({ message: 'Starting docker deployment sequence' })
|
|
47
43
|
|
|
48
44
|
const dockerCommandScript = `'#!/bin/bash'
|
|
49
|
-
${
|
|
50
|
-
${
|
|
51
|
-
${
|
|
45
|
+
${DockerService.stopContainer(deploymentRequest)}
|
|
46
|
+
${DockerService.resolveCredentials(deploymentRequest)}
|
|
47
|
+
${DockerService.startContainer(platformConfig, deploymentRequest)}`
|
|
52
48
|
|
|
53
49
|
const deploymentId = nanoid()
|
|
54
50
|
|
|
@@ -60,15 +56,15 @@ ${DockerClient.startContainer(platformConfig, deploymentRequest)}`
|
|
|
60
56
|
const command = exec(`bash ${FilePaths.DeploymentScript}`)
|
|
61
57
|
|
|
62
58
|
command.stdout.on('data', data => {
|
|
63
|
-
logInfo({ message: `[
|
|
59
|
+
logInfo({ message: `[DockerService]: ${data}` })
|
|
64
60
|
})
|
|
65
61
|
|
|
66
62
|
command.stderr.on('data', (data) => {
|
|
67
|
-
logError({ message: `[
|
|
63
|
+
logError({ message: `[DockerService]: ${data}` })
|
|
68
64
|
})
|
|
69
65
|
|
|
70
66
|
command.on('close', code => {
|
|
71
|
-
logInfo({ message: `[
|
|
67
|
+
logInfo({ message: `[DockerService] command exited with code ${code}` })
|
|
72
68
|
fs.unlinkSync(FilePaths.DeploymentScript)
|
|
73
69
|
resolve()
|
|
74
70
|
})
|
|
@@ -77,3 +73,7 @@ ${DockerClient.startContainer(platformConfig, deploymentRequest)}`
|
|
|
77
73
|
}
|
|
78
74
|
|
|
79
75
|
}
|
|
76
|
+
|
|
77
|
+
module.exports = {
|
|
78
|
+
DockerService
|
|
79
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const { CaddyService } = require('./caddy')
|
|
2
|
+
const { DockerService } = require('./docker')
|
|
3
|
+
const { RestApiService } = require('./rest-api')
|
|
4
|
+
|
|
5
|
+
const { PlatformTemplateService } = require('../template')
|
|
6
|
+
const { PlatformConfigService } = require('../config')
|
|
7
|
+
const { DeploymentQueueClient } = require('../deployment-queue')
|
|
8
|
+
const { logError } = require('../log')
|
|
9
|
+
|
|
10
|
+
// journalctl -u service-name.service
|
|
11
|
+
class PlatformServerService {
|
|
12
|
+
|
|
13
|
+
static start(platformTemplatesFilePath) {
|
|
14
|
+
PlatformTemplateService.readFromFile(platformTemplatesFilePath).then(([firstPlatformTemplateFound]) => {
|
|
15
|
+
const platformConfig = PlatformConfigService.from(firstPlatformTemplateFound)
|
|
16
|
+
|
|
17
|
+
RestApiService.start(platformConfig)
|
|
18
|
+
CaddyService.applyDefaultConfig(platformConfig)
|
|
19
|
+
|
|
20
|
+
DeploymentQueueClient.pollForDeploymentRequests(
|
|
21
|
+
platformConfig,
|
|
22
|
+
deploymentRequest => {
|
|
23
|
+
DockerService.deploy(platformConfig, deploymentRequest)
|
|
24
|
+
CaddyService.addDeployment(platformConfig, deploymentRequest)
|
|
25
|
+
return Promise.resolve()
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
})
|
|
30
|
+
.catch(error => logError({ message: '[PlatformServerService] Could not start the platform server', error }))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
PlatformServerService
|
|
37
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
const express = require('express')
|
|
2
|
+
const { logInfo } = require('../log')
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
class RestApiService {
|
|
5
5
|
|
|
6
6
|
static start(platformConfig) {
|
|
7
7
|
const server = express()
|
|
@@ -17,8 +17,12 @@ export class CiRestApi {
|
|
|
17
17
|
})
|
|
18
18
|
|
|
19
19
|
server.listen(platformConfig.ciInternalServerPort, () => {
|
|
20
|
-
logInfo({ message: `[
|
|
20
|
+
logInfo({ message: `[RestApiService] API is live on port ${platformConfig.ciInternalServerPort}`})
|
|
21
21
|
})
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
}
|
|
25
|
+
|
|
26
|
+
module.exports = {
|
|
27
|
+
RestApiService
|
|
28
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const arg = require('arg')
|
|
3
|
+
const { PlatformTemplateService } = require('./platform-template')
|
|
4
|
+
|
|
5
|
+
const { logInfo, logError } = require('../log')
|
|
6
|
+
|
|
7
|
+
//eslint-disable-next-line no-unused-vars
|
|
8
|
+
const [_, __, command, ...options] = process.argv
|
|
9
|
+
|
|
10
|
+
const validate = () => {
|
|
11
|
+
logInfo({ message: 'Running validate command' })
|
|
12
|
+
|
|
13
|
+
const parsedArgs = arg({
|
|
14
|
+
'--platforms': String,
|
|
15
|
+
'-p': '--platforms'
|
|
16
|
+
}, { argv: options })
|
|
17
|
+
|
|
18
|
+
PlatformTemplateService.readFromFile(parsedArgs['--platforms'])
|
|
19
|
+
.then(() => logInfo({ message: 'Template is valid' }))
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
command === 'validate' ? validate() : logError({ message: 'No command provided' })
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./platform-template')
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
// @param {number} [foo=1]
|
|
1
|
+
const { resolve } = require('path')
|
|
2
|
+
const { readFileSync } = require('fs')
|
|
3
|
+
const { logError, logInfo } = require('../log')
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Platform template definition
|
|
@@ -20,8 +19,9 @@ import { logError, logInfo } from './log.js'
|
|
|
20
19
|
* @property {string} ciInternalServerPort- ? | number;
|
|
21
20
|
* @property {string} ciServerName - ?
|
|
22
21
|
* @property {string} ciDockerNetworkName - ?
|
|
22
|
+
* @property {string} ciGithubActionsRepo - organisation/repoName
|
|
23
23
|
*/
|
|
24
|
-
|
|
24
|
+
class PlatformTemplateService {
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Reads the json file that holds the platform templates
|
|
@@ -62,3 +62,7 @@ export class PlatformTemplateService {
|
|
|
62
62
|
return obj
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
+
|
|
66
|
+
module.exports = {
|
|
67
|
+
PlatformTemplateService
|
|
68
|
+
}
|