@ossy/deployment-tools 0.0.67 → 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 +61 -1
- package/package.json +2 -1
- package/src/aws-credentials/cli.js +1 -2
- package/src/caddy/caddy-config.js +24 -26
- package/src/caddy/caddy.js +5 -43
- package/src/config/platform-config.js +29 -17
- package/src/deploy/cli.js +15 -9
- package/src/deploy/index.js +1 -0
- package/src/deploy/platform-deployment.js +32 -66
- package/src/infrastructure/cli.js +29 -18
- package/src/infrastructure/{container-server/container-server.js → container-deployment-target/container-deployment-target.js} +29 -43
- package/src/infrastructure/container-deployment-target/index.js +3 -0
- package/src/infrastructure/deployment-target-stack.js +46 -0
- package/src/infrastructure/dns-stack.js +61 -0
- package/src/infrastructure/{establish-trust-stack.js → trust-ci-stack.js} +3 -3
- 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/template/platform-template.js +1 -6
- package/src/caddy/caddy.playground.js +0 -21
- package/src/infrastructure/container-server/index.js +0 -3
- package/src/infrastructure/platform-stack.js +0 -58
- 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
|
@@ -37,11 +37,71 @@ npx --yes @ossy/deployment-tools deploy \
|
|
|
37
37
|
--ossyfile packages/${{ github.event.inputs.packageName }}/ossy.json \
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
##
|
|
40
|
+
## Concepts
|
|
41
|
+
|
|
42
|
+
**Workspace**
|
|
43
|
+
|
|
44
|
+
A workspace is an umbrella for our services.
|
|
45
|
+
It needs to be associated with at least one billable account.
|
|
46
|
+
The workspace holds information like what tools and services are in use and should
|
|
47
|
+
be billed, and what users have access to these tools and services.
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
id: string;
|
|
51
|
+
name: string;
|
|
52
|
+
participants: WorkspaceParticipant[];
|
|
53
|
+
services: ServiceDefinition[];
|
|
54
|
+
billingInformation
|
|
55
|
+
|
|
56
|
+
```
|
|
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
|
+
|
|
75
|
+
## Overview of our infrastructure
|
|
41
76
|
|
|
42
77
|
We use AWS to host our infrastructure and all of it is defined in JavaScript with the help of
|
|
43
78
|
(AWS CDK)[https://aws.amazon.com/cdk/].
|
|
44
79
|
|
|
80
|
+
**Static content**
|
|
81
|
+
|
|
82
|
+
We use a s3 bucket for static content.
|
|
83
|
+
This bucket is used to host websites, images, videos and other static content.
|
|
84
|
+
On root level you'll find directories that represent one workspace each.
|
|
85
|
+
|
|
86
|
+
/<workspacId>/<service>/
|
|
87
|
+
/<workspacId>/websites/website-id
|
|
88
|
+
|
|
89
|
+
The bucket have directories for each workspace that is the workspaceID.
|
|
90
|
+
|
|
91
|
+
The bucket have directories for each workspace that contains a media directory and website directories
|
|
92
|
+
|
|
93
|
+
- a place to host media files like images, videos, pdf documents etc.
|
|
94
|
+
- a platform to host different docker images to
|
|
95
|
+
- a mongodb database that can ensure data persistance without much effort from our our side
|
|
96
|
+
- an email service
|
|
97
|
+
- an easy way to host multiple single page applications
|
|
98
|
+
|
|
99
|
+
Stacks
|
|
100
|
+
|
|
101
|
+
- email service stack per env
|
|
102
|
+
- media bucket stack per env
|
|
103
|
+
- stack for dns records with the account that holds domain names
|
|
104
|
+
|
|
45
105
|
### Adding a new AWS account
|
|
46
106
|
We have a different account for each service and environment.
|
|
47
107
|
To add a new account follow the steps below.
|
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,48 +22,43 @@ const Handlers = {
|
|
|
19
22
|
*/
|
|
20
23
|
class CaddyConfigService {
|
|
21
24
|
|
|
22
|
-
static
|
|
23
|
-
|
|
24
|
-
const url = [
|
|
25
|
-
deploymentRequest.subdomain,
|
|
26
|
-
platformConfig.activeEnvironment !== 'prod' ? platformConfig.activeEnvironment : 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
|
},
|
|
54
|
-
tls: platformConfig.
|
|
43
|
+
tls: platformConfig.environmentType === 'local-dev' ? undefined : {
|
|
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 = {
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform config definition
|
|
3
|
+
* @typedef {Object} PlatformConfig
|
|
4
|
+
* @property {string} platformName - Name of platform
|
|
5
|
+
* @property {string} environmentType - local, test, qa, prod
|
|
6
|
+
*
|
|
7
|
+
* @property {string} awsAccountId - Aws account id
|
|
8
|
+
* @property {string=} awsRegion - ?
|
|
9
|
+
* @property {string=} awsKeyPairName - ?
|
|
10
|
+
* @property {string} awsRoleToAssume - ?
|
|
11
|
+
* @property {string=} awsDeploymentSqsName - ?
|
|
12
|
+
* @property {string=} awsDeploymentSqsArn - ?
|
|
13
|
+
*
|
|
14
|
+
* @property {string=} ciDockerNetworkName - ?
|
|
15
|
+
* @property {string} ciGithubActionsRepo - organisation/repoName
|
|
16
|
+
*/
|
|
17
|
+
|
|
1
18
|
const SupportedRegions = {
|
|
2
19
|
North: 'eu-north-1'
|
|
3
20
|
}
|
|
@@ -11,16 +28,10 @@ const SupportedEnvironments = {
|
|
|
11
28
|
}
|
|
12
29
|
|
|
13
30
|
const SupportedDeploymentTypes = {
|
|
14
|
-
Container: 'CONTAINER'
|
|
15
|
-
|
|
31
|
+
Container: 'CONTAINER',
|
|
32
|
+
Static: 'STATIC'
|
|
16
33
|
}
|
|
17
34
|
|
|
18
|
-
// export interface PlatformConfig extends Required<Omit<PlatformTemplate, 'awsRoleToAssume' | 'awsKeyPairName'>> {
|
|
19
|
-
// activeEnvironment: SupportedEnvironments;
|
|
20
|
-
// awsRoleToAssume?: string;
|
|
21
|
-
// awsKeyPairName?: string;
|
|
22
|
-
// }
|
|
23
|
-
|
|
24
35
|
/**
|
|
25
36
|
* @class
|
|
26
37
|
*/
|
|
@@ -31,17 +42,17 @@ class PlatformConfigService {
|
|
|
31
42
|
const withDefaults = {
|
|
32
43
|
platformName: SupportedEnvironments.LOCAL,
|
|
33
44
|
domain: 'localhost',
|
|
34
|
-
|
|
35
|
-
supportedDeploymentTypes: ['CONTAINER'],
|
|
36
|
-
ciSubDomain: 'ci',
|
|
37
|
-
ciInternalServerPort: 3000,
|
|
38
|
-
ciServerName: 'ci-client',
|
|
39
|
-
ciDockerNetworkName: 'deployment-tools',
|
|
45
|
+
environmentType: SupportedEnvironments.LOCAL,
|
|
40
46
|
awsRegion: SupportedRegions.North,
|
|
41
|
-
...template
|
|
47
|
+
...template,
|
|
48
|
+
// values below should not be overriden by the template properties
|
|
49
|
+
ciDockerNetworkName: 'deployment-tools',
|
|
42
50
|
}
|
|
43
51
|
|
|
44
|
-
const
|
|
52
|
+
const awsDeploymentSqsName = `${withDefaults.platformName}-container-deployments-requests`
|
|
53
|
+
|
|
54
|
+
const awsDeploymentSqsArn =
|
|
55
|
+
`https://sqs.${withDefaults.awsRegion}.amazonaws.com/${withDefaults.awsAccountId}/${awsDeploymentSqsName}`
|
|
45
56
|
|
|
46
57
|
const awsRoleToAssume = process.env.CI
|
|
47
58
|
? `github-ci-role-${withDefaults.platformName}`
|
|
@@ -49,8 +60,9 @@ class PlatformConfigService {
|
|
|
49
60
|
|
|
50
61
|
return {
|
|
51
62
|
...withDefaults,
|
|
63
|
+
awsDeploymentSqsName,
|
|
52
64
|
awsDeploymentSqsArn,
|
|
53
|
-
awsRoleToAssume
|
|
65
|
+
awsRoleToAssume,
|
|
54
66
|
}
|
|
55
67
|
|
|
56
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,63 +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
|
-
|
|
49
|
-
.
|
|
50
|
-
.
|
|
23
|
+
return Promise.all([
|
|
24
|
+
DeploymentTemplateService.readOssyFiles(globPatternForOssyFiles),
|
|
25
|
+
PlatformTemplateService.readFromFile(pathToPlatformTemplates)
|
|
26
|
+
.then(templates => templates.map(PlatformConfigService.from))
|
|
27
|
+
])
|
|
28
|
+
.then(([deploymentTemplates, platformConfigs]) => {
|
|
51
29
|
|
|
52
|
-
|
|
30
|
+
const platformConfig = platformConfigs.find(({ platformName }) => platformName === targetPlatform)
|
|
31
|
+
const deploymentTemplatesForTargetPlatform = deploymentTemplates[targetPlatform] || []
|
|
32
|
+
const deploymentTemplate = deploymentTemplatesForTargetPlatform.find(({ domain }) => domain === targetDomain)
|
|
53
33
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
34
|
+
if (!platformConfig) {
|
|
35
|
+
logError({ message: `[PlatformDeploymentService] Could not find a platform named ${targetPlatform}` })
|
|
36
|
+
return Promise.reject()
|
|
37
|
+
}
|
|
57
38
|
|
|
58
|
-
|
|
39
|
+
if (!deploymentTemplate) {
|
|
40
|
+
logError({ message: `[PlatformDeploymentService] Could not find a deployment template for ${targetDomain} in ${targetPlatform}` })
|
|
41
|
+
return Promise.reject()
|
|
42
|
+
}
|
|
59
43
|
|
|
60
|
-
|
|
61
|
-
logError({ message: `[PlatformDeploymentService] Could not find a deployment platform with the name ${deploymentTemplate.targetDeploymentPlatform}` })
|
|
62
|
-
return Promise.reject()
|
|
63
|
-
}
|
|
44
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
|
64
45
|
|
|
65
|
-
|
|
46
|
+
if (deploymentTemplate.type === SupportedDeploymentTypes.Container) {
|
|
66
47
|
|
|
67
|
-
|
|
68
|
-
logError({ message: `[PlatformDeploymentService] Unsupported deployment type of ${deploymentTemplate.type}` })
|
|
69
|
-
return Promise.reject()
|
|
70
|
-
}
|
|
48
|
+
const caddyConfig = CaddyConfigService.createConfig(platformConfig, deploymentTemplatesForTargetPlatform)
|
|
71
49
|
|
|
72
50
|
const deploymentRequest = {
|
|
73
51
|
...deploymentTemplate,
|
|
74
|
-
env: PlatformDeploymentService.getEnvironmentVariables(targetEnvironment, deploymentTemplate),
|
|
75
52
|
username: username,
|
|
76
|
-
authentication: authentication
|
|
53
|
+
authentication: authentication,
|
|
54
|
+
caddyConfig
|
|
77
55
|
}
|
|
78
56
|
|
|
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
|
-
static getEnvironmentVariables(targetEnvironment, deploymentRequest) {
|
|
93
|
-
const envs = deploymentRequest.env || {}
|
|
94
|
-
return {
|
|
95
|
-
...(envs.shared || {}),
|
|
96
|
-
...(envs[targetEnvironment] || {})
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
66
|
}
|
|
101
67
|
|
|
102
68
|
module.exports = {
|
|
@@ -1,30 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/* eslint-disable no-new */
|
|
3
3
|
const { App } = require('aws-cdk-lib')
|
|
4
|
-
|
|
5
|
-
const {
|
|
6
|
-
const {
|
|
7
|
-
|
|
8
|
-
const { PlatformTemplateService } = require('../template')
|
|
4
|
+
const { TrustCiStack } = require('./trust-ci-stack')
|
|
5
|
+
const { DeploymentTargetStack } = require('./deployment-target-stack')
|
|
6
|
+
const { DnsStack } = require('./dns-stack')
|
|
7
|
+
const { PlatformTemplateService, DeploymentTemplateService } = require('../template')
|
|
9
8
|
const { PlatformConfigService } = require('../config')
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
.
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
const { PlatformDeploymentService } = require('../deploy')
|
|
10
|
+
|
|
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]) => {
|
|
16
18
|
const app = new App()
|
|
17
19
|
|
|
18
20
|
configs.forEach(config => {
|
|
19
|
-
const env = { account: config.awsAccountId, region: config.awsRegion }
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
const stackProps = {
|
|
23
|
+
config,
|
|
24
|
+
env: {
|
|
25
|
+
account: config.awsAccountId,
|
|
26
|
+
region: config.awsRegion
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
new TrustCiStack(app, `${config.platformName}-trust-ci`, stackProps)
|
|
31
|
+
|
|
32
|
+
const deploymentTarget = new DeploymentTargetStack(app, `${config.platformName}-deployment-target`, stackProps)
|
|
22
33
|
|
|
23
|
-
config.
|
|
24
|
-
|
|
25
|
-
.
|
|
26
|
-
|
|
27
|
-
|
|
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
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { CfnOutput } = require('aws-cdk-lib')
|
|
1
|
+
const { CfnOutput, Duration, RemovalPolicy } = require('aws-cdk-lib')
|
|
2
2
|
const { Construct } = require('constructs')
|
|
3
3
|
const {
|
|
4
4
|
Instance,
|
|
@@ -12,25 +12,23 @@ const {
|
|
|
12
12
|
Port,
|
|
13
13
|
UserData
|
|
14
14
|
} = require('aws-cdk-lib/aws-ec2')
|
|
15
|
-
const { HostedZone, ARecord, RecordTarget } = require('aws-cdk-lib/aws-route53')
|
|
16
15
|
const { Role, ServicePrincipal, Policy, PolicyStatement, Effect } = require('aws-cdk-lib/aws-iam')
|
|
17
|
-
const {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
getInstallDocker
|
|
21
|
-
} = require('./user-data-commands')
|
|
16
|
+
const { Queue } = require('aws-cdk-lib/aws-sqs')
|
|
17
|
+
const { Source, BucketDeployment } = require('aws-cdk-lib/aws-s3-deployment')
|
|
18
|
+
const { getInstallNodeJs, getInstallNpm, getInstallDocker } = require('./user-data-commands')
|
|
22
19
|
const { CaddyService } = require('./caddy.service')
|
|
23
20
|
const { DeploymentToolsService } = require('./deployment-tools.service')
|
|
24
21
|
const { AwsProfile } = require('./aws-profile')
|
|
25
22
|
const { SupportedRegions } = require('../../config')
|
|
26
23
|
|
|
27
24
|
/**
|
|
28
|
-
*
|
|
25
|
+
* ContainerServerProps
|
|
29
26
|
* @namespace ContainerServer
|
|
30
27
|
* @typedef {Object} ContainerServerProps
|
|
31
|
-
* @property {PlatformConfig}
|
|
32
|
-
* @property {Bucket}
|
|
28
|
+
* @property {PlatformConfig} config - platform config
|
|
29
|
+
* @property {Bucket} bucket - s3 bucket
|
|
33
30
|
*/
|
|
31
|
+
|
|
34
32
|
const InstanceImages = {
|
|
35
33
|
UBUNTU: 'ami-092cce4a19b438926'
|
|
36
34
|
}
|
|
@@ -38,11 +36,9 @@ const InstanceImages = {
|
|
|
38
36
|
/**
|
|
39
37
|
* @class
|
|
40
38
|
*/
|
|
41
|
-
class
|
|
39
|
+
class ContainerDeploymentTarget extends Construct {
|
|
42
40
|
|
|
43
41
|
/**
|
|
44
|
-
* EC2 Instance that docker containers are served on
|
|
45
|
-
*
|
|
46
42
|
* @param {object} scope - scope
|
|
47
43
|
* @param {string} id - id
|
|
48
44
|
* @param {ContainerServerProps} props - ContainerServerProps
|
|
@@ -50,18 +46,8 @@ class ContainerServer extends Construct {
|
|
|
50
46
|
constructor(scope, id, props) {
|
|
51
47
|
super(scope, id)
|
|
52
48
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
const vpc = Vpc.fromLookup(this, 'VPC', {
|
|
58
|
-
isDefault: true
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
const securityGroup = new SecurityGroup(this, 'SecurityGroup', {
|
|
62
|
-
vpc,
|
|
63
|
-
allowAllOutbound: true
|
|
64
|
-
})
|
|
49
|
+
const vpc = Vpc.fromLookup(this, 'VPC', { isDefault: true })
|
|
50
|
+
const securityGroup = new SecurityGroup(this, 'SecurityGroup', { vpc, allowAllOutbound: true })
|
|
65
51
|
|
|
66
52
|
securityGroup.addIngressRule(
|
|
67
53
|
Peer.anyIpv4(),
|
|
@@ -81,6 +67,16 @@ class ContainerServer extends Construct {
|
|
|
81
67
|
'allow HTTPS traffic from anywhere'
|
|
82
68
|
)
|
|
83
69
|
|
|
70
|
+
const deploymentQueue = new Queue(this, 'DeploymentQueue', {
|
|
71
|
+
queueName: `${props.config.awsDeploymentSqsName}`,
|
|
72
|
+
receiveMessageWaitTime: Duration.seconds(20)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const platformConfigDeployment = new BucketDeployment(this, 'PlatformConfigDeployment', {
|
|
76
|
+
sources: [Source.jsonData('platform-config.json', props.config)],
|
|
77
|
+
destinationBucket: props.bucket
|
|
78
|
+
})
|
|
79
|
+
|
|
84
80
|
const role = new Role(this, 'role', {
|
|
85
81
|
assumedBy: new ServicePrincipal('ec2.amazonaws.com')
|
|
86
82
|
})
|
|
@@ -95,7 +91,7 @@ class ContainerServer extends Construct {
|
|
|
95
91
|
'route53:ChangeResourceRecordSets'
|
|
96
92
|
],
|
|
97
93
|
resources: [
|
|
98
|
-
`arn:aws:route53:::hostedzone
|
|
94
|
+
`arn:aws:route53:::hostedzone/*`,
|
|
99
95
|
'arn:aws:route53:::change/*'
|
|
100
96
|
]
|
|
101
97
|
}),
|
|
@@ -127,7 +123,7 @@ class ContainerServer extends Construct {
|
|
|
127
123
|
)
|
|
128
124
|
|
|
129
125
|
userData.addS3DownloadCommand({
|
|
130
|
-
bucket: props.
|
|
126
|
+
bucket: props.bucket,
|
|
131
127
|
bucketKey: 'platform-config.json',
|
|
132
128
|
localFile: '/home/ubuntu/platform-config.json'
|
|
133
129
|
})
|
|
@@ -152,25 +148,15 @@ class ContainerServer extends Construct {
|
|
|
152
148
|
machineImage: new GenericLinuxImage({
|
|
153
149
|
[SupportedRegions.North]: InstanceImages.UBUNTU
|
|
154
150
|
}),
|
|
155
|
-
keyName: props.
|
|
151
|
+
keyName: props.config.awsKeyPairName
|
|
156
152
|
})
|
|
157
153
|
|
|
158
|
-
props.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
// const hostedZone = !!props.createNewHostedZone
|
|
162
|
-
// ? new PublicHostedZone(this, 'HostedZone', { zoneName: props.domain })
|
|
163
|
-
// : HostedZone.fromLookup(this, 'HostedZone', { domainName: props.domain });
|
|
154
|
+
props.bucket.grantRead(ec2Instance, '*')
|
|
155
|
+
deploymentQueue.grant(ec2Instance, '*')
|
|
164
156
|
|
|
165
|
-
|
|
166
|
-
new ARecord(this, 'WildcardRecord', {
|
|
167
|
-
zone: hostedZone,
|
|
168
|
-
recordName: `*.${props.platformConfig.activeEnvironment}.${props.platformConfig.domain}`,
|
|
169
|
-
target: RecordTarget.fromIpAddresses(ec2Instance.instancePublicIp)
|
|
170
|
-
})
|
|
157
|
+
this.instancePublicIp = ec2Instance.instancePublicIp
|
|
171
158
|
|
|
172
|
-
|
|
173
|
-
new CfnOutput(this, 'Intance Ip', {
|
|
159
|
+
new CfnOutput(this, 'Instance Ip', {
|
|
174
160
|
value: ec2Instance.instancePublicIp,
|
|
175
161
|
description: 'Public ip of the ec2 instance',
|
|
176
162
|
exportName: 'instanceIp'
|
|
@@ -180,5 +166,5 @@ class ContainerServer extends Construct {
|
|
|
180
166
|
}
|
|
181
167
|
|
|
182
168
|
module.exports = {
|
|
183
|
-
|
|
169
|
+
ContainerDeploymentTarget
|
|
184
170
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* eslint-disable no-new */
|
|
2
|
+
const { nanoid } = require('nanoid')
|
|
3
|
+
const { Stack, Duration, RemovalPolicy } = require('aws-cdk-lib')
|
|
4
|
+
const { HostedZone, ARecord, RecordTarget } = require('aws-cdk-lib/aws-route53')
|
|
5
|
+
const { Bucket, BucketEncryption, BlockPublicAccess } = require('aws-cdk-lib/aws-s3')
|
|
6
|
+
const { ContainerDeploymentTarget } = require('./container-deployment-target')
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @class
|
|
10
|
+
*/
|
|
11
|
+
class DeploymentTargetStack extends Stack {
|
|
12
|
+
constructor(scope, id, props) {
|
|
13
|
+
super(scope, id, props)
|
|
14
|
+
|
|
15
|
+
if (!props?.config) {
|
|
16
|
+
throw ('[DeploymentTargetStack] No template provided')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const bucketId = nanoid().toLowerCase().replaceAll('_', '').replaceAll('-', '')
|
|
20
|
+
const bucketName = `${props.config.platformName}-${bucketId}`
|
|
21
|
+
|
|
22
|
+
// TODO: this should probably not be destroyed....
|
|
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
|
+
})
|
|
31
|
+
|
|
32
|
+
// TODO: add persistant storage
|
|
33
|
+
const containerDeploymentTarget =
|
|
34
|
+
new ContainerDeploymentTarget(this, 'ContainerDeploymentTarget', {
|
|
35
|
+
config: props.config,
|
|
36
|
+
bucket: staticDeploymentTarget
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
this.containerDeploymentTargetPublicIp = containerDeploymentTarget.instancePublicIp
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = {
|
|
45
|
+
DeploymentTargetStack
|
|
46
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -11,7 +11,7 @@ const {
|
|
|
11
11
|
/**
|
|
12
12
|
* @class
|
|
13
13
|
*/
|
|
14
|
-
class
|
|
14
|
+
class TrustCiStack extends Stack {
|
|
15
15
|
/**
|
|
16
16
|
* Establishes trust between GithHub and Amazon Web Services.
|
|
17
17
|
* This is needed so that we can interact with Amazon Web Services through
|
|
@@ -50,7 +50,7 @@ class EstablishTrustStack 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}:*`
|
|
@@ -64,5 +64,5 @@ class EstablishTrustStack extends Stack {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
module.exports = {
|
|
67
|
-
|
|
67
|
+
TrustCiStack
|
|
68
68
|
}
|
|
@@ -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
|
@@ -7,8 +7,7 @@ const { logError, logInfo } = require('../log')
|
|
|
7
7
|
* @typedef {Object} PlatformTemplate
|
|
8
8
|
* @property {string} platformName - Name of platform
|
|
9
9
|
* @property {string} domain - example.com
|
|
10
|
-
* @property {string
|
|
11
|
-
* @property {string[]} supportedEnvironments - qa
|
|
10
|
+
* @property {string} environmentType - local, test, qa, prod
|
|
12
11
|
*
|
|
13
12
|
* @property {string} awsAccountId - Aws account id
|
|
14
13
|
* @property {string=} awsRegion - ?
|
|
@@ -16,10 +15,6 @@ const { logError, logInfo } = require('../log')
|
|
|
16
15
|
* @property {string} awsRoleToAssume - ?
|
|
17
16
|
* @property {string=} awsDeploymentSqsArn - ?
|
|
18
17
|
*
|
|
19
|
-
* @property {string=} ciSubDomain - ?
|
|
20
|
-
* @property {string|mumber=} ciInternalServerPort - ? | number;
|
|
21
|
-
* @property {string=} ciServerName - ?
|
|
22
|
-
* @property {string=} ciDockerNetworkName - ?
|
|
23
18
|
* @property {string} ciGithubActionsRepo - organisation/repoName
|
|
24
19
|
*/
|
|
25
20
|
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
const { CaddyService } = require('./caddy')
|
|
2
|
-
|
|
3
|
-
const config = {
|
|
4
|
-
activeEnvironment: '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)
|
|
@@ -1,58 +0,0 @@
|
|
|
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
|
-
const { nanoid } = require('nanoid')
|
|
7
|
-
|
|
8
|
-
const { ContainerServer } = require('./container-server')
|
|
9
|
-
|
|
10
|
-
const { SupportedDeploymentTypes } = require('../config')
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @class
|
|
14
|
-
*/
|
|
15
|
-
class PlatformStack extends Stack {
|
|
16
|
-
constructor(scope, id, props) {
|
|
17
|
-
super(scope, id, props)
|
|
18
|
-
|
|
19
|
-
if (!props?.config) {
|
|
20
|
-
throw ('[PlatformStack] No template config provided')
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const isContainerDeploymentsEnabled = props.config.supportedDeploymentTypes.includes(SupportedDeploymentTypes.Container)
|
|
24
|
-
|
|
25
|
-
if (isContainerDeploymentsEnabled) {
|
|
26
|
-
|
|
27
|
-
const deploymentQueue = new Queue(this, 'DeploymentQueue', {
|
|
28
|
-
queueName: `${props.config.platformName}-${props.config.activeEnvironment}`,
|
|
29
|
-
receiveMessageWaitTime: Duration.seconds(20)
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
const platformConfigBucket = new Bucket(this, 'PlatformConfig', {
|
|
33
|
-
bucketName: `${props.config.platformName}-${props.config.activeEnvironment}-${nanoid().toLowerCase().replaceAll('_', '').replaceAll('-', '')}`,
|
|
34
|
-
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
|
|
35
|
-
encryption: BucketEncryption.S3_MANAGED,
|
|
36
|
-
removalPolicy: RemovalPolicy.DESTROY,
|
|
37
|
-
autoDeleteObjects: true
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
const platformConfigDeployment = new BucketDeployment(this, 'PlatformConfigDeployment', {
|
|
41
|
-
sources: [Source.jsonData('platform-config.json', props.config)],
|
|
42
|
-
destinationBucket: platformConfigBucket
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
new ContainerServer(this, 'ContainerServer', {
|
|
46
|
-
platformConfig: props.config,
|
|
47
|
-
platformConfigBucket: platformConfigDeployment.deployedBucket,
|
|
48
|
-
deploymentQueue: deploymentQueue
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
module.exports = {
|
|
57
|
-
PlatformStack
|
|
58
|
-
}
|
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
|