@ossy/deployment-tools 0.0.44 → 0.0.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -4
- package/cdk.context.json +37 -0
- package/cdk.json +40 -0
- package/package.json +18 -8
- package/src/aws-credentials/aws-credentials.js +74 -0
- package/src/aws-credentials/cli.js +28 -0
- package/src/aws-credentials/index.js +1 -0
- package/src/config/index.js +1 -0
- package/src/{platform-config.js → config/platform-config.js} +24 -5
- package/src/{cli-commands/deploy-handler.js → deploy/cli.js} +12 -6
- package/src/deploy/platform-deployment.js +74 -0
- package/src/{deployment-queue-client.js → deployment-queue/deployment-queue.js} +20 -16
- package/src/deployment-queue/index.js +1 -0
- package/src/index.js +5 -3
- package/src/infrastructure/cli.js +30 -0
- package/src/infrastructure/container-server/aws-profile.js +22 -0
- package/src/infrastructure/container-server/caddy.service.js +69 -0
- package/src/infrastructure/container-server/container-server.js +175 -0
- package/src/infrastructure/container-server/deployment-tools.service.js +37 -0
- package/src/infrastructure/container-server/index.js +3 -0
- package/src/infrastructure/container-server/user-data-commands.js +32 -0
- package/src/infrastructure/establish-trust-stack.js +65 -0
- package/src/infrastructure/platform-stack.js +53 -0
- package/src/log.js +9 -3
- package/src/{caddy-client.js → server/caddy.js} +14 -10
- package/src/server/cli.js +34 -0
- package/src/{docker-client.js → server/docker.js} +16 -16
- package/src/server/platform-server.js +37 -0
- package/src/{ci-rest-api.js → server/rest-api.js} +8 -4
- package/src/template/cli.js +22 -0
- package/src/template/index.js +1 -0
- package/src/{platform-template.js → template/platform-template.js} +9 -5
- package/src/types.js +0 -33
- package/src/aws-credentials-client.js +0 -43
- package/src/cli-commands/index.js +0 -23
- package/src/cli-commands/start-handler.js +0 -24
- package/src/cli-commands/status-handler.js +0 -7
- package/src/cli-commands/stop-handler.js +0 -7
- package/src/platform-cli.js +0 -7
- package/src/platform-client.js +0 -95
package/README.md
CHANGED
|
@@ -3,27 +3,29 @@
|
|
|
3
3
|
Collection of scripts and tools to aid deployment of
|
|
4
4
|
containers and static files to Amazon Web Services through GitHub Actions
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## Server
|
|
7
7
|
|
|
8
8
|
### start
|
|
9
9
|
Starts a node server in the background that polls an deployment queue for container deployment requests.
|
|
10
10
|
Make sure NodeJs and npm is installed and Docker and Caddy is up and running.
|
|
11
11
|
```bash
|
|
12
|
-
npx @ossy/deployment-tools start
|
|
12
|
+
npx @ossy/deployment-tools server start
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
### stop
|
|
16
16
|
Stops the deployment-tools systemd service
|
|
17
17
|
```bash
|
|
18
|
-
npx @ossy/deployment-tools stop
|
|
18
|
+
npx @ossy/deployment-tools server stop
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
### status
|
|
22
22
|
Prints the status of the deployment-tools systemd service
|
|
23
23
|
```bash
|
|
24
|
-
npx @ossy/deployment-tools status
|
|
24
|
+
npx @ossy/deployment-tools server status
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
## Deployment
|
|
28
|
+
|
|
27
29
|
### deploy
|
|
28
30
|
Sends a deployment request to the aws sqs deployment queue.
|
|
29
31
|
```bash
|
|
@@ -34,3 +36,27 @@ npx --yes @ossy/deployment-tools deploy \
|
|
|
34
36
|
--platforms packages/infrastructure/bin/deployment-platforms.json \
|
|
35
37
|
--ossyfile packages/${{ github.event.inputs.packageName }}/ossy.json \
|
|
36
38
|
```
|
|
39
|
+
|
|
40
|
+
## Infrastructure
|
|
41
|
+
|
|
42
|
+
<!-- Deploys AWS infrastructure
|
|
43
|
+
```
|
|
44
|
+
npx --yes @ossy/deployment-tools infrastructure deploy
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Destroys AWS infrastructure
|
|
48
|
+
```
|
|
49
|
+
npx --yes @ossy/deployment-tools infrastructure destroy
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Prints AWS infrastructure stacks
|
|
53
|
+
```
|
|
54
|
+
npx --yes @ossy/deployment-tools infrastructure ls
|
|
55
|
+
``` -->
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
The `cdk.json` file tells the CDK Toolkit how to execute your app.
|
|
59
|
+
|
|
60
|
+
* `cdk deploy` deploy this stack to your default AWS account/region
|
|
61
|
+
* `cdk diff` compare deployed stack with current state
|
|
62
|
+
* `cdk synth` emits the synthesized CloudFormation template
|
package/cdk.context.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"vpc-provider:account=322874034009:filter.isDefault=true:region=eu-north-1:returnAsymmetricSubnets=true": {
|
|
3
|
+
"vpcId": "vpc-50df1939",
|
|
4
|
+
"vpcCidrBlock": "172.31.0.0/16",
|
|
5
|
+
"availabilityZones": [],
|
|
6
|
+
"subnetGroups": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Public",
|
|
9
|
+
"type": "Public",
|
|
10
|
+
"subnets": [
|
|
11
|
+
{
|
|
12
|
+
"subnetId": "subnet-b88e49d1",
|
|
13
|
+
"cidr": "172.31.16.0/20",
|
|
14
|
+
"availabilityZone": "eu-north-1a",
|
|
15
|
+
"routeTableId": "rtb-2ce32245"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"subnetId": "subnet-6bed0b10",
|
|
19
|
+
"cidr": "172.31.32.0/20",
|
|
20
|
+
"availabilityZone": "eu-north-1b",
|
|
21
|
+
"routeTableId": "rtb-2ce32245"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"subnetId": "subnet-6d999827",
|
|
25
|
+
"cidr": "172.31.0.0/20",
|
|
26
|
+
"availabilityZone": "eu-north-1c",
|
|
27
|
+
"routeTableId": "rtb-2ce32245"
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"hosted-zone:account=322874034009:domainName=ossy.se:region=eu-north-1": {
|
|
34
|
+
"Id": "/hostedzone/Z05895872N99P5G3TLU28",
|
|
35
|
+
"Name": "ossy.se."
|
|
36
|
+
}
|
|
37
|
+
}
|
package/cdk.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"app": "node src/infrastructure/cli.js",
|
|
3
|
+
"watch": {
|
|
4
|
+
"include": [
|
|
5
|
+
"**"
|
|
6
|
+
],
|
|
7
|
+
"exclude": [
|
|
8
|
+
"README.md",
|
|
9
|
+
"cdk*.json",
|
|
10
|
+
"jest.config.js",
|
|
11
|
+
"package*.json",
|
|
12
|
+
"yarn.lock",
|
|
13
|
+
"node_modules",
|
|
14
|
+
"test"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"context": {
|
|
18
|
+
"@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
|
|
19
|
+
"@aws-cdk/core:stackRelativeExports": true,
|
|
20
|
+
"@aws-cdk/aws-rds:lowercaseDbIdentifier": true,
|
|
21
|
+
"@aws-cdk/aws-lambda:recognizeVersionProps": true,
|
|
22
|
+
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
|
|
23
|
+
"@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true,
|
|
24
|
+
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
|
|
25
|
+
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
|
|
26
|
+
"@aws-cdk/core:checkSecretUsage": true,
|
|
27
|
+
"@aws-cdk/aws-iam:minimizePolicies": true,
|
|
28
|
+
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
|
|
29
|
+
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
|
|
30
|
+
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
|
|
31
|
+
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
|
|
32
|
+
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
|
|
33
|
+
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
|
|
34
|
+
"@aws-cdk/core:enablePartitionLiterals": true,
|
|
35
|
+
"@aws-cdk/core:target-partitions": [
|
|
36
|
+
"aws",
|
|
37
|
+
"aws-cn"
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
}
|
package/package.json
CHANGED
|
@@ -1,27 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ossy/deployment-tools",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.46",
|
|
4
4
|
"description": "Collection of scripts and tools to aid deployment of containers and static files to Amazon Web Services through GitHub Actions",
|
|
5
|
-
"type": "module",
|
|
6
5
|
"main": "./src/index.js",
|
|
7
6
|
"scripts": {
|
|
8
7
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
9
|
-
"build": "",
|
|
10
|
-
"build:docs": "jsdoc ./src/index.js ./package.json"
|
|
8
|
+
"build": "echo \"The build step is not required when using JavaScript!\" && exit 0",
|
|
9
|
+
"build:docs": "jsdoc ./src/index.js ./package.json",
|
|
10
|
+
"cdk": "cdk"
|
|
11
11
|
},
|
|
12
12
|
"author": "Ossy",
|
|
13
13
|
"license": "ISC",
|
|
14
|
-
"bin":
|
|
14
|
+
"bin": {
|
|
15
|
+
"aws": "./src/aws-credentials/cli.js",
|
|
16
|
+
"deploy": "./src/deploy/cli.js",
|
|
17
|
+
"template": "./src/template/cli.js",
|
|
18
|
+
"server": "./src/server/cli.js",
|
|
19
|
+
"infrastructure": "./src/infrastructure/cli.js"
|
|
20
|
+
},
|
|
15
21
|
"dependencies": {
|
|
16
22
|
"@actions/core": "^1.10.0",
|
|
17
23
|
"@aws-sdk/client-sqs": "^3.186.0",
|
|
18
24
|
"@aws-sdk/client-sts": "^3.188.0",
|
|
19
25
|
"arg": "^5.0.2",
|
|
20
26
|
"express": "^4.18.1",
|
|
21
|
-
"nanoid": "^
|
|
22
|
-
"node-fetch": "^
|
|
27
|
+
"nanoid": "^3.3.4",
|
|
28
|
+
"node-fetch": "^2.6.7",
|
|
29
|
+
"aws-cdk-lib": "2.47.0",
|
|
30
|
+
"constructs": "^10.0.0"
|
|
23
31
|
},
|
|
24
32
|
"devDependencies": {
|
|
25
|
-
"jsdoc": "^3.6.11"
|
|
33
|
+
"jsdoc": "^3.6.11",
|
|
34
|
+
"aws-cdk": "2.47.0",
|
|
35
|
+
"jest": "^27.5.1"
|
|
26
36
|
}
|
|
27
37
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const core = require('@actions/core')
|
|
2
|
+
const { STSClient, AssumeRoleWithWebIdentityCommand } = require('@aws-sdk/client-sts')
|
|
3
|
+
|
|
4
|
+
const { logInfo, logError } = require('../log')
|
|
5
|
+
|
|
6
|
+
class AwsCredentialsService {
|
|
7
|
+
|
|
8
|
+
static resolveAwsCredentials(platformConfig) {
|
|
9
|
+
// If awsRoleToAssume is present, then we assume we run in a github workflow
|
|
10
|
+
// If awsRoleToAssume is not present, then we assume they are resolved localy by aws-sdk
|
|
11
|
+
if (!platformConfig.awsRoleToAssume) {
|
|
12
|
+
logInfo({ message: '[AwsCredentialsService] No aws role to assume was found, leaving auth logic to @aws-sdk package' })
|
|
13
|
+
return Promise.resolve(undefined)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const stsClient = new STSClient({ region: platformConfig.awsRegion })
|
|
17
|
+
|
|
18
|
+
logInfo({ message: '[AwsCredentialsService] Fetching GitHub ID token' })
|
|
19
|
+
return core.getIDToken('sts.amazonaws.com')
|
|
20
|
+
.then(webIdentityToken => {
|
|
21
|
+
logInfo({ message: `[AwsCredentialsService] Attempting to resolve aws credentials by assuming the role: ${platformConfig.awsRoleToAssume}` })
|
|
22
|
+
return stsClient.send(new AssumeRoleWithWebIdentityCommand({
|
|
23
|
+
RoleArn: `arn:aws:iam::${platformConfig.awsAccountId}:role/${platformConfig.awsRoleToAssume}`,
|
|
24
|
+
RoleSessionName: 'GitHubActions',
|
|
25
|
+
DurationSeconds: 15 * 60,
|
|
26
|
+
WebIdentityToken: webIdentityToken
|
|
27
|
+
}))
|
|
28
|
+
})
|
|
29
|
+
.then(responseData => ({
|
|
30
|
+
// Don't ask
|
|
31
|
+
AccessKeyId: responseData.Credentials.AccessKeyId,
|
|
32
|
+
SessionToken: responseData.Credentials.SessionToken,
|
|
33
|
+
SecretAccessKey: responseData.Credentials.SecretAccessKey,
|
|
34
|
+
accessKeyId: responseData.Credentials.AccessKeyId,
|
|
35
|
+
sessionToken: responseData.Credentials.SessionToken,
|
|
36
|
+
secretAccessKey: responseData.Credentials.SecretAccessKey
|
|
37
|
+
}))
|
|
38
|
+
.catch(error => {
|
|
39
|
+
logError({ message: '[AwsCredentialsService] Could not resolve temporary credentials', error })
|
|
40
|
+
return undefined
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static exportCredentialsToGithubWorkflow(params) {
|
|
45
|
+
// Configure the AWS CLI and AWS SDKs using environment variables and set them as secrets.
|
|
46
|
+
// Setting the credentials as secrets masks them in Github Actions logs
|
|
47
|
+
const { accessKeyId, secretAccessKey, sessionToken } = params
|
|
48
|
+
|
|
49
|
+
// AWS_ACCESS_KEY_ID:
|
|
50
|
+
// Specifies an AWS access key associated with an IAM user or role
|
|
51
|
+
core.setSecret(accessKeyId)
|
|
52
|
+
core.exportVariable('AWS_ACCESS_KEY_ID', accessKeyId)
|
|
53
|
+
|
|
54
|
+
// AWS_SECRET_ACCESS_KEY:
|
|
55
|
+
// Specifies the secret key associated with the access key. This is essentially the "password" for the access key.
|
|
56
|
+
core.setSecret(secretAccessKey)
|
|
57
|
+
core.exportVariable('AWS_SECRET_ACCESS_KEY', secretAccessKey)
|
|
58
|
+
|
|
59
|
+
// AWS_SESSION_TOKEN:
|
|
60
|
+
// Specifies the session token value that is required if you are using temporary security credentials.
|
|
61
|
+
if (sessionToken) {
|
|
62
|
+
core.setSecret(sessionToken)
|
|
63
|
+
core.exportVariable('AWS_SESSION_TOKEN', sessionToken)
|
|
64
|
+
} else if (process.env.AWS_SESSION_TOKEN) {
|
|
65
|
+
// clear session token from previous credentials action
|
|
66
|
+
core.exportVariable('AWS_SESSION_TOKEN', '')
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = {
|
|
73
|
+
AwsCredentialsService
|
|
74
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const arg = require('arg')
|
|
3
|
+
const { AwsCredentialsService } = require('./aws-credentials')
|
|
4
|
+
|
|
5
|
+
const { logInfo, logError } = require('../log')
|
|
6
|
+
|
|
7
|
+
//eslint-disable-next-line no-unused-vars
|
|
8
|
+
const [_, __, command, ...options] = process.argv
|
|
9
|
+
|
|
10
|
+
const resolveCredentials = () => {
|
|
11
|
+
logInfo({ message: 'resolve-credentials' })
|
|
12
|
+
|
|
13
|
+
const parsedArgs = arg({
|
|
14
|
+
'--access-key-id': String,
|
|
15
|
+
'--session-token': String,
|
|
16
|
+
'--secret-access-key': String
|
|
17
|
+
}, { argv: options })
|
|
18
|
+
|
|
19
|
+
AwsCredentialsService.exportCredentialsToGithubWorkflow({
|
|
20
|
+
accessKeyId: parsedArgs['--access-key-id'],
|
|
21
|
+
sessionToken: parsedArgs['--session-token'],
|
|
22
|
+
secretAccessKey: parsedArgs['--secret-access-key']
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
!!command
|
|
27
|
+
? { 'resolve-credentials': resolveCredentials }[command]()
|
|
28
|
+
: logError({ message: 'No command provided' })
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./aws-credentials')
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./platform-config')
|
|
@@ -1,9 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} from './types.js'
|
|
1
|
+
const SupportedRegions = {
|
|
2
|
+
North: 'eu-north-1'
|
|
3
|
+
}
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
const SupportedEnvironments = {
|
|
6
|
+
LOCAL: 'local',
|
|
7
|
+
QA: 'qa',
|
|
8
|
+
TEST: 'test',
|
|
9
|
+
DEMO: 'demo',
|
|
10
|
+
PROD: 'prod'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const SupportedDeploymentTypes = {
|
|
14
|
+
Container: 'CONTAINER'
|
|
15
|
+
// Static = 'STATIC'
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
class PlatformConfigService {
|
|
7
19
|
|
|
8
20
|
static from(template) {
|
|
9
21
|
|
|
@@ -32,3 +44,10 @@ export class PlatformConfigService {
|
|
|
32
44
|
}
|
|
33
45
|
|
|
34
46
|
}
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
PlatformConfigService,
|
|
50
|
+
SupportedRegions,
|
|
51
|
+
SupportedEnvironments,
|
|
52
|
+
SupportedDeploymentTypes
|
|
53
|
+
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const arg = require('arg')
|
|
3
|
+
const { PlatformDeploymentService } = require('./platform-deployment')
|
|
4
|
+
const { logInfo } = require('../log')
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
//eslint-disable-next-line no-unused-vars
|
|
7
|
+
const [_, __, ...options] = process.argv
|
|
8
|
+
|
|
9
|
+
const deploy = () => {
|
|
6
10
|
logInfo({ message: 'Running deploy command' })
|
|
7
11
|
|
|
8
12
|
const parsedArgs = arg({
|
|
@@ -20,9 +24,9 @@ export const deployHandler = cliArgs => {
|
|
|
20
24
|
|
|
21
25
|
'--platforms': String,
|
|
22
26
|
'-p': '--platforms'
|
|
23
|
-
}, { argv:
|
|
27
|
+
}, { argv: options })
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
PlatformDeploymentService.deploy({
|
|
26
30
|
username: parsedArgs['--username'],
|
|
27
31
|
authentication: parsedArgs['--authentication'],
|
|
28
32
|
targetEnvironment: parsedArgs['--target-env'],
|
|
@@ -30,3 +34,5 @@ export const deployHandler = cliArgs => {
|
|
|
30
34
|
pathToOssyFile: parsedArgs['--ossyfile']
|
|
31
35
|
})
|
|
32
36
|
}
|
|
37
|
+
|
|
38
|
+
deploy()
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const { resolve } = require('path')
|
|
2
|
+
const { readFileSync } = require('fs')
|
|
3
|
+
const { PlatformTemplateService } = require('../template')
|
|
4
|
+
const { PlatformConfigService, SupportedDeploymentTypes } = require('../config')
|
|
5
|
+
const { DeploymentQueueClient } = require('../deployment-queue')
|
|
6
|
+
const { logError } = require('../log')
|
|
7
|
+
|
|
8
|
+
class PlatformDeploymentService {
|
|
9
|
+
|
|
10
|
+
static deploy({
|
|
11
|
+
username,
|
|
12
|
+
authentication,
|
|
13
|
+
targetEnvironment,
|
|
14
|
+
pathToPlatformTemplates,
|
|
15
|
+
pathToOssyFile
|
|
16
|
+
}) {
|
|
17
|
+
|
|
18
|
+
const platformConfigRequest = PlatformTemplateService.readFromFile(pathToPlatformTemplates)
|
|
19
|
+
.then(templates => templates.map(x => ({ ...x, activeEnvironment: targetEnvironment })))
|
|
20
|
+
.then(templates => templates.map(x => PlatformConfigService.from(x)))
|
|
21
|
+
|
|
22
|
+
const deploymentTemplatesRequest = PlatformDeploymentService.getDeploymentTemplates(pathToOssyFile)
|
|
23
|
+
|
|
24
|
+
return Promise.all([platformConfigRequest, deploymentTemplatesRequest])
|
|
25
|
+
.then(([platformConfigs, deploymentTemplates]) => {
|
|
26
|
+
deploymentTemplates.map(deploymentTemplate => {
|
|
27
|
+
|
|
28
|
+
const platformConfig = platformConfigs.find(config => config.platformName === deploymentTemplate.targetDeploymentPlatform)
|
|
29
|
+
|
|
30
|
+
if (!platformConfig) {
|
|
31
|
+
logError({ message: `[PlatformDeploymentService] Could not find a deployment platform with the name ${deploymentTemplate.targetDeploymentPlatform}` })
|
|
32
|
+
return Promise.reject()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
|
|
36
|
+
|
|
37
|
+
if (deploymentTemplate.type !== SupportedDeploymentTypes.Container) {
|
|
38
|
+
logError({ message: `[PlatformDeploymentService] Unsupported deployment type of ${deploymentTemplate.type}` })
|
|
39
|
+
return Promise.reject()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const deploymentRequest = {
|
|
43
|
+
...deploymentTemplate,
|
|
44
|
+
env: PlatformDeploymentService.getEnvironmentVariables(targetEnvironment, deploymentTemplate),
|
|
45
|
+
username: username,
|
|
46
|
+
authentication: authentication
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return DeploymentQueueClient.sendDeploymentRequest(platformConfig, deploymentRequest)
|
|
50
|
+
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
.catch(error => logError({ message: '[PlatformDeploymentService] Could not send deployment request', error }))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static getDeploymentTemplates(pathToOssyFile) {
|
|
57
|
+
if (!pathToOssyFile) return logError({ message: '[PlatformDeploymentService] No path to ossy.json provided' })
|
|
58
|
+
const ossyfile = JSON.parse(readFileSync(resolve(pathToOssyFile), 'utf8'))
|
|
59
|
+
return Promise.resolve(ossyfile.deployments || [])
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static getEnvironmentVariables(targetEnvironment, deploymentRequest) {
|
|
63
|
+
const envs = deploymentRequest.env || {}
|
|
64
|
+
return {
|
|
65
|
+
...(envs.shared || {}),
|
|
66
|
+
...(envs[targetEnvironment] || {})
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = {
|
|
73
|
+
PlatformDeploymentService
|
|
74
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
const {
|
|
2
2
|
SQSClient,
|
|
3
3
|
SendMessageCommand,
|
|
4
4
|
DeleteMessageCommand,
|
|
5
5
|
ReceiveMessageCommand
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
} = require('@aws-sdk/client-sqs')
|
|
7
|
+
const { AwsCredentialsService } = require('../aws-credentials')
|
|
8
|
+
const { logInfo, logError, logDebug } = require('../log')
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
class DeploymentQueueService {
|
|
11
11
|
|
|
12
12
|
static sendDeploymentRequest(platformConfig, deploymentRequest) {
|
|
13
|
-
logInfo({ message: '[
|
|
14
|
-
return
|
|
13
|
+
logInfo({ message: '[DeploymentQueueService] Starting deployment sequence' })
|
|
14
|
+
return DeploymentQueueService.createAwsSqsClient(platformConfig)
|
|
15
15
|
.then(sqsClient => {
|
|
16
16
|
|
|
17
17
|
const sendMessageParams = {
|
|
@@ -19,19 +19,19 @@ export class DeploymentQueueClient {
|
|
|
19
19
|
MessageBody: JSON.stringify(deploymentRequest)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
logDebug({ message: '[
|
|
22
|
+
logDebug({ message: '[DeploymentQueueService] SendMessageCommand params', data: sendMessageParams })
|
|
23
23
|
const command = new SendMessageCommand(sendMessageParams)
|
|
24
24
|
|
|
25
25
|
return sqsClient.send(command)
|
|
26
|
-
.then(() => logInfo({ message: '[
|
|
27
|
-
.catch(error => logError({ message: '[
|
|
26
|
+
.then(() => logInfo({ message: '[DeploymentQueueService] Deployment request sent' }))
|
|
27
|
+
.catch(error => logError({ message: '[DeploymentQueueService] Could not send deployment request', error }))
|
|
28
28
|
})
|
|
29
29
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
static pollForDeploymentRequests(platformConfig, handleDeploymentRequest) {
|
|
33
|
-
logInfo({ message: '[
|
|
34
|
-
|
|
33
|
+
logInfo({ message: '[DeploymentQueueService] Starting polling for deployment requests' })
|
|
34
|
+
DeploymentQueueService.createAwsSqsClient(platformConfig).then(sqsClient => {
|
|
35
35
|
const FIVE_MINUTES = 3000
|
|
36
36
|
|
|
37
37
|
setInterval(() => {
|
|
@@ -41,7 +41,7 @@ export class DeploymentQueueClient {
|
|
|
41
41
|
sqsClient.send(receiveMessageCommand)
|
|
42
42
|
.then(data => data.Messages.map(message => {
|
|
43
43
|
|
|
44
|
-
logInfo({ message: '[
|
|
44
|
+
logInfo({ message: '[DeploymentQueueService] Received deployment request' })
|
|
45
45
|
|
|
46
46
|
handleDeploymentRequest(JSON.parse(message.Body))
|
|
47
47
|
.then(() => {
|
|
@@ -52,8 +52,8 @@ export class DeploymentQueueClient {
|
|
|
52
52
|
})
|
|
53
53
|
|
|
54
54
|
sqsClient.send(deleteMessageCommand)
|
|
55
|
-
.then(() => logInfo({ message: '[
|
|
56
|
-
.catch(error => logError({ message: '[
|
|
55
|
+
.then(() => logInfo({ message: '[DeploymentQueueService] Removing deployment request from queue' }))
|
|
56
|
+
.catch(error => logError({ message: '[DeploymentQueueService] Could not delete message from queue', error }))
|
|
57
57
|
})
|
|
58
58
|
|
|
59
59
|
}))
|
|
@@ -64,7 +64,7 @@ export class DeploymentQueueClient {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
static createAwsSqsClient(platformConfig) {
|
|
67
|
-
return
|
|
67
|
+
return AwsCredentialsService.resolveAwsCredentials(platformConfig)
|
|
68
68
|
.then(awsCredentials => new SQSClient({
|
|
69
69
|
region: platformConfig.awsRegion,
|
|
70
70
|
credentials: awsCredentials
|
|
@@ -72,3 +72,7 @@ export class DeploymentQueueClient {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
}
|
|
75
|
+
|
|
76
|
+
module.exports = {
|
|
77
|
+
DeploymentQueueService
|
|
78
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./deployment-queue')
|
package/src/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
const { PlatformTemplateService } = require('./template')
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
PlatformTemplateService
|
|
5
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-new */
|
|
3
|
+
const { App } = require('aws-cdk-lib')
|
|
4
|
+
|
|
5
|
+
const { PlatformStack } = require('./platform-stack')
|
|
6
|
+
const { EstablishTrustStack } = require('./establish-trust-stack')
|
|
7
|
+
|
|
8
|
+
const { PlatformTemplateService } = require('../template')
|
|
9
|
+
const { PlatformConfigService } = require('../config')
|
|
10
|
+
|
|
11
|
+
PlatformTemplateService
|
|
12
|
+
.readFromFile(process.env.PLATFORMS)
|
|
13
|
+
.then(templates => templates.map(PlatformConfigService.from))
|
|
14
|
+
.then(configs => {
|
|
15
|
+
|
|
16
|
+
const app = new App()
|
|
17
|
+
|
|
18
|
+
configs.forEach(config => {
|
|
19
|
+
const env = { account: config.awsAccountId, region: config.awsRegion }
|
|
20
|
+
|
|
21
|
+
new EstablishTrustStack(app, `${config.platformName}-establish-trust`, { config, env })
|
|
22
|
+
|
|
23
|
+
config.supportedEnvironments
|
|
24
|
+
.map(activeEnvironment => PlatformConfigService.from({ ...config, activeEnvironment }))
|
|
25
|
+
.forEach(config => {
|
|
26
|
+
new PlatformStack(app, `${config.platformName}-${config.activeEnvironment}`, { config, env })
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
})
|
|
30
|
+
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class AwsProfile {
|
|
2
|
+
|
|
3
|
+
static writeFile(roleArn, region) {
|
|
4
|
+
|
|
5
|
+
const awsProfileFile = `
|
|
6
|
+
[profile ci-client]
|
|
7
|
+
role_arn = ${roleArn}
|
|
8
|
+
credential_source = Ec2InstanceMetadata
|
|
9
|
+
region = ${region}
|
|
10
|
+
`
|
|
11
|
+
return [
|
|
12
|
+
'sudo mkdir /home/caddy',
|
|
13
|
+
'sudo mkdir /home/caddy/.aws',
|
|
14
|
+
`sudo echo "${awsProfileFile}" >> /home/caddy/.aws/credentials`
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = {
|
|
21
|
+
AwsProfile
|
|
22
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const systemdServiceFile = `
|
|
2
|
+
# caddy-api.service
|
|
3
|
+
#
|
|
4
|
+
# For using Caddy with its API.
|
|
5
|
+
#
|
|
6
|
+
# This unit is "durable" in that it will automatically resume
|
|
7
|
+
# the last active configuration if the service is restarted.
|
|
8
|
+
#
|
|
9
|
+
# See https://caddyserver.com/docs/install for instructions.
|
|
10
|
+
|
|
11
|
+
[Unit]
|
|
12
|
+
Description=Caddy
|
|
13
|
+
Documentation=https://caddyserver.com/docs/
|
|
14
|
+
After=network.target network-online.target
|
|
15
|
+
Requires=network-online.target
|
|
16
|
+
|
|
17
|
+
[Service]
|
|
18
|
+
Type=notify
|
|
19
|
+
User=caddy
|
|
20
|
+
Group=caddy
|
|
21
|
+
ExecStart=/usr/bin/caddy.route53 run --environ --resume
|
|
22
|
+
TimeoutStopSec=5s
|
|
23
|
+
LimitNOFILE=1048576
|
|
24
|
+
LimitNPROC=512
|
|
25
|
+
PrivateTmp=true
|
|
26
|
+
ProtectSystem=full
|
|
27
|
+
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
|
28
|
+
|
|
29
|
+
[Install]
|
|
30
|
+
WantedBy=multi-user.target cloud-init.target
|
|
31
|
+
`
|
|
32
|
+
|
|
33
|
+
class CaddyService {
|
|
34
|
+
|
|
35
|
+
static install() {
|
|
36
|
+
return [
|
|
37
|
+
`sudo echo "${systemdServiceFile}" >> /etc/systemd/system/caddy-route53.service`,
|
|
38
|
+
'sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https',
|
|
39
|
+
'sudo curl -1sLf \'https://dl.cloudsmith.io/public/caddy/stable/gpg.key\' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg',
|
|
40
|
+
'sudo curl -1sLf \'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt\' | sudo tee /etc/apt/sources.list.d/caddy-stable.list',
|
|
41
|
+
'sudo curl -1sLf \'https://dl.cloudsmith.io/public/caddy/xcaddy/gpg.key\' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-xcaddy-archive-keyring.gpg',
|
|
42
|
+
'sudo curl -1sLf \'https://dl.cloudsmith.io/public/caddy/xcaddy/debian.deb.txt\' | sudo tee /etc/apt/sources.list.d/caddy-xcaddy.list',
|
|
43
|
+
'sudo add-apt-repository ppa:longsleep/golang-backports -y',
|
|
44
|
+
'sudo apt update',
|
|
45
|
+
'sudo apt install caddy xcaddy golang-go -y',
|
|
46
|
+
'sudo xcaddy build --with github.com/caddy-dns/route53',
|
|
47
|
+
'sudo mv ./caddy /usr/bin/caddy.route53'
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static enable() {
|
|
52
|
+
return [
|
|
53
|
+
'sudo systemctl disable caddy.service',
|
|
54
|
+
'sudo systemctl enable caddy-route53.service'
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static start() {
|
|
59
|
+
return [
|
|
60
|
+
'sudo systemctl stop caddy.service',
|
|
61
|
+
'sudo systemctl start caddy-route53.service'
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = {
|
|
68
|
+
CaddyService
|
|
69
|
+
}
|