Skip to content

Commit cd8b582

Browse files
committed
👷 refactor deployment scripts to remove hardcoded list of DCs and sites
1 parent 247005e commit cd8b582

File tree

7 files changed

+114
-47
lines changed

7 files changed

+114
-47
lines changed

‎.gitlab/deploy-auto.yml‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ stages:
1717
- VERSION=$(node -p -e "require('./lerna.json').version")
1818
- yarn
1919
- yarn build:bundle
20-
- node ./scripts/deploy/deploy-prod-dc.ts v${VERSION%%.*} $UPLOAD_PATH --check-monitors
20+
- node ./scripts/deploy/deploy-prod-dc.ts v${VERSION%%.*} $DATACENTER --check-monitors
2121

2222
step-1_deploy-prod-minor-dcs:
2323
when: manual
@@ -26,7 +26,7 @@ step-1_deploy-prod-minor-dcs:
2626
- .base-configuration
2727
- .deploy-prod
2828
variables:
29-
UPLOAD_PATH: minor-dcs
29+
DATACENTER: minor-dcs
3030

3131
step-2_deploy-prod-eu1:
3232
needs:
@@ -35,7 +35,7 @@ step-2_deploy-prod-eu1:
3535
- .base-configuration
3636
- .deploy-prod
3737
variables:
38-
UPLOAD_PATH: eu1
38+
DATACENTER: eu1
3939

4040
step-3_deploy-prod-us1:
4141
needs:
@@ -44,7 +44,7 @@ step-3_deploy-prod-us1:
4444
- .base-configuration
4545
- .deploy-prod
4646
variables:
47-
UPLOAD_PATH: us1
47+
DATACENTER: us1
4848

4949
step-4_deploy-prod-gov:
5050
needs:
@@ -53,7 +53,7 @@ step-4_deploy-prod-gov:
5353
- .base-configuration
5454
- .deploy-prod
5555
variables:
56-
UPLOAD_PATH: root
56+
DATACENTER: gov
5757

5858
step-5_publish-npm:
5959
needs:

‎.gitlab/deploy-manual.yml‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,35 @@ stages:
1919
- VERSION=$(node -p -e "require('./lerna.json').version")
2020
- yarn
2121
- yarn build:bundle
22-
- node ./scripts/deploy/deploy-prod-dc.ts v${VERSION%%.*} $UPLOAD_PATH --no-check-monitors
22+
- node ./scripts/deploy/deploy-prod-dc.ts v${VERSION%%.*} $DATACENTER --no-check-monitors
2323

2424
step-1_deploy-prod-minor-dcs:
2525
extends:
2626
- .base-configuration
2727
- .deploy-prod
2828
variables:
29-
UPLOAD_PATH: minor-dcs
29+
DATACENTER: minor-dcs
3030

3131
step-2_deploy-prod-eu1:
3232
extends:
3333
- .base-configuration
3434
- .deploy-prod
3535
variables:
36-
UPLOAD_PATH: eu1
36+
DATACENTER: eu1
3737

3838
step-3_deploy-prod-us1:
3939
extends:
4040
- .base-configuration
4141
- .deploy-prod
4242
variables:
43-
UPLOAD_PATH: us1
43+
DATACENTER: us1
4444

4545
step-4_deploy-prod-gov:
4646
extends:
4747
- .base-configuration
4848
- .deploy-prod
4949
variables:
50-
UPLOAD_PATH: root
50+
DATACENTER: root
5151

5252
step-5_publish-npm:
5353
stage: deploy
@@ -80,7 +80,7 @@ step-7_create-github-release:
8080
- node scripts/release/create-github-release.ts
8181

8282
# This step is used to deploy the SDK to a new datacenter.
83-
# the `UPLOAD_PATH` variable needs to be provided as an argument when starting the manual job
83+
# the `DATACENTER` variable needs to be provided as an argument when starting the manual job
8484
optional_step-deploy-to-new-datacenter:
8585
extends:
8686
- .base-configuration

‎scripts/deploy/check-monitors.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
*/
66
import { printLog, runMain, fetchHandlingError } from '../lib/executionUtils.ts'
77
import { getTelemetryOrgApiKey, getTelemetryOrgApplicationKey } from '../lib/secrets.ts'
8-
import { siteByDatacenter } from '../lib/datacenter.ts'
8+
import { getSite } from '../lib/datacenter.ts'
99
import { browserSdkVersion } from '../lib/browserSdkVersion.ts'
1010

1111
const datacenters = process.argv[2].split(',')
1212

