@ossy/deployment-tools 0.0.68 → 0.0.69
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 +17 -1
- package/package.json +2 -1
- package/src/aws-credentials/cli.js +1 -2
- package/src/caddy/caddy-config.js +23 -25
- package/src/caddy/caddy.js +5 -43
- package/src/config/platform-config.js +6 -9
- package/src/deploy/cli.js +15 -9
- package/src/deploy/index.js +1 -0
- package/src/deploy/platform-deployment.js +33 -59
- package/src/infrastructure/cli.js +19 -8
- package/src/infrastructure/{container-server/container-server.js → container-deployment-target/container-deployment-target.js} +6 -18
- package/src/infrastructure/container-deployment-target/index.js +3 -0
- package/src/infrastructure/deployment-target-stack.js +14 -15
- package/src/infrastructure/dns-stack.js +61 -0
- package/src/infrastructure/trust-ci-stack.js +1 -1
- package/src/server/platform-server.js +1 -3
- package/src/template/deployment-template.js +86 -0
- package/src/template/index.js +4 -1
- package/src/caddy/caddy.playground.js +0 -21
- package/src/infrastructure/container-server/index.js +0 -3
- package/src/server/platform-server.playground.js +0 -10
- package/src/server/rest-api.js +0 -31
- /package/src/infrastructure/{container-server → container-deployment-target}/aws-profile.js +0 -0
- /package/src/infrastructure/{container-server → container-deployment-target}/caddy.service.js +0 -0
- /package/src/infrastructure/{container-server → container-deployment-target}/deployment-tools.service.js +0 -0
- /package/src/infrastructure/{container-server → container-deployment-target}/user-data-commands.js +0 -0
package/README.md
CHANGED
|
@@ -55,6 +55,23 @@ billingInformation
|
|
|
55
55
|
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
+
## Our domains
|
|
59
|
+
|
|
60
|
+
ossy.se
|
|
61
|
+
www.ossy.se
|
|
62
|
+
test.ossy.se
|
|
63
|
+
|
|
64
|
+
api.ossy.se
|
|
65
|
+
api.test.ossy.se
|
|
66
|
+
|
|
67
|
+
plexus.ossy.se
|
|
68
|
+
plexus.test.ossy.se
|
|
69
|
+
|
|
70
|
+
oskarssylwan.se
|
|
71
|
+
www.oskarssylwan.se
|
|
72
|
+
test.oskarssylwan.se
|
|
73
|
+
|
|
74
|
+
|
|
58
75
|
## Overview of our infrastructure
|
|
59
76
|
|
|
60
77
|
We use AWS to host our infrastructure and all of it is defined in JavaScript with the help of
|
|
@@ -84,7 +101,6 @@ Stacks
|
|
|
84
101
|
- email service stack per env
|
|
85
102
|
- media bucket stack per env
|
|
86
103
|
- stack for dns records with the account that holds domain names
|
|
87
|
-
-
|
|
88
104
|
|
|
89
105
|
### Adding a new AWS account
|
|
90
106
|
We have a different account for each service and environment.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ossy/deployment-tools",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.69",
|
|
4
4
|
"description": "Collection of scripts and tools to aid deployment of containers and static files to Amazon Web Services through GitHub Actions",
|
|
5
5
|
"source": "./src/index.js",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"aws-cdk-lib": "^2.59.0",
|
|
22
22
|
"constructs": "^10.1.211",
|
|
23
23
|
"express": "^4.18.1",
|
|
24
|
+
"glob": "^9.3.2",
|
|
24
25
|
"nanoid": "^3.3.4",
|
|
25
26
|
"node-fetch": "^2.6.7"
|
|
26
27
|
},
|
|
@@ -29,8 +29,7 @@ const assumeRole = options => {
|
|
|
29
29
|
'--target-platform': String
|
|
30
30
|
}, { argv: options })
|
|
31
31
|
|
|
32
|
-
const
|
|
33
|
-
const [platformName] = stackname.split('-')
|
|
32
|
+
const platformName = parsedArgs['--target-platform'] || ''
|
|
34
33
|
|
|
35
34
|
PlatformTemplateService.readFromFile(parsedArgs['--platforms'] || process.env.PLATFORMS)
|
|
36
35
|
.then(templates => templates.map(PlatformConfigService.from))
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
const { DeploymentTemplateService } = require('../template')
|
|
2
|
+
const { SupportedEnvironments } = require('../config')
|
|
3
|
+
|
|
1
4
|
const Matchers = {
|
|
2
5
|
host: host => ({ host: [host] }),
|
|
3
6
|
path: path => ({ path: [path] })
|
|
@@ -19,35 +22,21 @@ const Handlers = {
|
|
|
19
22
|
*/
|
|
20
23
|
class CaddyConfigService {
|
|
21
24
|
|
|
22
|
-
static
|
|
23
|
-
|
|
24
|
-
const url = [
|
|
25
|
-
deploymentRequest.subdomain,
|
|
26
|
-
platformConfig.environmentType !== 'prod' ? platformConfig.environmentType : undefined,
|
|
27
|
-
platformConfig.domain
|
|
28
|
-
]
|
|
29
|
-
.filter(x => !!x)
|
|
30
|
-
.join('.')
|
|
25
|
+
static createConfig(platformConfig, deploymentTemplates) {
|
|
31
26
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
handle: [Handlers.subroute([{ handle: [Handlers.reverseProxy(deploymentRequest.hostPort)]}])]
|
|
35
|
-
}
|
|
36
|
-
}
|
|
27
|
+
const containerDeployments = DeploymentTemplateService
|
|
28
|
+
.getContainerDeploymentsForEnvironmentType(platformConfig.environmentType, deploymentTemplates)
|
|
37
29
|
|
|
38
|
-
static getDefaultConfig(platformConfig) {
|
|
39
30
|
return {
|
|
40
31
|
apps: {
|
|
41
32
|
http: {
|
|
42
33
|
servers: {
|
|
43
|
-
|
|
34
|
+
'deployment-tools': {
|
|
44
35
|
listen: [':80', ':443'],
|
|
45
|
-
routes:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
]
|
|
36
|
+
routes: containerDeployments.map(deploymentTemplate => ({
|
|
37
|
+
match: [Matchers.host(deploymentRequest.domain)],
|
|
38
|
+
handle: [Handlers.subroute([{ handle: [Handlers.reverseProxy(deploymentRequest.hostPort)]}])]
|
|
39
|
+
}))
|
|
51
40
|
}
|
|
52
41
|
}
|
|
53
42
|
},
|
|
@@ -55,12 +44,21 @@ class CaddyConfigService {
|
|
|
55
44
|
automation: {
|
|
56
45
|
policies: [
|
|
57
46
|
{
|
|
58
|
-
subjects:
|
|
47
|
+
subjects: DeploymentTemplateService.groupDeploymentDomainsByRootDomain(containerDeployments).keys().flatMap(rootDomain => {
|
|
48
|
+
const environmentSubdomain = platformConfig.environmentType === SupportedEnvironments.PROD
|
|
49
|
+
? ''
|
|
50
|
+
: `${platformConfig.environmentType}.`
|
|
51
|
+
|
|
52
|
+
return [
|
|
53
|
+
`*.${environmentSubdomain}${rootDomain}`,
|
|
54
|
+
`${environmentSubdomain}${rootDomain}`
|
|
55
|
+
]
|
|
56
|
+
}),
|
|
59
57
|
issuers:[
|
|
60
58
|
{
|
|
61
|
-
challenges:{
|
|
59
|
+
challenges: {
|
|
62
60
|
dns:{
|
|
63
|
-
provider:{
|
|
61
|
+
provider: {
|
|
64
62
|
'max_retries': 10,
|
|
65
63
|
name: 'route53',
|
|
66
64
|
'aws_profile': 'ci-client'
|
package/src/caddy/caddy.js
CHANGED
|
@@ -7,55 +7,17 @@ const { logInfo, logError, logDebug } = require('../log')
|
|
|
7
7
|
*/
|
|
8
8
|
class CaddyService {
|
|
9
9
|
|
|
10
|
-
static
|
|
11
|
-
|
|
12
|
-
const host = routeConfig.match[0].host[0]
|
|
13
|
-
logInfo({ message: `[CaddyService] Updating caddy config to route ${host} to localhost:${deploymentRequest.hostPort}` })
|
|
14
|
-
|
|
15
|
-
return fetch(`http://localhost:2019/config/apps/http/servers/${platformConfig.ciServerName}/routes`, {
|
|
10
|
+
static applyConfig(config) {
|
|
11
|
+
return fetch('http://localhost:2019/load', {
|
|
16
12
|
method: 'POST',
|
|
17
13
|
headers: { 'Content-Type': 'application/json' },
|
|
18
|
-
body: JSON.stringify(
|
|
14
|
+
body: JSON.stringify(config)
|
|
19
15
|
})
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
.then(response => response?.error && logError({ message: '[CaddyService] Could not apply default caddy config', error }))
|
|
17
|
+
.catch(error => logError({ message: '[CaddyService] Could not apply default caddy config', error }))
|
|
22
18
|
}
|
|
23
19
|
|
|
24
|
-
static applyDefaultConfig(platformConfig) {
|
|
25
|
-
return CaddyService.fetchServerConfig(platformConfig)
|
|
26
|
-
.then(caddyConfig => {
|
|
27
|
-
|
|
28
|
-
if (caddyConfig) {
|
|
29
|
-
logInfo({ message: '[CaddyService] Server config already exist, not applying default config' })
|
|
30
|
-
return
|
|
31
|
-
}
|
|
32
20
|
|
|
33
|
-
logInfo({ message: '[CaddyService] Applying default caddy config' })
|
|
34
|
-
const defaultConfig = CaddyConfigService.getDefaultConfig(platformConfig)
|
|
35
|
-
return fetch('http://localhost:2019/load', {
|
|
36
|
-
method: 'POST',
|
|
37
|
-
headers: { 'Content-Type': 'application/json' },
|
|
38
|
-
body: JSON.stringify(defaultConfig)
|
|
39
|
-
})
|
|
40
|
-
})
|
|
41
|
-
.then(response => response?.error && logError({ message: '[CaddyService] Could not apply default caddy config', error }))
|
|
42
|
-
.catch(error => logError({ message: '[CaddyService] Could not apply default caddy config', error }))
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
static fetchServerConfig(platformConfig) {
|
|
47
|
-
logInfo({ message: '[CaddyService] Fetching server config' })
|
|
48
|
-
return fetch(`http://localhost:2019/config/apps/http/servers/${platformConfig.ciServerName}`, {
|
|
49
|
-
method: 'GET',
|
|
50
|
-
headers: { 'Content-Type': 'application/json' }
|
|
51
|
-
})
|
|
52
|
-
.then(x => x.json())
|
|
53
|
-
.then(response => {
|
|
54
|
-
if (!response?.error) return response
|
|
55
|
-
logInfo({ message: '[CaddyService] No server config found' })
|
|
56
|
-
logDebug({ message: '[CaddyService] Error while fetching server config', data: response.error })
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
21
|
}
|
|
60
22
|
|
|
61
23
|
module.exports = {
|
|
@@ -2,18 +2,15 @@
|
|
|
2
2
|
* Platform config definition
|
|
3
3
|
* @typedef {Object} PlatformConfig
|
|
4
4
|
* @property {string} platformName - Name of platform
|
|
5
|
-
* @property {string} domain - example.com
|
|
6
5
|
* @property {string} environmentType - local, test, qa, prod
|
|
7
6
|
*
|
|
8
7
|
* @property {string} awsAccountId - Aws account id
|
|
9
8
|
* @property {string=} awsRegion - ?
|
|
10
9
|
* @property {string=} awsKeyPairName - ?
|
|
11
10
|
* @property {string} awsRoleToAssume - ?
|
|
11
|
+
* @property {string=} awsDeploymentSqsName - ?
|
|
12
12
|
* @property {string=} awsDeploymentSqsArn - ?
|
|
13
13
|
*
|
|
14
|
-
* @property {string=} ciSubDomain - ?
|
|
15
|
-
* @property {string|mumber=} ciInternalServerPort - ? | number;
|
|
16
|
-
* @property {string=} ciServerName - ?
|
|
17
14
|
* @property {string=} ciDockerNetworkName - ?
|
|
18
15
|
* @property {string} ciGithubActionsRepo - organisation/repoName
|
|
19
16
|
*/
|
|
@@ -49,14 +46,13 @@ class PlatformConfigService {
|
|
|
49
46
|
awsRegion: SupportedRegions.North,
|
|
50
47
|
...template,
|
|
51
48
|
// values below should not be overriden by the template properties
|
|
52
|
-
ciSubDomain: 'ci',
|
|
53
|
-
ciInternalServerPort: 3000,
|
|
54
|
-
ciServerName: 'ci-client',
|
|
55
49
|
ciDockerNetworkName: 'deployment-tools',
|
|
56
50
|
}
|
|
57
51
|
|
|
52
|
+
const awsDeploymentSqsName = `${withDefaults.platformName}-container-deployments-requests`
|
|
53
|
+
|
|
58
54
|
const awsDeploymentSqsArn =
|
|
59
|
-
`https://sqs.${withDefaults.awsRegion}.amazonaws.com/${withDefaults.awsAccountId}/${
|
|
55
|
+
`https://sqs.${withDefaults.awsRegion}.amazonaws.com/${withDefaults.awsAccountId}/${awsDeploymentSqsName}`
|
|
60
56
|
|
|
61
57
|
const awsRoleToAssume = process.env.CI
|
|
62
58
|
? `github-ci-role-${withDefaults.platformName}`
|
|
@@ -64,8 +60,9 @@ class PlatformConfigService {
|
|
|
64
60
|
|
|
65
61
|
return {
|
|
66
62
|
...withDefaults,
|
|
63
|
+
awsDeploymentSqsName,
|
|
67
64
|
awsDeploymentSqsArn,
|
|
68
|
-
awsRoleToAssume
|
|
65
|
+
awsRoleToAssume,
|
|
69
66
|
}
|
|
70
67
|
|
|
71
68
|
}
|
package/src/deploy/cli.js
CHANGED
|
@@ -13,22 +13,28 @@ const deploy = options => {
|
|
|
13
13
|
'--authentication': String,
|
|
14
14
|
'--a': '--authentication',
|
|
15
15
|
|
|
16
|
-
'--
|
|
17
|
-
'-
|
|
16
|
+
'--domain': String,
|
|
17
|
+
'-d': '--domain',
|
|
18
|
+
|
|
19
|
+
'--platform': String,
|
|
20
|
+
'-p': '--platform',
|
|
21
|
+
|
|
22
|
+
'--platforms-path': String,
|
|
23
|
+
'-pp': '--platforms-path',
|
|
24
|
+
|
|
25
|
+
'--ossy-files': String,
|
|
26
|
+
'-o': '--ossy-files',
|
|
18
27
|
|
|
19
|
-
'--ossyfile': String,
|
|
20
|
-
'-o': '--ossyfile',
|
|
21
28
|
|
|
22
|
-
'--platforms': String,
|
|
23
|
-
'-p': '--platforms'
|
|
24
29
|
}, { argv: options })
|
|
25
30
|
|
|
26
31
|
PlatformDeploymentService.deploy({
|
|
27
32
|
username: parsedArgs['--username'],
|
|
28
33
|
authentication: parsedArgs['--authentication'],
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
targetDomain: parsedArgs['--domain'],
|
|
35
|
+
targetPlatform: parsedArgs['--platform'],
|
|
36
|
+
pathToPlatformTemplates: parsedArgs['--platforms-path'],
|
|
37
|
+
pathToOssyFile: parsedArgs['--ossy-files']
|
|
32
38
|
})
|
|
33
39
|
}
|
|
34
40
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./platform-deployment.js')
|
|
@@ -1,37 +1,11 @@
|
|
|
1
|
-
const { resolve } = require('path')
|
|
2
1
|
const { readFileSync } = require('fs')
|
|
3
|
-
const {
|
|
4
|
-
const {
|
|
2
|
+
const { resolve } = require('path')
|
|
3
|
+
const { PlatformTemplateService, DeploymentTemplateService } = require('../template')
|
|
4
|
+
const { PlatformConfigService, SupportedDeploymentTypes, SupportedEnvironments } = require('../config')
|
|
5
5
|
const { DeploymentQueueService } = require('../deployment-queue')
|
|
6
|
+
const { CaddyConfigService } = require('../caddy')
|
|
6
7
|
const { logError } = require('../log')
|
|
7
8
|
|
|
8
|
-
// export interface DeploymentTemplate {
|
|
9
|
-
// type: SupportedDeploymentTypes;
|
|
10
|
-
// targetDeploymentPlatform: string;
|
|
11
|
-
// subdomain?: string;
|
|
12
|
-
// env?: {
|
|
13
|
-
// shared?: { [name: string]: string | number };
|
|
14
|
-
// prod?: { [name: string]: string | number };
|
|
15
|
-
// test?: { [name: string]: string | number };
|
|
16
|
-
// qa?: { [name: string]: string | number };
|
|
17
|
-
// }
|
|
18
|
-
// }
|
|
19
|
-
|
|
20
|
-
// export interface ContainerDeploymentTemplate extends DeploymentTemplate {
|
|
21
|
-
// type: SupportedDeploymentTypes.Container;
|
|
22
|
-
// dockerFile: string;
|
|
23
|
-
// dockerContext: string;
|
|
24
|
-
// image: string;
|
|
25
|
-
// hostPort: number;
|
|
26
|
-
// containerPort: number;
|
|
27
|
-
// registry: string;
|
|
28
|
-
// }
|
|
29
|
-
|
|
30
|
-
// export interface ContainerDeploymentRequest extends ContainerDeploymentTemplate {
|
|
31
|
-
// authentication?: string;
|
|
32
|
-
// username?: string;
|
|
33
|
-
// }
|
|
34
|
-
|
|
35
9
|
/**
|
|
36
10
|
* @class
|
|
37
11
|
*/
|
|
@@ -40,55 +14,55 @@ class PlatformDeploymentService {
|
|
|
40
14
|
static deploy({
|
|
41
15
|
username,
|
|
42
16
|
authentication,
|
|
43
|
-
|
|
17
|
+
targetDomain,
|
|
18
|
+
targetPlatform,
|
|
44
19
|
pathToPlatformTemplates,
|
|
45
|
-
|
|
20
|
+
globPatternForOssyFiles
|
|
46
21
|
}) {
|
|
47
22
|
|
|
48
23
|
return Promise.all([
|
|
49
|
-
|
|
24
|
+
DeploymentTemplateService.readOssyFiles(globPatternForOssyFiles),
|
|
50
25
|
PlatformTemplateService.readFromFile(pathToPlatformTemplates)
|
|
51
26
|
.then(templates => templates.map(PlatformConfigService.from))
|
|
52
27
|
])
|
|
53
28
|
.then(([deploymentTemplates, platformConfigs]) => {
|
|
54
|
-
deploymentTemplates.map(deploymentTemplate => {
|
|
55
29
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
)
|
|
30
|
+
const platformConfig = platformConfigs.find(({ platformName }) => platformName === targetPlatform)
|
|
31
|
+
const deploymentTemplatesForTargetPlatform = deploymentTemplates[targetPlatform] || []
|
|
32
|
+
const deploymentTemplate = deploymentTemplatesForTargetPlatform.find(({ domain }) => domain === targetDomain)
|
|
60
33
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
34
|
+
if (!platformConfig) {
|
|
35
|
+
logError({ message: `[PlatformDeploymentService] Could not find a platform named ${targetPlatform}` })
|
|
36
|
+
return Promise.reject()
|
|
37
|
+
}
|
|
65
38
|
|
|
66
|
-
|
|
39
|
+
if (!deploymentTemplate) {
|
|
40
|
+
logError({ message: `[PlatformDeploymentService] Could not find a deployment template for ${targetDomain} in ${targetPlatform}` })
|
|
41
|
+
return Promise.reject()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
|
45
|
+
|
|
46
|
+
if (deploymentTemplate.type === SupportedDeploymentTypes.Container) {
|
|
67
47
|
|
|
68
|
-
|
|
69
|
-
const deploymentRequest = {
|
|
70
|
-
...deploymentTemplate,
|
|
71
|
-
username: username,
|
|
72
|
-
authentication: authentication
|
|
73
|
-
}
|
|
48
|
+
const caddyConfig = CaddyConfigService.createConfig(platformConfig, deploymentTemplatesForTargetPlatform)
|
|
74
49
|
|
|
75
|
-
|
|
50
|
+
const deploymentRequest = {
|
|
51
|
+
...deploymentTemplate,
|
|
52
|
+
username: username,
|
|
53
|
+
authentication: authentication,
|
|
54
|
+
caddyConfig
|
|
76
55
|
}
|
|
77
56
|
|
|
78
|
-
|
|
79
|
-
|
|
57
|
+
return DeploymentQueueService.sendDeploymentRequest(platformConfig, deploymentRequest)
|
|
58
|
+
}
|
|
80
59
|
|
|
81
|
-
})
|
|
60
|
+
logError({ message: `[PlatformDeploymentService] Unsupported deployment type of ${deploymentTemplate.type}` })
|
|
61
|
+
return Promise.reject()
|
|
82
62
|
})
|
|
83
63
|
.catch(error => logError({ message: '[PlatformDeploymentService] Could not send deployment request', error }))
|
|
84
64
|
}
|
|
85
65
|
|
|
86
|
-
static getDeploymentTemplates(pathToOssyFile) {
|
|
87
|
-
if (!pathToOssyFile) return logError({ message: '[PlatformDeploymentService] No path to ossy.json provided' })
|
|
88
|
-
const ossyfile = JSON.parse(readFileSync(resolve(pathToOssyFile), 'utf8'))
|
|
89
|
-
return Promise.resolve(ossyfile.deployments || [])
|
|
90
|
-
}
|
|
91
|
-
|
|
92
66
|
}
|
|
93
67
|
|
|
94
68
|
module.exports = {
|
|
@@ -3,17 +3,21 @@
|
|
|
3
3
|
const { App } = require('aws-cdk-lib')
|
|
4
4
|
const { TrustCiStack } = require('./trust-ci-stack')
|
|
5
5
|
const { DeploymentTargetStack } = require('./deployment-target-stack')
|
|
6
|
-
const {
|
|
6
|
+
const { DnsStack } = require('./dns-stack')
|
|
7
|
+
const { PlatformTemplateService, DeploymentTemplateService } = require('../template')
|
|
7
8
|
const { PlatformConfigService } = require('../config')
|
|
9
|
+
const { PlatformDeploymentService } = require('../deploy')
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
.
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
Promise.all([
|
|
12
|
+
DeploymentTemplateService.readOssyFiles('../../../**/ossy.json'),
|
|
13
|
+
PlatformTemplateService
|
|
14
|
+
.readFromFile(process.env.PLATFORMS)
|
|
15
|
+
.then(templates => templates.map(PlatformConfigService.from))
|
|
16
|
+
])
|
|
17
|
+
.then(([deploymentMap, configs]) => {
|
|
13
18
|
const app = new App()
|
|
14
19
|
|
|
15
20
|
configs.forEach(config => {
|
|
16
|
-
const stackBaseName = `${config.platformName}-${config.environmentType}`
|
|
17
21
|
|
|
18
22
|
const stackProps = {
|
|
19
23
|
config,
|
|
@@ -23,8 +27,15 @@ PlatformTemplateService
|
|
|
23
27
|
}
|
|
24
28
|
}
|
|
25
29
|
|
|
26
|
-
new TrustCiStack(app, `${
|
|
27
|
-
|
|
30
|
+
new TrustCiStack(app, `${config.platformName}-trust-ci`, stackProps)
|
|
31
|
+
|
|
32
|
+
const deploymentTarget = new DeploymentTargetStack(app, `${config.platformName}-deployment-target`, stackProps)
|
|
33
|
+
|
|
34
|
+
new DnsStack(app, `${config.platformName}-dns`, {
|
|
35
|
+
...stackProps,
|
|
36
|
+
deployments: deploymentMap[config.platformName],
|
|
37
|
+
containerDeploymentTargetPublicIp: deploymentTarget.containerDeploymentTargetPublicIp
|
|
38
|
+
})
|
|
28
39
|
|
|
29
40
|
})
|
|
30
41
|
})
|
|
@@ -12,20 +12,13 @@ const {
|
|
|
12
12
|
Port,
|
|
13
13
|
UserData
|
|
14
14
|
} = require('aws-cdk-lib/aws-ec2')
|
|
15
|
-
const { ARecord, RecordTarget } = require('aws-cdk-lib/aws-route53')
|
|
16
15
|
const { Role, ServicePrincipal, Policy, PolicyStatement, Effect } = require('aws-cdk-lib/aws-iam')
|
|
17
16
|
const { Queue } = require('aws-cdk-lib/aws-sqs')
|
|
18
17
|
const { Source, BucketDeployment } = require('aws-cdk-lib/aws-s3-deployment')
|
|
19
|
-
|
|
20
|
-
const {
|
|
21
|
-
getInstallNodeJs,
|
|
22
|
-
getInstallNpm,
|
|
23
|
-
getInstallDocker
|
|
24
|
-
} = require('./user-data-commands')
|
|
18
|
+
const { getInstallNodeJs, getInstallNpm, getInstallDocker } = require('./user-data-commands')
|
|
25
19
|
const { CaddyService } = require('./caddy.service')
|
|
26
20
|
const { DeploymentToolsService } = require('./deployment-tools.service')
|
|
27
21
|
const { AwsProfile } = require('./aws-profile')
|
|
28
|
-
|
|
29
22
|
const { SupportedRegions } = require('../../config')
|
|
30
23
|
|
|
31
24
|
/**
|
|
@@ -33,7 +26,6 @@ const { SupportedRegions } = require('../../config')
|
|
|
33
26
|
* @namespace ContainerServer
|
|
34
27
|
* @typedef {Object} ContainerServerProps
|
|
35
28
|
* @property {PlatformConfig} config - platform config
|
|
36
|
-
* @property {Zone} hostedZone - aws zone
|
|
37
29
|
* @property {Bucket} bucket - s3 bucket
|
|
38
30
|
*/
|
|
39
31
|
|
|
@@ -44,7 +36,7 @@ const InstanceImages = {
|
|
|
44
36
|
/**
|
|
45
37
|
* @class
|
|
46
38
|
*/
|
|
47
|
-
class
|
|
39
|
+
class ContainerDeploymentTarget extends Construct {
|
|
48
40
|
|
|
49
41
|
/**
|
|
50
42
|
* @param {object} scope - scope
|
|
@@ -76,7 +68,7 @@ class ContainerServer extends Construct {
|
|
|
76
68
|
)
|
|
77
69
|
|
|
78
70
|
const deploymentQueue = new Queue(this, 'DeploymentQueue', {
|
|
79
|
-
queueName: `${props.config.
|
|
71
|
+
queueName: `${props.config.awsDeploymentSqsName}`,
|
|
80
72
|
receiveMessageWaitTime: Duration.seconds(20)
|
|
81
73
|
})
|
|
82
74
|
|
|
@@ -99,7 +91,7 @@ class ContainerServer extends Construct {
|
|
|
99
91
|
'route53:ChangeResourceRecordSets'
|
|
100
92
|
],
|
|
101
93
|
resources: [
|
|
102
|
-
`arn:aws:route53:::hostedzone
|
|
94
|
+
`arn:aws:route53:::hostedzone/*`,
|
|
103
95
|
'arn:aws:route53:::change/*'
|
|
104
96
|
]
|
|
105
97
|
}),
|
|
@@ -162,11 +154,7 @@ class ContainerServer extends Construct {
|
|
|
162
154
|
props.bucket.grantRead(ec2Instance, '*')
|
|
163
155
|
deploymentQueue.grant(ec2Instance, '*')
|
|
164
156
|
|
|
165
|
-
|
|
166
|
-
zone: props.hostedZone,
|
|
167
|
-
recordName: `*.${props.config.environmentType}.${props.config.domain}`,
|
|
168
|
-
target: RecordTarget.fromIpAddresses(ec2Instance.instancePublicIp)
|
|
169
|
-
})
|
|
157
|
+
this.instancePublicIp = ec2Instance.instancePublicIp
|
|
170
158
|
|
|
171
159
|
new CfnOutput(this, 'Instance Ip', {
|
|
172
160
|
value: ec2Instance.instancePublicIp,
|
|
@@ -178,5 +166,5 @@ class ContainerServer extends Construct {
|
|
|
178
166
|
}
|
|
179
167
|
|
|
180
168
|
module.exports = {
|
|
181
|
-
|
|
169
|
+
ContainerDeploymentTarget
|
|
182
170
|
}
|
|
@@ -3,7 +3,7 @@ const { nanoid } = require('nanoid')
|
|
|
3
3
|
const { Stack, Duration, RemovalPolicy } = require('aws-cdk-lib')
|
|
4
4
|
const { HostedZone, ARecord, RecordTarget } = require('aws-cdk-lib/aws-route53')
|
|
5
5
|
const { Bucket, BucketEncryption, BlockPublicAccess } = require('aws-cdk-lib/aws-s3')
|
|
6
|
-
const {
|
|
6
|
+
const { ContainerDeploymentTarget } = require('./container-deployment-target')
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @class
|
|
@@ -16,29 +16,28 @@ class DeploymentTargetStack extends Stack {
|
|
|
16
16
|
throw ('[DeploymentTargetStack] No template provided')
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
const domain = `${props.config.environmentType}.${props.config.domain}`
|
|
20
19
|
const bucketId = nanoid().toLowerCase().replaceAll('_', '').replaceAll('-', '')
|
|
21
|
-
const bucketName = `${props.config.platformName}-${
|
|
22
|
-
|
|
23
|
-
const hostedZone = new HostedZone(this, 'HostedZone', { zoneName: domain })
|
|
20
|
+
const bucketName = `${props.config.platformName}-${bucketId}`
|
|
24
21
|
|
|
25
22
|
// TODO: this should probably not be destroyed....
|
|
26
|
-
const staticDeploymentTarget =
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
const staticDeploymentTarget =
|
|
24
|
+
new Bucket(this, 'StaticDeploymentTarget', {
|
|
25
|
+
bucketName: bucketName,
|
|
26
|
+
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
|
|
27
|
+
encryption: BucketEncryption.S3_MANAGED,
|
|
28
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
29
|
+
autoDeleteObjects: true
|
|
30
|
+
})
|
|
33
31
|
|
|
34
|
-
// Todo rename to container deployment target
|
|
35
32
|
// TODO: add persistant storage
|
|
36
|
-
|
|
33
|
+
const containerDeploymentTarget =
|
|
34
|
+
new ContainerDeploymentTarget(this, 'ContainerDeploymentTarget', {
|
|
37
35
|
config: props.config,
|
|
38
|
-
hostedZone: hostedZone,
|
|
39
36
|
bucket: staticDeploymentTarget
|
|
40
37
|
})
|
|
41
38
|
|
|
39
|
+
this.containerDeploymentTargetPublicIp = containerDeploymentTarget.instancePublicIp
|
|
40
|
+
|
|
42
41
|
}
|
|
43
42
|
}
|
|
44
43
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const { Stack } = require('aws-cdk-lib')
|
|
2
|
+
const { HostedZone, ARecord, RecordTarget } = require('aws-cdk-lib/aws-route53')
|
|
3
|
+
const { SupportedDeploymentTypes, SupportedEnvironments } = require('../config')
|
|
4
|
+
const { DeploymentTemplateService } = require('../template')
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* DnsStackProps
|
|
8
|
+
* @namespace DnsStack
|
|
9
|
+
* @typedef {Object} DnsStackProps
|
|
10
|
+
* @property {PlatformConfig} config - platform config
|
|
11
|
+
* @property {PlatformConfig} deployments - deployment templates[]
|
|
12
|
+
* @property {string} containerDeploymentTargetPublicIp - public ip address of ec2 instance that hosts our containerss
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const InstanceImages = {
|
|
16
|
+
UBUNTU: 'ami-092cce4a19b438926'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @class
|
|
21
|
+
*/
|
|
22
|
+
class DnsStack extends Stack {
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {object} scope - scope
|
|
26
|
+
* @param {string} id - id
|
|
27
|
+
* @param {ContainerServerProps} props - ContainerServerProps
|
|
28
|
+
*/
|
|
29
|
+
constructor(scope, id, props) {
|
|
30
|
+
super(scope, id, props)
|
|
31
|
+
|
|
32
|
+
if (props.config.environmentType === SupportedEnvironments.PROD) {
|
|
33
|
+
// const isDomainForCorrectEnvironment = !Object.values(SupportedEnvironments)
|
|
34
|
+
// .find(env => deployment.domain.includes(env))
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const containerDeployments = DeploymentTemplateService
|
|
39
|
+
.getContainerDeploymentsForEnvironmentType(props.config.environmentType, props.deployments)
|
|
40
|
+
|
|
41
|
+
DeploymentTemplateService
|
|
42
|
+
.groupDeploymentDomainsByRootDomain(containerDeployments)
|
|
43
|
+
.forEach((domains, rootDomain) => {
|
|
44
|
+
const hostedZone = new HostedZone(this, rootDomain, { zoneName: rootDomain })
|
|
45
|
+
|
|
46
|
+
domains.forEach(domain => {
|
|
47
|
+
new ARecord(this, domain, {
|
|
48
|
+
zone: hostedZone,
|
|
49
|
+
recordName: domain,
|
|
50
|
+
target: RecordTarget.fromIpAddresses(props.containerDeploymentTargetPublicIp)
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = {
|
|
60
|
+
DnsStack
|
|
61
|
+
}
|
|
@@ -50,7 +50,7 @@ class TrustCiStack extends Stack {
|
|
|
50
50
|
statements: [
|
|
51
51
|
new PolicyStatement({
|
|
52
52
|
effect: Effect.ALLOW,
|
|
53
|
-
actions: ['sts:AssumeRole'],
|
|
53
|
+
actions: ['sts:AssumeRole', 'sqs:SendMessage'],
|
|
54
54
|
resources: [
|
|
55
55
|
`arn:aws:iam::${props.config.awsAccountId}:role/cdk-*`,
|
|
56
56
|
`arn:aws:sqs:${props.config.awsRegion}:${props.config.awsAccountId}:*`
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const { CaddyService } = require('../caddy')
|
|
2
2
|
const { DockerService } = require('../docker')
|
|
3
|
-
const { RestApiService } = require('./rest-api')
|
|
4
3
|
|
|
5
4
|
const { PlatformTemplateService } = require('../template')
|
|
6
5
|
const { PlatformConfigService } = require('../config')
|
|
@@ -18,7 +17,6 @@ class PlatformServerService {
|
|
|
18
17
|
PlatformTemplateService.readFromFile(platformTemplatesFilePath).then(([firstPlatformTemplateFound]) => {
|
|
19
18
|
const platformConfig = PlatformConfigService.from(firstPlatformTemplateFound)
|
|
20
19
|
|
|
21
|
-
RestApiService.start(platformConfig)
|
|
22
20
|
DockerService.createDockerNetworkForContainerManagerServer(platformConfig)
|
|
23
21
|
.then(() => DockerService.startDefaultContainers(platformConfig))
|
|
24
22
|
CaddyService.applyDefaultConfig(platformConfig)
|
|
@@ -27,7 +25,7 @@ class PlatformServerService {
|
|
|
27
25
|
platformConfig,
|
|
28
26
|
deploymentRequest => {
|
|
29
27
|
DockerService.deploy(platformConfig, deploymentRequest)
|
|
30
|
-
.then(() => CaddyService.
|
|
28
|
+
.then(() => CaddyService.applyConfig(deploymentRequest.caddyConfig))
|
|
31
29
|
return Promise.resolve()
|
|
32
30
|
}
|
|
33
31
|
)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const { glob } = require('glob')
|
|
2
|
+
const { readFileSync } = require('fs')
|
|
3
|
+
const { logError, logInfo } = require('../log')
|
|
4
|
+
const { SupportedDeploymentTypes, SupportedEnvironments } = require('../config')
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Deployment template definition
|
|
8
|
+
* @typedef {Object} DeploymentTemplate
|
|
9
|
+
* @property {string} type - CONTAINER | STATIC
|
|
10
|
+
* @property {string} domain - example.com
|
|
11
|
+
* @property {string} targetDeploymentPlatform - name of platform to deploy to
|
|
12
|
+
*
|
|
13
|
+
* @property {string} image - name of image to be deployed
|
|
14
|
+
* @property {string} registry - registry where the image is hosted
|
|
15
|
+
* @property {string=} hostPort - host port
|
|
16
|
+
* @property {string=} containerPort - port that the container exposes
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Utility class that helps you read and validate platfor templates from file system
|
|
21
|
+
* @class
|
|
22
|
+
*/
|
|
23
|
+
class DeploymentTemplateService {
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Read and and group deployments by targetDeploymentPlatform
|
|
27
|
+
*
|
|
28
|
+
* @param {string} blob - File path to platform templates json
|
|
29
|
+
*/
|
|
30
|
+
static readOssyFiles(blob) {
|
|
31
|
+
return glob(blob, { ignore: 'node_modules/**' })
|
|
32
|
+
.then(filePaths => filePaths
|
|
33
|
+
.map(path => readFileSync(path, 'utf-8'))
|
|
34
|
+
.map(json => JSON.parse(json))
|
|
35
|
+
.flatMap(ossyFileContent => ossyFileContent.deployments)
|
|
36
|
+
.reduce((deploymentsMap, deployment) => {
|
|
37
|
+
|
|
38
|
+
if (!!deploymentsMap[deployment.targetDeploymentPlatform]) {
|
|
39
|
+
return {
|
|
40
|
+
...deploymentsMap,
|
|
41
|
+
[deployment.targetDeploymentPlatform]: [
|
|
42
|
+
...deploymentsMap[deployment.targetDeploymentPlatform],
|
|
43
|
+
deployment
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
...deploymentsMap,
|
|
50
|
+
[deployment.targetDeploymentPlatform]: [deployment]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
}, {})
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static getContainerDeploymentsForEnvironmentType(environmentType, deployments) {
|
|
58
|
+
return deployments
|
|
59
|
+
.filter(deployment => {
|
|
60
|
+
const isContainerDeployment = deployment.type === SupportedDeploymentTypes.Container
|
|
61
|
+
const isDomainForCorrectEnvironment = deployment.domain.includes(environmentType)
|
|
62
|
+
return isContainerDeployment && isDomainForCorrectEnvironment
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static groupDeploymentDomainsByRootDomain(deployments) {
|
|
67
|
+
return deployments
|
|
68
|
+
.map(deployment => deployment.domain)
|
|
69
|
+
.reduce((domainGroups, domain) => {
|
|
70
|
+
const [topLevelDomain, domainName] = domain.split('.').reverse()
|
|
71
|
+
const rootDomain = `${domainName}.${topLevelDomain}`
|
|
72
|
+
|
|
73
|
+
domainGroups.has(rootDomain)
|
|
74
|
+
? domainGroups.set(rootDomain, [...domainGroups.get(rootDomain), domain])
|
|
75
|
+
: domainGroups.set(rootDomain, [domain])
|
|
76
|
+
|
|
77
|
+
return domainGroups
|
|
78
|
+
}, new Map())
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = {
|
|
85
|
+
DeploymentTemplateService
|
|
86
|
+
}
|
package/src/template/index.js
CHANGED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
const { CaddyService } = require('./caddy')
|
|
2
|
-
|
|
3
|
-
const config = {
|
|
4
|
-
environmentType: 'prod',
|
|
5
|
-
domain: 'localhost',
|
|
6
|
-
ciServerName: 'ossy',
|
|
7
|
-
ciSubDomain: 'ci',
|
|
8
|
-
ciInternalServerPort: '3000'
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const deploymentRequest = {
|
|
12
|
-
subdomain: 'cc',
|
|
13
|
-
hostPort: '3000'
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
CaddyService.applyDefaultConfig(config)
|
|
17
|
-
|
|
18
|
-
// CaddyService.addDeployment(config, deploymentRequest)
|
|
19
|
-
|
|
20
|
-
// CaddyService.fetchServerConfig(config)
|
|
21
|
-
// .then(console.log)
|
package/src/server/rest-api.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
const express = require('express')
|
|
2
|
-
const { logInfo } = require('../log')
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @class
|
|
6
|
-
*/
|
|
7
|
-
class RestApiService {
|
|
8
|
-
|
|
9
|
-
static start(platformConfig) {
|
|
10
|
-
const server = express()
|
|
11
|
-
|
|
12
|
-
server.use(express.json())
|
|
13
|
-
|
|
14
|
-
server.get('/', (req, res) => {
|
|
15
|
-
res.redirect('/status')
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
server.get('/status', (req, res) => {
|
|
19
|
-
res.send('Server is live')
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
server.listen(platformConfig.ciInternalServerPort, () => {
|
|
23
|
-
logInfo({ message: `[RestApiService] API is live on port ${platformConfig.ciInternalServerPort}`})
|
|
24
|
-
})
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
module.exports = {
|
|
30
|
-
RestApiService
|
|
31
|
-
}
|
|
File without changes
|
/package/src/infrastructure/{container-server → container-deployment-target}/caddy.service.js
RENAMED
|
File without changes
|
|
File without changes
|
/package/src/infrastructure/{container-server → container-deployment-target}/user-data-commands.js
RENAMED
|
File without changes
|