@ossy/deployment-tools 0.0.68 → 0.0.70

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.
Files changed (26) hide show
  1. package/README.md +17 -1
  2. package/package.json +2 -1
  3. package/src/aws-credentials/cli.js +1 -2
  4. package/src/caddy/caddy-config.js +23 -25
  5. package/src/caddy/caddy.js +5 -43
  6. package/src/config/platform-config.js +6 -9
  7. package/src/deploy/cli.js +15 -9
  8. package/src/deploy/index.js +1 -0
  9. package/src/deploy/platform-deployment.js +33 -59
  10. package/src/infrastructure/cli.js +19 -8
  11. package/src/infrastructure/{container-server/container-server.js → container-deployment-target/container-deployment-target.js} +6 -18
  12. package/src/infrastructure/container-deployment-target/index.js +3 -0
  13. package/src/infrastructure/deployment-target-stack.js +14 -15
  14. package/src/infrastructure/dns-stack.js +61 -0
  15. package/src/infrastructure/trust-ci-stack.js +1 -1
  16. package/src/server/platform-server.js +1 -4
  17. package/src/template/deployment-template.js +86 -0
  18. package/src/template/index.js +4 -1
  19. package/src/caddy/caddy.playground.js +0 -21
  20. package/src/infrastructure/container-server/index.js +0 -3
  21. package/src/server/platform-server.playground.js +0 -10
  22. package/src/server/rest-api.js +0 -31
  23. /package/src/infrastructure/{container-server → container-deployment-target}/aws-profile.js +0 -0
  24. /package/src/infrastructure/{container-server → container-deployment-target}/caddy.service.js +0 -0
  25. /package/src/infrastructure/{container-server → container-deployment-target}/deployment-tools.service.js +0 -0
  26. /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.68",