1313
runMain(async () => {
1414
for (const datacenter of datacenters) {
15-
const site = siteByDatacenter[datacenter]
15+
const site = getSite(datacenter)
1616
const apiKey = getTelemetryOrgApiKey(site)
1717
const applicationKey = getTelemetryOrgApplicationKey(site)
1818

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { parseArgs } from 'node:util'
22
import { printLog, runMain, timeout } from '../lib/executionUtils.ts'
33
import { command } from '../lib/command.ts'
4-
import { siteByDatacenter } from '../lib/datacenter.ts'
4+
import { getAllMinorDcs, getAllPrivateDcs } from '../lib/datacenter.ts'
55

66
/**
77
* Orchestrate the deployments of the artifacts for specific DCs
@@ -12,15 +12,6 @@ const ONE_MINUTE_IN_SECOND = 60
1212
const GATE_DURATION = 30 * ONE_MINUTE_IN_SECOND
1313
const GATE_INTERVAL = ONE_MINUTE_IN_SECOND
1414

15-
// Major DCs are the ones that are deployed last.
16-
// They have their own step jobs in `deploy-manual.yml` and `deploy-auto.yml`.
17-
const MAJOR_DCS = ['root', 'us1', 'eu1']
18-
19-
// Minor DCs are all the DCs from `siteByDatacenter` that are not in `MAJOR_DCS`.
20-
function getAllMinorDcs(): string[] {
21-
return Object.keys(siteByDatacenter).filter((dc) => !MAJOR_DCS.includes(dc))
22-
}
23-
2415
if (!process.env.NODE_TEST_CONTEXT) {
2516
runMain(() => main(...process.argv.slice(2)))
2617
}
@@ -42,30 +33,56 @@ export async function main(...args: string[]): Promise<void> {
4233
})
4334

4435
const version = positionals[0]
45-
const uploadPath = positionals[1] === 'minor-dcs' ? getAllMinorDcs().join(',') : positionals[1]
36+
const datacenters = getDatacenters(positionals[1])
4637

47-
if (!uploadPath) {
48-
throw new Error('UPLOAD_PATH argument is required')
38+
if (!datacenters) {
39+
throw new Error('DATACENTER argument is required')
4940
}
5041

5142
if (checkMonitors) {
52-
command`node ./scripts/deploy/check-monitors.ts ${uploadPath}`.withLogs().run()
43+
command`node ./scripts/deploy/check-monitors.ts ${datacenters.join(',')}`.withLogs().run()
5344
}
5445

55-
command`node ./scripts/deploy/deploy.ts prod ${version} ${uploadPath}`.withLogs().run()
56-
command`node ./scripts/deploy/upload-source-maps.ts ${version} ${uploadPath}`.withLogs().run()
46+
const uploadPathTypes = toDatacenterUploadPathType(datacenters).join(',')
5747

58-
if (checkMonitors && uploadPath !== 'root') {
59-
await gateMonitors(uploadPath)
48+
command`node ./scripts/deploy/deploy.ts prod ${version} ${uploadPathTypes}`.withLogs().run()
49+
command`node ./scripts/deploy/upload-source-maps.ts ${version} ${uploadPathTypes}`.withLogs().run()
50+
51+
if (checkMonitors) {
52+
await gateMonitors(datacenters)
6053
}
6154
}
6255

63-
async function gateMonitors(uploadPath: string): Promise<void> {
64-
printLog(`Check monitors for ${uploadPath} during ${GATE_DURATION / ONE_MINUTE_IN_SECOND} minutes`)
56+
async function gateMonitors(datacenters: string[]): Promise<void> {
57+
printLog(`Check monitors for ${datacenters.join(',')} during ${GATE_DURATION / ONE_MINUTE_IN_SECOND} minutes`)
58+
6559
for (let i = 0; i < GATE_DURATION; i += GATE_INTERVAL) {
66-
command`node ./scripts/deploy/check-monitors.ts ${uploadPath}`.run()
60+
command`node ./scripts/deploy/check-monitors.ts ${datacenters.join(',')}`.run()
6761
process.stdout.write('.') // progress indicator
6862
await timeout(GATE_INTERVAL * 1000)
6963
}
64+
7065
printLog() // new line
7166
}
67+
68+
function getDatacenters(datacenterGroup: string): string[] {
69+
if (datacenterGroup === 'minor-dcs') {
70+
return getAllMinorDcs()
71+
}
72+
73+
if (datacenterGroup === 'private-regions') {
74+
return getAllPrivateDcs()
75+
}
76+
77+
return datacenterGroup.split(',')
78+
}
79+
80+
function toDatacenterUploadPathType(datacenters: string[]): string[] {
81+
return datacenters.map((datacenter) => {
82+
if (datacenter === 'gov') {
83+
return 'root'
84+
}
85+
86+
return datacenter
87+
})
88+
}

‎scripts/deploy/upload-source-maps.spec.ts‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
import assert from 'node:assert/strict'
22
import path from 'node:path'
33
import { beforeEach, before, describe, it, mock } from 'node:test'
4-
import { siteByDatacenter } from '../lib/datacenter.ts'
54
import { mockModule, mockCommandImplementation, replaceChunkHashes } from './lib/testHelpers.ts'
65

6+
const MOCK_SITES = [
7+
'us1.datadoghq.com',
8+
'eu1.datadoghq.eu',
9+
'us3.datadoghq.com',
10+
'us5.datadoghq.com',
11+
'ap1.datadoghq.com',
12+
'ap2.datadoghq.com',
13+
]
714
const FAKE_API_KEY = 'FAKE_API_KEY'
815
const ENV_STAGING = {
916
DATADOG_API_KEY: FAKE_API_KEY,
@@ -50,7 +57,7 @@ describe('upload-source-maps', () => {
5057
})
5158

5259
function forEachDatacenter(callback: (site: string) => void): void {
53-
for (const site of Object.values(siteByDatacenter)) {
60+
for (const site of MOCK_SITES) {
5461
callback(site)
5562
}
5663
}

‎scripts/deploy/upload-source-maps.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { printLog, runMain } from '../lib/executionUtils.ts'
33
import { command } from '../lib/command.ts'
44
import { getBuildEnvValue } from '../lib/buildEnv.ts'
55
import { getTelemetryOrgApiKey } from '../lib/secrets.ts'
6-
import { siteByDatacenter } from '../lib/datacenter.ts'
6+
import { getSite, getAllDatacenters } from '../lib/datacenter.ts'
77
import { forEachFile } from '../lib/filesUtils.ts'
88
import { buildRootUploadPath, buildDatacenterUploadPath, buildBundleFolder, packages } from './lib/deploymentUtils.ts'
99

@@ -20,7 +20,8 @@ function getSitesByVersion(version: string): string[] {
2020
case 'canary':
2121
return ['datadoghq.com']
2222
default:
23-
return Object.values(siteByDatacenter)
23+
// TODO: do we upload to root for all DCs?
24+
return getAllDatacenters().map(getSite)
2425
}
2526
}
2627

@@ -56,7 +57,7 @@ async function uploadSourceMaps(
5657
uploadPath = buildRootUploadPath(packageName, version)
5758
await renameFilesWithVersionSuffix(bundleFolder, version)
5859
} else {
59-
sites = [siteByDatacenter[uploadPathType]]
60+
sites = [getSite(uploadPathType)]
6061
uploadPath = buildDatacenterUploadPath(uploadPathType, packageName, version)
6162
}
6263
const prefix = path.dirname(`/${uploadPath}`)

‎scripts/lib/datacenter.ts‎

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,51 @@
1-
export const siteByDatacenter: Record<string, string> = {
2-
us1: 'datadoghq.com',
3-
eu1: 'datadoghq.eu',
4-
us3: 'us3.datadoghq.com',
5-
us5: 'us5.datadoghq.com',
6-
ap1: 'ap1.datadoghq.com',
7-
ap2: 'ap2.datadoghq.com',
8-
prtest00: 'prtest00.datad0g.com',
1+
import { command } from './command.ts'
2+
3+
// Major DCs are the ones that are deployed last.
4+
// They have their own step jobs in `deploy-manual.yml` and `deploy-auto.yml`.
5+
const MAJOR_DCS = ['gov', 'us1', 'eu1']
6+
7+
export function getSite(datacenter: string): string {
8+
return getAllDatacentersMetadata()[datacenter].site
9+
}
10+
11+
export function getAllDatacenters(): string[] {
12+
return Object.keys(getAllDatacentersMetadata())
13+
}
14+
15+
export function getAllMinorDcs(): string[] {
16+
return getAllDatacenters().filter((dc) => !MAJOR_DCS.includes(dc) && !dc.startsWith('pr'))
17+
}
18+
19+
export function getAllPrivateDcs(): string[] {
20+
return getAllDatacenters().filter((dc) => dc.startsWith('pr'))
21+
}
22+
23+
interface Datacenter {
24+
name: string
25+
site: string
26+
}
27+
28+
let cachedDatacenters: Record<string, Datacenter> | undefined
29+
30+
function getAllDatacentersMetadata(): Record<string, Datacenter> {
31+
if (cachedDatacenters) {
32+
return cachedDatacenters
33+
}
34+
35+
const selector = 'datacenter.environment == "prod" && datacenter.flavor == "site"'
36+
const rawDatacenters = command`ddtool datacenters list --selector ${selector}`.run().trim()
37+
const jsonDatacenters = JSON.parse(rawDatacenters) as Datacenter[]
38+
39+
cachedDatacenters = {}
40+
41+
for (const datacenter of jsonDatacenters) {
42+
const shortName = datacenter.name.split('.')[0]
43+
44+
cachedDatacenters[shortName] = {
45+
name: datacenter.name,
46+
site: datacenter.site,
47+
}
48+
}
49+
50+
return cachedDatacenters
951
}

0 commit comments

Comments
 (0)