@ossy/deployment-tools 3.0.9 → 3.4.0

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 (33) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +156 -118
  3. package/jest.config.js +5 -0
  4. package/package.json +6 -4
  5. package/src/config/platform-config.js +16 -16
  6. package/src/ecs/platform-ecs-services.js +209 -0
  7. package/src/ecs/platform-ecs-services.spec.js +163 -0
  8. package/src/edge/platform-edge-domains.js +101 -0
  9. package/src/edge/platform-edge-domains.spec.js +87 -0
  10. package/src/index.js +45 -1
  11. package/src/infrastructure/dns-stack.js +47 -3
  12. package/src/infrastructure/dns-stack.spec.js +15 -0
  13. package/src/infrastructure/platform-ci-stack.js +151 -0
  14. package/src/infrastructure/platform-ecs-stack.js +349 -0
  15. package/src/infrastructure/platform-edge-stack.js +213 -0
  16. package/src/infrastructure/platform-secrets-stack.js +103 -0
  17. package/src/infrastructure/platform-stage.js +32 -5
  18. package/src/infrastructure/storage-static-stack.js +4 -5
  19. package/src/secrets/platform-secret-services.js +32 -0
  20. package/src/secrets/platform-secret-services.spec.js +40 -0
  21. package/src/secrets/sync-platform-secrets.js +136 -0
  22. package/src/services/platform-services.js +94 -0
  23. package/src/services/platform-services.spec.js +80 -0
  24. package/src/template/platform-template.js +5 -5
  25. package/src/infrastructure/container-deployment-target/aws-profile.js +0 -25
  26. package/src/infrastructure/container-deployment-target/caddy.service.js +0 -117
  27. package/src/infrastructure/container-deployment-target/container-deployment-target.js +0 -222
  28. package/src/infrastructure/container-deployment-target/container-service.js +0 -162
  29. package/src/infrastructure/container-deployment-target/index.js +0 -3
  30. package/src/infrastructure/container-deployment-target/ossy-api.service.js +0 -54
  31. package/src/infrastructure/container-deployment-target/ossy-runtime.service.js +0 -49
  32. package/src/infrastructure/container-deployment-target/user-data-commands.js +0 -31
  33. package/src/infrastructure/deployment-target-stack.js +0 -53
