@ossy/deployment-tools 0.0.24 → 0.0.26

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.
@@ -1,24 +0,0 @@
1
- import * as core from '@actions/core'
2
- import { STSClient, AssumeRoleWithWebIdentityCommand } from '@aws-sdk/client-sts'
3
-
4
- export class AwsCredentialsClient {
5
-
6
- static getTemporaryCredentials(awsAccountId, region, roleToAssume = 'github-ci-role') {
7
- const stsClient = new STSClient({ region })
8
-
9
- return core.getIDToken('sts.amazonaws.com')
10
- .then(webIdentityToken => stsClient.send(new AssumeRoleWithWebIdentityCommand({
11
- RoleArn: `arn:aws:iam::${awsAccountId}:role/${roleToAssume}`,
12
- RoleSessionName: 'GitHubActions',
13
- DurationSeconds: 15 * 60,
14
- WebIdentityToken: webIdentityToken
15
- })))
16
- .then(responseData => ({
17
- accessKeyId: responseData.Credentials.AccessKeyId,
18
- secretAccessKey: responseData.Credentials.SecretAccessKey,
19
- sessionToken: responseData.Credentials.SessionToken
20
- }))
21
-
22
- }
23
-
24
- }
package/src/config.js DELETED
@@ -1,9 +0,0 @@
1
- export const platformName = process.env.DEPLOYMENT_TOOLS_PLATFORM_NAME
2
- export const domain = process.env.DEPLOYMENT_TOOLS_DOMAIN || 'localhost'
3
- export const environmentName = process.env.DEPLOYMENT_TOOLS_ENVIRONMENT_NAME || 'dev'
4
- export const ciSubDomain = process.env.DEPLOYMENT_TOOLS_CI_SUB_DOMAIN || 'ci'
5
- export const port = process.env.DEPLOYMENT_TOOLS_PORT || 3000
6
- export const awsAccountId = process.env.AWS_ACCOUNT_ID
7
- export const awsRegion = process.env.AWS_REGION
8
-
9
- export const deploymentQueueUrl = `https://sqs.${awsRegion}.amazonaws.com/${awsAccountId}/${platformName}-${environmentName}`
@@ -1,118 +0,0 @@
1
- import { resolve } from 'path'
2
- import { readFileSync } from 'fs'
3
- import { AwsCredentialsClient } from './aws-credentials-client.js'
4
- import { DeploymentQueueClient } from './deployment-queue-client.js'
5
-
6
- export class ContainerManagerClient {
7
-
8
- //eslint-disable-next-line max-params
9
- static deploy(
10
- username,
11
- authentication,
12
- targetEnvironment = 'local-dev',
13
- pathToDeploymentPlatforms,
14
- pathToOssyFile
15
- ) {
16
- const containerManagerClient = new ContainerManagerClient()
17
- return containerManagerClient.deploy(
18
- username,
19
- authentication,
20
- targetEnvironment,
21
- pathToDeploymentPlatforms,
22
- pathToOssyFile
23
- )
24
- }
25
-
26
- constructor() {}
27
-
28
- getDeployments(pathToOssyFile) {
29
- const ossyfile = JSON.parse(readFileSync(resolve(pathToOssyFile), 'utf8'))
30
- return Promise.resolve(ossyfile.deployments || [])
31
- }
32
-
33
- getDeploymentPlatforms(pathToDeploymentPlatforms) {
34
-
35
- const localDevPlatform = {
36
- name: 'dev',
37
- domain: 'localhost',
38
- supportedDeploymentTypes: ['CONTAINER']
39
- }
40
-
41
- if (!pathToDeploymentPlatforms) return [localDevPlatform]
42
-
43
- const deploymentPlatforms = JSON.parse(readFileSync(resolve(pathToDeploymentPlatforms), 'utf8'))
44
- return Promise.resolve(deploymentPlatforms || [localDevPlatform])
45
- }
46
-
47
- getDeploymentTargetURL(targetEnvironment, deploymentPlatform, deployment) {
48
- let domain = targetEnvironment !== 'prod'
49
- ? `${targetEnvironment}.`
50
- : ''
51
-
52
- domain = deployment.subdomain
53
- ? `${domain}${deployment.subdomain}.${deploymentPlatform.domain}`
54
- : `${domain}${deploymentPlatform.domain}`
55
-
56
- return domain
57
- }
58
-
59
- getEnvironmentVariables(targetEnvironment, deployment) {
60
- const envs = deployment.env || {}
61
- return {
62
- ...(envs.shared || {}),
63
- ...(envs[targetEnvironment] || {})
64
- }
65
- }
66
-
67
- //eslint-disable-next-line max-params
68
- deploy(
69
- username,
70
- authentication,
71
- targetEnvironment,
72
- pathToDeploymentPlatforms,
73
- pathToOssyFile
74
- ) {
75
- console.log('pathToDeploymentPlatforms', pathToDeploymentPlatforms)
76
- console.log('pathToOssyFile', pathToOssyFile)
77
- console.log('pathToOssyFile resolved', resolve(pathToOssyFile))
78
- return Promise.all([
79
- this.getDeploymentPlatforms(pathToDeploymentPlatforms),
80
- this.getDeployments(pathToOssyFile)
81
- ])
82
- .then(([platforms, deployments]) => {
83
- deployments.map(deployment => {
84
- const platform = platforms.find(platform => platform.name === deployment.targetDeploymentPlatform)
85
-
86
- if (!platform) {
87
- return Promise.reject(
88
- `Could not find a deployment platform with the name ${deployment.targetDeploymentPlatform}`
89
- )
90
- }
91
-
92
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0
93
-
94
- const body = {
95
- image: deployment.image,
96
- hostPort: deployment.hostPort,
97
- containerPort: deployment.containerPort,
98
- domain: this.getDeploymentTargetURL(targetEnvironment, platform, deployment),
99
- env: this.getEnvironmentVariables(targetEnvironment, deployment),
100
- registry: deployment.registry,
101
- username: username,
102
- authentication: authentication
103
- }
104
-
105
- return AwsCredentialsClient.getTemporaryCredentials(platform.awsAccountId, platform.awsRegion)
106
- .then(credentials => {
107
- const deploymentQueueClient = DeploymentQueueClient.new({ credentials })
108
- return deploymentQueueClient.sendMessage(body)
109
- .then(() => console.log('[ContainerManagerCommands] Deployment request has been sent'))
110
- .catch(error => console.log('[ContainerManagerCommands] Could not send deployment request', error))
111
-
112
- })
113
- })
114
- })
115
- .catch(error => console.log(error))
116
- }
117
-
118
- }
@@ -1,89 +0,0 @@
1
- import express from 'express'
2
- import { CaddyClient } from './caddy-client.js'
3
- import { DockerClient } from './docker-client.js'
4
- import { DeploymentQueueClient } from './deployment-queue-client.js'
5
- import * as config from './config.js'
6
-
7
- export class ContainerManagerServer {
8
-
9
- static start() {
10
- return new ContainerManagerServer()
11
- }
12
-
13
- constructor() {
14
- this.server = express()
15
- this.dockerClient = DockerClient.new()
16
- this.caddyClient = CaddyClient.new()
17
- this.deploymentQueueClient = DeploymentQueueClient.new()
18
-
19
- this.applyDefaultCaddyConfig()
20
- this.setupServerEndpoints()
21
- this.pollForDeploymentRequests()
22
- }
23
-
24
- setupServerEndpoints() {
25
- this.server.use(express.json())
26
-
27
- this.server.get('/', (req, res) => {
28
- res.redirect('/status')
29
- })
30
-
31
- this.server.get('/status', (req, res) => {
32
- res.json('Server is live')
33
- })
34
-
35
- this.server.listen(config.port, () => {
36
- console.log(`Web API is live on port ${config.port}`)
37
- })
38
- }
39
-
40
- applyDefaultCaddyConfig() {
41
- this.caddyClient.applyDefaultServerConfig()
42
- .then(() => this.caddyClient.deploy({
43
- domain: `${config.ciSubDomain}.${config.environmentName}.${config.domain}`,
44
- targetPort: config.port
45
- }))
46
- }
47
-
48
- pollForDeploymentRequests() {
49
- const FIVE_MINUTES = 3000
50
-
51
- const handleIcomingMessages = () => this.deploymentQueueClient.receiveMessages()
52
- .then(data => data.Messages.map(message => {
53
- console.log('[ContainerManagerServer] handleIcomingMessages')
54
- this.deploy(message)
55
- this.deploymentQueueClient.deleteMessage(message.ReceiptHandle)
56
- }))
57
- .catch(error => console.log('[ContainerManagerServer] handleIcomingMessages error', error))
58
-
59
- setInterval(handleIcomingMessages, FIVE_MINUTES)
60
- }
61
-
62
- deploy(deploymentRequestMessage) {
63
-
64
- const {
65
- registry,
66
- username,
67
- authentication,
68
- containerPort,
69
- hostPort,
70
- image,
71
- domain,
72
- env
73
- } = deploymentRequestMessage
74
-
75
- this.dockerClient.deploy({
76
- image,
77
- registry,
78
- username,
79
- authentication,
80
- containerPort,
81
- hostPort,
82
- env
83
- })
84
-
85
- domain && this.caddyClient.deploy({ domain, targetPort: hostPort })
86
-
87
- }
88
-
89
- }
@@ -1,57 +0,0 @@
1
- import {
2
- SQSClient,
3
- SendMessageCommand,
4
- DeleteMessageCommand,
5
- ReceiveMessageCommand
6
- } from '@aws-sdk/client-sqs'
7
- import * as config from './config.js'
8
-
9
- export class DeploymentQueueClient {
10
-
11
- static new({ queueUrl, region, credentials } = {}) {
12
-
13
- const deploymentQueueClientDefaultConfig = {
14
- queueUrl: queueUrl || config.deploymentQueueUrl,
15
- region: region || config.awsRegion,
16
- credentials
17
- }
18
-
19
- return new DeploymentQueueClient(deploymentQueueClientDefaultConfig)
20
- }
21
-
22
- constructor({ queueUrl, region, credentials }) {
23
- this.queueUrl = queueUrl
24
- this.sqs = new SQSClient({ region, credentials })
25
- }
26
-
27
- sendMessage(messageBody) {
28
- const command = new SendMessageCommand({
29
- QueueUrl: this.queueUrl,
30
- MessageBody: JSON.stringify(messageBody)
31
- })
32
-
33
- return this.sqs.send(command)
34
- .then(() => console.log('Success'))
35
- .catch(err => console.log(err))
36
- }
37
-
38
- receiveMessages() {
39
- const command = new ReceiveMessageCommand({ QueueUrl: this.queueUrl })
40
-
41
- return this.sqs.send(command)
42
- .catch(error => console.log('Error', error))
43
- }
44
-
45
- deleteMessage(receiptHandle) {
46
- const command = new DeleteMessageCommand({
47
- QueueUrl: this.queueUrl,
48
- ReceiptHandle: receiptHandle
49
- })
50
-
51
- return this.sqs.send(command)
52
- .then(() => console.log('success'))
53
- .catch(error => console.log('Error', error))
54
-
55
- }
56
-
57
- }
@@ -1,80 +0,0 @@
1
- import { exec } from 'child_process'
2
- import fs from 'fs'
3
- import { nanoid } from 'nanoid'
4
- import path from 'path'
5
- import { fileURLToPath } from 'url'
6
-
7
- const __filename = fileURLToPath(import.meta.url)
8
- const __dirname = path.dirname(__filename)
9
-
10
- export class DockerClient {
11
-
12
- static new() {
13
- return new DockerClient()
14
- }
15
-
16
- constructor() {
17
- this.networkName = 'deployment-tools'
18
- exec(`sudo docker network create ${this.networkName}`)
19
- }
20
-
21
- stopContainer({ image }) {
22
- const name = image.replaceAll('/', '_')
23
- return `sudo docker stop ${name} ||`
24
- }
25
-
26
- startContainer({ image, containerPort, hostPort, registry, env }) {
27
- const name = image.replaceAll('/', '_')
28
- const imageUrl = !!registry ? `${registry}/${image}` : image
29
- const envsAsString = Object.entries(env || {}).reduce((envs, [name, value]) => `${envs} --env ${name}=${value}`, '')
30
- return `sudo docker run -d -p ${hostPort}:${containerPort} --name=${name} --network=${this.networkName} --network-alias=${name} --rm ${envsAsString} ${imageUrl}`
31
- }
32
-
33
- resolveCredentials({ registry, username, authentication }) {
34
- return (username || authentication)
35
- ? `sudo docker login ${registry} -u ${username} -p ${authentication}`
36
- : 'echo No credentials provided, assuming image is publicly hosted'
37
- }
38
-
39
- deploy({
40
- image,
41
- registry,
42
- username,
43
- authentication,
44
- containerPort,
45
- hostPort,
46
- env
47
- }) {
48
- return new Promise(resolve => {
49
- const dockerCommandScript = `'#!/bin/bash'
50
- ${this.stopContainer({ image })}
51
- ${this.resolveCredentials({ registry, username, authentication })}
52
- ${this.startContainer({ image, containerPort, hostPort, registry, env })}`
53
-
54
- const deploymentId = nanoid()
55
-
56
- const FilePaths = {
57
- DeploymentScript: `${__dirname}/${deploymentId}.sh`
58
- }
59
-
60
- fs.writeFileSync(FilePaths.DeploymentScript, dockerCommandScript)
61
- const command = exec(`bash ${FilePaths.DeploymentScript}`)
62
-
63
- command.stdout.on('data', (data) => {
64
- console.log(`[DockerClient]: ${data}`)
65
- })
66
-
67
- command.stderr.on('data', (data) => {
68
- console.error(`[DockerClient]: ${data}`)
69
- })
70
-
71
- command.on('close', (code) => {
72
- console.log(`[DockerClient] command exited with code ${code}`)
73
- fs.unlinkSync(FilePaths.DeploymentScript)
74
- resolve()
75
- })
76
- })
77
-
78
- }
79
-
80
- }
package/src/index.js DELETED
@@ -1,79 +0,0 @@
1
- #!/usr/bin/env node
2
- import { platform } from 'os'
3
- import { exec } from 'child_process'
4
- import arg from 'arg'
5
- import { ContainerManagerServer } from './container-manager-server.js'
6
- import { ContainerManagerClient } from './container-manager-client.js'
7
-
8
- const [_, __, command, ...restArgs] = process.argv
9
-
10
- const startHandler = () => {
11
- console.log('Running start command')
12
-
13
- const Platforms = {
14
- windows: 'win32',
15
- mac: 'darwin'
16
- }
17
-
18
- if ([Platforms.windows].includes(platform())) {
19
- return console.error('Deployment tools do not support this os')
20
- }
21
-
22
- ContainerManagerServer.start()
23
- }
24
-
25
- const stopHandler = () => {
26
- console.log('Running stop command')
27
- exec('systemctl stop deployment-tools.service')
28
- }
29
-
30
- const statusHandler = () => {
31
- console.log('Running status command')
32
- exec('systemctl status deployment-tools.service')
33
- }
34
-
35
- const deployHandler = () => {
36
- console.log('Running deploy command')
37
-
38
- const args = arg({
39
- '--username': String,
40
- '-u': '--username',
41
-
42
- '--authentication': String,
43
- '--a': '--authentication',
44
-
45
- '--target-env': String,
46
- '-t': '--target-env',
47
-
48
- '--ossyfile': String,
49
- '-o': '--ossyfile',
50
-
51
- '--platforms': String,
52
- '-p': '--platforms'
53
- }, { argv: restArgs })
54
-
55
- console.log('args', args)
56
-
57
- ContainerManagerClient.deploy(
58
- args['--username'],
59
- args['--authentication'],
60
- args['--target-env'],
61
- args['--platforms'],
62
- args['--ossyfile']
63
- )
64
- }
65
-
66
- const Commands = {
67
- start: startHandler,
68
- stop: stopHandler,
69
- status: statusHandler,
70
- deploy: deployHandler
71
- }
72
-
73
- const commandHandler = Commands[command]
74
-
75
- if (!commandHandler) {
76
- console.log('Command not implemented, did you spell it correctly?')
77
- }
78
-
79
- commandHandler()