3
+ "version": "0.0.70",
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 stackname = parsedArgs['--target-platform'] || ''
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 getRouteConfig(platformConfig, deploymentRequest) {
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
- return {
33
- match: [Matchers.host(url)],
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
- [platformConfig.ciServerName]: {
34
+ 'deployment-tools': {
44
35
  listen: [':80', ':443'],
45
- routes: [
46
- {
47
- match: [Matchers.host(`${platformConfig.ciSubDomain}.${platformConfig.environmentType}.${platformConfig.domain}`)],
48
- handle: [Handlers.subroute([{ handle: [Handlers.reverseProxy(platformConfig.ciInternalServerPort)]}])]
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:[`*.${platformConfig.environmentType}.${platformConfig.domain}`],
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'
@@ -7,55 +7,17 @@ const { logInfo, logError, logDebug } = require('../log')
7
7
  */
8
8
  class CaddyService {
9
9
 
10
- static addDeployment(platformConfig, deploymentRequest) {
11
- const routeConfig = CaddyConfigService.getRouteConfig(platformConfig, deploymentRequest)
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(routeConfig)
14
+ body: JSON.stringify(config)
19
15
  })
20
- .then(response => response?.error && logError({ message: `[CaddyService] Could not update caddy config to include ${host}`, error }))
21
- .catch(error => logError({ message: `[CaddyService] Could not update caddy config to include ${host}`, error }))
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}/${withDefaults.platformName}-${withDefaults.environmentType}`
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
- '--target-env': String,
17
- '-t': '--target-env',
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
- targetEnvironment: parsedArgs['--target-env'],
30
- pathToPlatformTemplates: parsedArgs['--platforms'],
31
- pathToOssyFile: parsedArgs['--ossyfile']
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 { PlatformTemplateService } = require('../template')
4
- const { PlatformConfigService, SupportedDeploymentTypes } = require('../config')
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
- targetEnvironment,
17
+ targetDomain,
18
+ targetPlatform,
44
19
  pathToPlatformTemplates,
45
- pathToOssyFile
20
+ globPatternForOssyFiles
46
21
  }) {
47
22
 
48
23
  return Promise.all([
49
- PlatformDeploymentService.getDeploymentTemplates(pathToOssyFile),
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
- const platformConfig = platformConfigs.find(config =>
57
- config.platformName === deploymentTemplate.targetDeploymentPlatform
58
- && config.environmentType == targetEnvironment
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
- if (!platformConfig) {
62
- logError({ message: `[PlatformDeploymentService] Could not find a deployment platform with the name ${deploymentTemplate.targetDeploymentPlatform} and environment type ${targetEnvironment}` })
63
- return Promise.reject()
64
- }
34
+ if (!platformConfig) {
35
+ logError({ message: `[PlatformDeploymentService] Could not find a platform named ${targetPlatform}` })
36
+ return Promise.reject()
37
+ }
65
38
 
66
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
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
- if (deploymentTemplate.type === SupportedDeploymentTypes.Container) {
69
- const deploymentRequest = {
70
- ...deploymentTemplate,
71
- username: username,
72
- authentication: authentication
73
- }
48
+ const caddyConfig = CaddyConfigService.createConfig(platformConfig, deploymentTemplatesForTargetPlatform)
74
49
 
75
- return DeploymentQueueService.sendDeploymentRequest(platformConfig, deploymentRequest)
50
+ const deploymentRequest = {
51
+ ...deploymentTemplate,
52
+ username: username,
53
+ authentication: authentication,
54
+ caddyConfig
76
55
  }
77
56
 
78
- logError({ message: `[PlatformDeploymentService] Unsupported deployment type of ${deploymentTemplate.type}` })
79
- return Promise.reject()
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 { PlatformTemplateService } = require('../template')
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
- PlatformTemplateService
10
- .readFromFile(process.env.PLATFORMS)
11
- .then(templates => templates.map(PlatformConfigService.from))
12
- .then(configs => {
11
+ Promise.all([
12
+ DeploymentTemplateService.readOssyFiles(process.env.OSSY_FILES),
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, `${stackBaseName}-trust-ci`, stackProps)
27
- new DeploymentTargetStack(app, `${stackBaseName}-deployment-target`, stackProps)
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 ContainerServer extends Construct {
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.platformName}-${props.config.environmentType}`,
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/${props.hostedZone.hostedZoneId}`,
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
- new ARecord(this, 'WildcardRecord', {
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
- ContainerServer
169
+ ContainerDeploymentTarget
182
170
  }
@@ -0,0 +1,3 @@
1
+ const { ContainerDeploymentTarget } = require('./container-deployment-target')
2
+
3
+ module.exports = { ContainerDeploymentTarget }
@@ -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 { ContainerServer } = require('./container-server')
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}-${props.config.environmentType}-${bucketId}`
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 = new Bucket(this, 'StaticDeploymentTarget', {
27
- bucketName: bucketName,
28
- blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
29
- encryption: BucketEncryption.S3_MANAGED,
30
- removalPolicy: RemovalPolicy.DESTROY,
31
- autoDeleteObjects: true
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
- new ContainerServer(this, 'ContainerDeploymentTarget', {
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,16 +17,14 @@ 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
- CaddyService.applyDefaultConfig(platformConfig)
25
22
 
26
23
  DeploymentQueueService.pollForDeploymentRequests(
27
24
  platformConfig,
28
25
  deploymentRequest => {
29
26
  DockerService.deploy(platformConfig, deploymentRequest)
30
- .then(() => CaddyService.addDeployment(platformConfig, deploymentRequest))
27
+ .then(() => CaddyService.applyConfig(deploymentRequest.caddyConfig))
31
28
  return Promise.resolve()
32
29
  }
33
30
  )
@@ -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
+ }
@@ -1 +1,4 @@
1
- module.exports = require('./platform-template')
1
+ module.exports = {
2
+ ...require('./deployment-template'),
3
+ ...require('./platform-template')
4
+ }
@@ -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)
@@ -1,3 +0,0 @@
1
- const { ContainerServer } = require('./container-server')
2
-
3
- module.exports = { ContainerServer }
@@ -1,10 +0,0 @@
1
- // const { PlatformServerService } = require('./platform-server')
2
- const { RestApiService } = require('./rest-api')
3
-
4
- // PlatformServerService.start({
5
- //
6
- // })
7
-
8
- RestApiService.start({
9
- ciInternalServerPort: 3000
10
- })
@@ -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
- }