@@ -1,162 +0,0 @@
1
- /**
2
- * @typedef {'http'|'tcp'} ServiceType
3
- *
4
- * @typedef {Object} HttpServiceConfig
5
- * @property {'http'} [type] - defaults to 'http'
6
- * @property {string} name - unique name, used for container name and systemd unit
7
- * @property {string} domain - domain this service handles (Caddy block + Route53)
8
- * @property {string} image - Docker image to run
9
- *
10
- * @typedef {Object} TcpServiceConfig
11
- * @property {'tcp'} type - marks this as a raw TCP/UDP service (no HTTP/Caddy)
12
- * @property {string} name - unique name, used for container name and systemd unit
13
- * @property {string} image - Docker image to run
14
- * @property {number[]} ports - ports to expose directly (same inside and outside container)
15
- * @property {'tcp'|'udp'|'both'} [protocol] - defaults to 'tcp'
16
- *
17
- * @typedef {HttpServiceConfig|TcpServiceConfig} ContainerServiceConfig
18
- */
19
-
20
- const BASE_HTTP_PORT = 3002 // 3000 = platform runtime, 3001 = API
21
-
22
- // ---------------------------------------------------------------------------
23
- // HTTP service — reverse-proxied through Caddy, container listens on port 3000
24
- // ---------------------------------------------------------------------------
25
-
26
- class HttpContainerService {
27
- constructor({ name, domain, image }, httpIndex) {
28
- this.name = name
29
- this.domain = domain
30
- this.image = image
31
- this.hostPort = BASE_HTTP_PORT + httpIndex
32
- }
33
-
34
- get systemdUnitFile() {
35
- return `
36
- [Unit]
37
- Description=Container service: ${this.name} (${this.domain})
38
- After=network.target docker.service
39
- Requires=docker.service
40
-
41
- [Service]
42
- EnvironmentFile=/etc/environment
43
- ExecStartPre=-/usr/bin/docker rm -f ${this.name}
44
- ExecStartPre=/usr/bin/docker pull ${this.image}
45
- ExecStart=/usr/bin/docker run --name ${this.name} \\
46
- --network ossy-network \\
47
- -p ${this.hostPort}:3000 \\
48
- --env-file /etc/environment \\
49
- ${this.image}
50
- ExecStop=/usr/bin/docker stop ${this.name}
51
- Restart=on-failure
52
- RestartSec=5
53
-
54
- [Install]
55
- WantedBy=multi-user.target
56
- `
57
- }
58
-
59
- get caddyBlock() {
60
- return `
61
- ${this.domain} {
62
- tls {
63
- dns route53 {
64
- max_retries 10
65
- }
66
- }
67
- reverse_proxy localhost:${this.hostPort}
68
- }`
69
- }
70
-
71
- /** Ports to open in the EC2 security group. HTTP services use Caddy on 80/443 — no extra rules needed. */
72
- get securityGroupPorts() {
73
- return []
74
- }
75
-
76
- get unitName() { return `${this.name}.service` }
77
- install() { return [`sudo tee /etc/systemd/system/${this.unitName} > /dev/null << 'EOF'\n${this.systemdUnitFile}\nEOF`] }
78
- enable() { return [`sudo systemctl enable ${this.name}`] }
79
- start() { return [`sudo systemctl start ${this.name}`] }
80
- }
81
-
82
- // ---------------------------------------------------------------------------
83
- // TCP/UDP service — bypasses Caddy, ports exposed directly on the host.
84
- // Used for game servers and any other raw socket services.
85
- // ---------------------------------------------------------------------------
86
-
87
- class TcpContainerService {
88
- constructor({ name, image, ports, protocol = 'tcp' }) {
89
- this.name = name
90
- this.image = image
91
- this.ports = ports
92
- this.protocol = protocol // 'tcp' | 'udp' | 'both'
93
- }
94
-
95
- get systemdUnitFile() {
96
- const portMappings = this.ports.map(p => `-p ${p}:${p}`).join(' \\\n ')
97
- return `
98
- [Unit]
99
- Description=Container service: ${this.name} (${this.protocol.toUpperCase()} ${this.ports.join(', ')})
100
- After=network.target docker.service
101
- Requires=docker.service
102
-
103
- [Service]
104
- EnvironmentFile=/etc/environment
105
- ExecStartPre=-/usr/bin/docker rm -f ${this.name}
106
- ExecStartPre=/usr/bin/docker pull ${this.image}
107
- ExecStart=/usr/bin/docker run --name ${this.name} \\
108
- --network ossy-network \\
109
- ${portMappings} \\
110
- --env-file /etc/environment \\
111
- ${this.image}
112
- ExecStop=/usr/bin/docker stop ${this.name}
113
- Restart=on-failure
114
- RestartSec=5
115
-
116
- [Install]
117
- WantedBy=multi-user.target
118
- `
119
- }
120
-
121
- /** TCP services bypass Caddy — no Caddy block. */
122
- get caddyBlock() { return null }
123
-
124
- /** Each port needs an explicit security group ingress rule. */
125
- get securityGroupPorts() {
126
- return this.ports.flatMap(port => {
127
- if (this.protocol === 'both') return [{ port, protocol: 'tcp' }, { port, protocol: 'udp' }]
128
- return [{ port, protocol: this.protocol }]
129
- })
130
- }
131
-
132
- get unitName() { return `${this.name}.service` }
133
- install() { return [`sudo tee /etc/systemd/system/${this.unitName} > /dev/null << 'EOF'\n${this.systemdUnitFile}\nEOF`] }
134
- enable() { return [`sudo systemctl enable ${this.name}`] }
135
- start() { return [`sudo systemctl start ${this.name}`] }
136
- }
137
-
138
- // ---------------------------------------------------------------------------
139
- // Factory
140
- // ---------------------------------------------------------------------------
141
-
142
- /**
143
- * Build service instances from the `services` array in platforms.json.
144
- * HTTP services auto-assign host ports starting at 3002 (counted separately
145
- * from TCP services so reordering TCP entries doesn't shift HTTP ports).
146
- *
147
- * @param {ContainerServiceConfig[]} services
148
- * @returns {(HttpContainerService|TcpContainerService)[]}
149
- */
150
- const fromConfig = (services = []) => {
151
- let httpIndex = 0
152
- return services.map(s => {
153
- if (s.type === 'tcp') return new TcpContainerService(s)
154
- return new HttpContainerService(s, httpIndex++)
155
- })
156
- }
157
-
158
- module.exports = {
159
- HttpContainerService,
160
- TcpContainerService,
161
- fromConfig
162
- }
@@ -1,3 +0,0 @@
1
- const { ContainerDeploymentTarget } = require('./container-deployment-target')
2
-
3
- module.exports = { ContainerDeploymentTarget }
@@ -1,54 +0,0 @@
1
- const systemdServiceFile = `
2
- [Unit]
3
- Description=Ossy API
4
- After=network.target docker.service
5
- Requires=docker.service
6
-
7
- [Service]
8
- EnvironmentFile=/etc/environment
9
- ExecStartPre=-/usr/bin/docker rm -f ossy-api
10
- ExecStartPre=/usr/bin/docker pull ghcr.io/ossy-se/api:latest
11
- ExecStart=/usr/bin/docker run --name ossy-api \\
12
- --network ossy-network \\
13
- -p 3001:3000 \\
14
- -e DB_URL=\${DB_URL} \\
15
- -e DB_NAME=\${DB_NAME} \\
16
- -e TOKEN_SECRET=\${TOKEN_SECRET} \\
17
- -e MEDIA_REPOSITORY=\${MEDIA_REPOSITORY} \\
18
- -e MEDIA_CDN_DOMAIN_NAME=\${MEDIA_CDN_DOMAIN_NAME} \\
19
- -e AWS_ACCESS_KEY_ID=\${AWS_ACCESS_KEY_ID} \\
20
- -e AWS_SECRET_ACCESS_KEY=\${AWS_SECRET_ACCESS_KEY} \\
21
- ghcr.io/ossy-se/api:latest
22
- ExecStop=/usr/bin/docker stop ossy-api
23
- Restart=on-failure
24
- RestartSec=5
25
-
26
- [Install]
27
- WantedBy=multi-user.target
28
- `
29
-
30
- // The image is pulled automatically on every start via ExecStartPre, so the
31
- // service always runs the latest published version. To redeploy: systemctl restart ossy-api
32
-
33
- /**
34
- * @class
35
- */
36
- class OssyApiService {
37
-
38
- static install() {
39
- return [`sudo tee /etc/systemd/system/ossy-api.service > /dev/null << 'EOF'\n${systemdServiceFile}\nEOF`]
40
- }
41
-
42
- static enable() {
43
- return ['sudo systemctl enable ossy-api']
44
- }
45
-
46
- static start() {
47
- return ['sudo systemctl start ossy-api']
48
- }
49
-
50
- }
51
-
52
- module.exports = {
53
- OssyApiService
54
- }
@@ -1,49 +0,0 @@
1
- const systemdServiceFile = `
2
- [Unit]
3
- Description=Ossy Runtime
4
- After=network.target docker.service
5
- Requires=docker.service
6
-
7
- [Service]
8
- EnvironmentFile=/etc/environment
9
- ExecStartPre=-/usr/bin/docker rm -f ossy-runtime
10
- ExecStartPre=/usr/bin/docker pull ghcr.io/ossy-se/platform:latest
11
- ExecStart=/usr/bin/docker run --name ossy-runtime \\
12
- --network ossy-network \\
13
- -p 3000:3000 \\
14
- -e OSSY_API_KEY=\${OSSY_API_KEY} \\
15
- -e OSSY_API_URL=http://ossy-api:3001/api/v0 \\
16
- ghcr.io/ossy-se/platform:latest
17
- ExecStop=/usr/bin/docker stop ossy-runtime
18
- Restart=on-failure
19
- RestartSec=5
20
-
21
- [Install]
22
- WantedBy=multi-user.target
23
- `
24
-
25
- // The image is pulled automatically on every start via ExecStartPre, so the
26
- // service always runs the latest published version. To redeploy: systemctl restart ossy-runtime
27
-
28
- /**
29
- * @class
30
- */
31
- class OssyRuntimeService {
32
-
33
- static install() {
34
- return [`sudo tee /etc/systemd/system/ossy-runtime.service > /dev/null << 'EOF'\n${systemdServiceFile}\nEOF`]
35
- }
36
-
37
- static enable() {
38
- return ['sudo systemctl enable ossy-runtime']
39
- }
40
-
41
- static start() {
42
- return ['sudo systemctl start ossy-runtime']
43
- }
44
-
45
- }
46
-
47
- module.exports = {
48
- OssyRuntimeService
49
- }
@@ -1,31 +0,0 @@
1
- const getInstallDocker = () => [
2
- 'apt-get remove docker docker-engine docker.io containerd runc',
3
- `apt-get install \
4
- apt-transport-https \
5
- ca-certificates \
6
- curl \
7
- gnupg-agent \
8
- software-properties-common -y`,
9
- 'curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -',
10
- `sudo add-apt-repository \
11
- "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
12
- $(lsb_release -cs) \
13
- stable"`,
14
- 'sudo apt-get update',
15
- 'sudo apt-get install docker-ce docker-ce-cli containerd.io -y'
16
- ]
17
-
18
- const getInstallNodeJs = () => [
19
- 'curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -',
20
- 'sudo apt-get -y install nodejs'
21
- ]
22
-
23
- const getInstallNpm = () => [
24
- 'sudo apt install npm'
25
- ]
26
-
27
- module.exports = {
28
- getInstallDocker,
29
- getInstallNodeJs,
30
- getInstallNpm
31
- }
@@ -1,53 +0,0 @@
1
- /* eslint-disable no-new */
2
- const { CfnOutput, Stack } = require('aws-cdk-lib')
3
- const { ContainerDeploymentTarget } = require('./container-deployment-target')
4
-
5
- /**
6
- * DeploymentTargetStackProps
7
- * @typedef {Object} DeploymentTargetStackProps
8
- * @property {PlatformConfig} config - platform config
9
- * @property {import('aws-cdk-lib/aws-s3').IBucket} bucket - static assets bucket (from StorageStaticStack)
10
- * @property {string} cdnDomainName - CloudFront domain name (from StorageStaticStack)
11
- */
12
-
13
- /**
14
- * DeploymentTargetStack provisions the EC2 instance (with Elastic IP) that runs the
15
- * platform services. The S3 bucket lives in StorageStaticStack so that EC2 replacements
16
- * never trigger CloudFormation cross-stack export conflicts on storage resources.
17
- *
18
- * MEDIA_REPOSITORY and MEDIA_CDN_DOMAIN_NAME are derived from the actual bucket and CDN
19
- * resources rather than being hardcoded in platforms.json.
20
- */
21
- class DeploymentTargetStack extends Stack {
22
- constructor(scope, id, props) {
23
- super(scope, id, props)
24
-
25
- if (!props?.config) {
26
- throw ('[DeploymentTargetStack] No config provided')
27
- }
28
-
29
- const containerDeploymentTarget = new ContainerDeploymentTarget(this, 'ContainerDeploymentTarget', {
30
- config: {
31
- ...props.config,
32
- env: {
33
- ...props.config.env,
34
- MEDIA_REPOSITORY: props.bucket.bucketName,
35
- MEDIA_CDN_DOMAIN_NAME: `https://${props.cdnDomainName}`
36
- }
37
- },
38
- bucket: props.bucket
39
- })
40
-
41
- this.containerDeploymentTargetPublicIp = containerDeploymentTarget.instancePublicIp
42
-
43
- new CfnOutput(this, 'ContainerDeploymentTargetPublicIp', {
44
- value: containerDeploymentTarget.instancePublicIp,
45
- description: 'Public IP of the EC2 instance (Elastic IP)',
46
- exportName: `${props.config.platformName}-ContainerDeploymentTargetPublicIp`
47
- })
48
- }
49
- }
50
-
51
- module.exports = {
52
- DeploymentTargetStack
53
- }