@metaplay/metaplay-auth 1.6.0 → 1.6.1
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/CHANGELOG.md +10 -0
- package/dist/index.cjs +135 -135
- package/index.ts +33 -80
- package/package.json +3 -6
- package/src/auth.ts +9 -15
- package/src/buildCommand.ts +13 -23
- package/src/deployment.ts +7 -5
- package/src/secret_store.ts +3 -2
- package/src/targetenvironment.ts +5 -5
- package/src/utils.ts +3 -2
- package/src/version.ts +1 -1
- package/.prettierignore +0 -2
- package/prettier.config.js +0 -3
package/index.ts
CHANGED
|
@@ -1,35 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander'
|
|
3
|
+
import { randomBytes } from 'crypto'
|
|
3
4
|
import Docker from 'dockerode'
|
|
5
|
+
import { existsSync } from 'fs'
|
|
6
|
+
import { writeFile, unlink } from 'fs/promises'
|
|
7
|
+
import { tmpdir } from 'os'
|
|
8
|
+
import { exit } from 'process'
|
|
9
|
+
import * as semver from 'semver'
|
|
10
|
+
|
|
11
|
+
import { KubeConfig } from '@kubernetes/client-node'
|
|
12
|
+
|
|
13
|
+
import { loginAndSaveTokens, machineLoginAndSaveTokens, extendCurrentSession, loadTokens, removeTokens, TokenSet } from './src/auth.js'
|
|
14
|
+
import { registerBuildCommand } from './src/buildCommand.js'
|
|
4
15
|
import { portalBaseUrl, setPortalBaseUrl } from './src/config.js'
|
|
5
|
-
import {
|
|
6
|
-
loginAndSaveTokens,
|
|
7
|
-
machineLoginAndSaveTokens,
|
|
8
|
-
extendCurrentSession,
|
|
9
|
-
loadTokens,
|
|
10
|
-
removeTokens,
|
|
11
|
-
TokenSet,
|
|
12
|
-
} from './src/auth.js'
|
|
13
16
|
import { checkGameServerDeployment, debugGameServer } from './src/deployment.js'
|
|
14
|
-
import {
|
|
15
|
-
pathJoin,
|
|
16
|
-
isValidFQDN,
|
|
17
|
-
executeCommand,
|
|
18
|
-
removeTrailingSlash,
|
|
19
|
-
fetchHelmChartVersions,
|
|
20
|
-
resolveBestMatchingVersion,
|
|
21
|
-
} from './src/utils.js'
|
|
22
17
|
import { logger, setLogLevel } from './src/logging.js'
|
|
23
18
|
import { TargetEnvironment } from './src/targetenvironment.js'
|
|
24
|
-
import {
|
|
25
|
-
import { tmpdir } from 'os'
|
|
26
|
-
import { randomBytes } from 'crypto'
|
|
27
|
-
import { writeFile, unlink } from 'fs/promises'
|
|
28
|
-
import { existsSync } from 'fs'
|
|
29
|
-
import { KubeConfig } from '@kubernetes/client-node'
|
|
30
|
-
import * as semver from 'semver'
|
|
19
|
+
import { pathJoin, isValidFQDN, executeCommand, removeTrailingSlash, fetchHelmChartVersions, resolveBestMatchingVersion } from './src/utils.js'
|
|
31
20
|
import { PACKAGE_VERSION } from './src/version.js'
|
|
32
|
-
import { registerBuildCommand } from './src/buildCommand.js'
|
|
33
21
|
|
|
34
22
|
/**
|
|
35
23
|
* Base URL of StackAPI infra to use -- defaults to p1.metaplay.io. Override with the global --stack-api flag.
|
|
@@ -136,8 +124,10 @@ async function resolveTargetEnvironmentFromSlugs(
|
|
|
136
124
|
): Promise<TargetEnvironment> {
|
|
137
125
|
// Fetch the deployment information from the portal
|
|
138
126
|
const portalEnvInfo = await fetchManagedEnvironmentInfo(tokens, organization, project, environment)
|
|
139
|
-
|
|
140
|
-
|
|
127
|
+
const humanId = portalEnvInfo.human_id
|
|
128
|
+
if (!humanId) {
|
|
129
|
+
throw new Error(`Portal returned missing human_id for environment '${organization}-${project}-${environment}'`)
|
|
130
|
+
}
|
|
141
131
|
|
|
142
132
|
return new TargetEnvironment(tokens.access_token, humanId, defaultStackApiBaseUrl)
|
|
143
133
|
}
|
|
@@ -176,9 +166,7 @@ async function resolveTargetEnvironment(
|
|
|
176
166
|
// Three parts is tuple of slush '<organization>-<project>-<environment>'
|
|
177
167
|
return await resolveTargetEnvironmentFromSlugs(tokens, parts[0], parts[1], parts[2])
|
|
178
168
|
} else {
|
|
179
|
-
throw new Error(
|
|
180
|
-
`Invalid environment address syntax '${address}'. Specify either "<organization>-<project>-<environment>", a humanId (eg, "delicious-elephant"), or a fully-qualified domain name (eg, idler-develop.p1.metaplay.io)`
|
|
181
|
-
)
|
|
169
|
+
throw new Error(`Invalid environment address syntax '${address}'. Specify either "<organization>-<project>-<environment>", a humanId (eg, "delicious-elephant"), or a fully-qualified domain name (eg, idler-develop.p1.metaplay.io)`)
|
|
182
170
|
}
|
|
183
171
|
}
|
|
184
172
|
} else if (options.organization && options.project && options.environment) {
|
|
@@ -188,9 +176,7 @@ async function resolveTargetEnvironment(
|
|
|
188
176
|
)
|
|
189
177
|
return await resolveTargetEnvironmentFromSlugs(tokens, options.organization, options.project, options.environment)
|
|
190
178
|
} else {
|
|
191
|
-
throw new Error(
|
|
192
|
-
'Could not determine target environment from arguments: You need to specify either an environment FQDN or an organization, project, and environment. Run this command with --help flag for more information.'
|
|
193
|
-
)
|
|
179
|
+
throw new Error('Could not determine target environment from arguments: You need to specify either an environment FQDN or an organization, project, and environment. Run this command with --help flag for more information.')
|
|
194
180
|
}
|
|
195
181
|
}
|
|
196
182
|
|
|
@@ -202,10 +188,7 @@ program
|
|
|
202
188
|
.version(PACKAGE_VERSION)
|
|
203
189
|
.option('-d, --debug', 'enable debug output')
|
|
204
190
|
.option('--portal-base-url <portal-base-url>', 'override the default portal base URL (e.g. http://localhost:3000)')
|
|
205
|
-
.option(
|
|
206
|
-
'--stack-api <stack-api-base-url>',
|
|
207
|
-
'override the default stack API base URL (e.g. https://infra.p1.metaplay.io/stackapi/)'
|
|
208
|
-
)
|
|
191
|
+
.option('--stack-api <stack-api-base-url>', 'override the default stack API base URL (e.g. https://infra.p1.metaplay.io/stackapi/)')
|
|
209
192
|
.hook('preAction', (thisCommand) => {
|
|
210
193
|
// Handle debug flag for all commands.
|
|
211
194
|
const opts = thisCommand.opts()
|
|
@@ -235,13 +218,8 @@ program
|
|
|
235
218
|
|
|
236
219
|
program
|
|
237
220
|
.command('machine-login')
|
|
238
|
-
.description(
|
|
239
|
-
|
|
240
|
-
)
|
|
241
|
-
.option(
|
|
242
|
-
'--dev-credentials',
|
|
243
|
-
'machine user credentials to use, only for dev purposes, use METAPLAY_CREDENTIALS env variable for better safety!'
|
|
244
|
-
)
|
|
221
|
+
.description('login to the Metaplay cloud using a machine account (using credentials in environment variable METAPLAY_CREDENTIALS)')
|
|
222
|
+
.option('--dev-credentials', 'machine user credentials to use, only for dev purposes, use METAPLAY_CREDENTIALS env variable for better safety!')
|
|
245
223
|
.action(async (options) => {
|
|
246
224
|
// Get credentials from command line or from METAPLAY_CREDENTIALS environment variable
|
|
247
225
|
let credentials: string
|
|
@@ -259,9 +237,7 @@ program
|
|
|
259
237
|
// \note We can't be certain that the secret does not contain pluses so split at the first occurrence
|
|
260
238
|
const splitOffset = credentials.indexOf('+')
|
|
261
239
|
if (splitOffset === -1) {
|
|
262
|
-
throw new Error(
|
|
263
|
-
'Invalid format for credentials, you should copy-paste the value from the developer portal verbatim'
|
|
264
|
-
)
|
|
240
|
+
throw new Error('Invalid format for credentials, you should copy-paste the value from the developer portal verbatim')
|
|
265
241
|
}
|
|
266
242
|
const clientId = credentials.substring(0, splitOffset)
|
|
267
243
|
const clientSecret = credentials.substring(splitOffset + 1)
|
|
@@ -315,10 +291,7 @@ program
|
|
|
315
291
|
.option('-p, --project <project>', '[deprecated] project name (e.g. idler)')
|
|
316
292
|
.option('-e, --environment <environment>', '[deprecated] environment name (e.g. develop)')
|
|
317
293
|
.option('-t, --type <credentials-type>', 'type of credentials handling in kubeconfig (static or dynamic)')
|
|
318
|
-
.option(
|
|
319
|
-
'--output <kubeconfig-path>',
|
|
320
|
-
'path of the output file where to write kubeconfig (written to stdout if not specified)'
|
|
321
|
-
)
|
|
294
|
+
.option('--output <kubeconfig-path>', 'path of the output file where to write kubeconfig (written to stdout if not specified)')
|
|
322
295
|
.hook('preAction', async () => {
|
|
323
296
|
await extendCurrentSession()
|
|
324
297
|
})
|
|
@@ -633,14 +606,8 @@ program
|
|
|
633
606
|
.argument('gameserver', 'address of gameserver (e.g. metaplay-idler-develop or idler-develop.p1.metaplay.io)')
|
|
634
607
|
.argument('image-tag', 'docker image tag to deploy (usually the SHA of the build)')
|
|
635
608
|
.requiredOption('-f, --values <path-to-values-file>', 'path to Helm values file to use for this deployment')
|
|
636
|
-
.option(
|
|
637
|
-
|
|
638
|
-
'path to local Helm chart directory (to use a chart from local disk)'
|
|
639
|
-
)
|
|
640
|
-
.option(
|
|
641
|
-
'--helm-chart-repo <url>',
|
|
642
|
-
'override the URL of the Helm chart repository (eg, https://charts.metaplay.dev/testing)'
|
|
643
|
-
)
|
|
609
|
+
.option('--local-chart-path <path-to-chart-directory>', 'path to local Helm chart directory (to use a chart from local disk)')
|
|
610
|
+
.option('--helm-chart-repo <url>', 'override the URL of the Helm chart repository (eg, https://charts.metaplay.dev/testing)')
|
|
644
611
|
.option('--helm-chart-version <version>', 'the Helm chart version to use (eg, 0.6.0)')
|
|
645
612
|
.option('--deployment-name', 'Helm deployment name to use', 'gameserver')
|
|
646
613
|
.hook('preAction', async () => {
|
|
@@ -670,16 +637,12 @@ program
|
|
|
670
637
|
const envInfo = await targetEnv.getEnvironmentDetails()
|
|
671
638
|
|
|
672
639
|
if (!imageTag) {
|
|
673
|
-
throw new Error(
|
|
674
|
-
'Must specify a valid docker image tag as the image-tag argument, usually the SHA of the build'
|
|
675
|
-
)
|
|
640
|
+
throw new Error('Must specify a valid docker image tag as the image-tag argument, usually the SHA of the build')
|
|
676
641
|
}
|
|
677
642
|
// \todo validate that imageTag is just the version part (i.e, contains no ':')
|
|
678
643
|
|
|
679
644
|
if (!options.deploymentName) {
|
|
680
|
-
throw new Error(
|
|
681
|
-
`Invalid Helm deployment name '${options.deploymentName}'; specify one with --deployment-name or use the default`
|
|
682
|
-
)
|
|
645
|
+
throw new Error(`Invalid Helm deployment name '${options.deploymentName}'; specify one with --deployment-name or use the default`)
|
|
683
646
|
}
|
|
684
647
|
|
|
685
648
|
// Fetch Docker credentials for target environment registry
|
|
@@ -784,9 +747,7 @@ program
|
|
|
784
747
|
console.warn('You should specify the Helm chart version with --helm-chart-version=<version>!')
|
|
785
748
|
}
|
|
786
749
|
if (!helmChartVersionSpec) {
|
|
787
|
-
throw new Error(
|
|
788
|
-
'No Helm chart version defined. With pre-R28 SDK versions, you must specify the Helm chart version explicitly with --helm-chart-version=<version>.'
|
|
789
|
-
)
|
|
750
|
+
throw new Error('No Helm chart version defined. With pre-R28 SDK versions, you must specify the Helm chart version explicitly with --helm-chart-version=<version>.')
|
|
790
751
|
}
|
|
791
752
|
|
|
792
753
|
// Parse the Helm chart version spec into a semver.Range, or null if 'latest' is specified
|
|
@@ -795,7 +756,7 @@ program
|
|
|
795
756
|
try {
|
|
796
757
|
helmChartRange = new semver.Range(helmChartVersionSpec)
|
|
797
758
|
} catch (error) {
|
|
798
|
-
throw new Error(`Helm chart version '${helmChartVersionSpec}' is not a valid SemVer range
|
|
759
|
+
throw new Error(`Helm chart version '${helmChartVersionSpec}' is not a valid SemVer range: ${String(error)}`)
|
|
799
760
|
}
|
|
800
761
|
}
|
|
801
762
|
|
|
@@ -811,9 +772,7 @@ program
|
|
|
811
772
|
// Resolve the best matching Helm chart version
|
|
812
773
|
const resolvedHelmChartVersion = resolveBestMatchingVersion(availableHelmChartVersions, helmChartRange)
|
|
813
774
|
if (!resolvedHelmChartVersion) {
|
|
814
|
-
throw new Error(
|
|
815
|
-
`No Helm chart version found that satisfies '${helmChartVersionSpec}' in repository '${helmChartRepo}'`
|
|
816
|
-
)
|
|
775
|
+
throw new Error(`No Helm chart version found that satisfies '${helmChartVersionSpec}' in repository '${helmChartRepo}'`)
|
|
817
776
|
}
|
|
818
777
|
logger.debug('Resolved Helm chart version: ', resolvedHelmChartVersion)
|
|
819
778
|
|
|
@@ -845,9 +804,7 @@ program
|
|
|
845
804
|
// \todo output something from Helm result?
|
|
846
805
|
} catch (error) {
|
|
847
806
|
const errMessage = error instanceof Error ? error.message : String(error)
|
|
848
|
-
throw new Error(
|
|
849
|
-
`Failed to execute 'helm': ${errMessage}. You need to have Helm v3 installed to deploy a game server with metaplay-auth.`
|
|
850
|
-
)
|
|
807
|
+
throw new Error(`Failed to execute 'helm': ${errMessage}. You need to have Helm v3 installed to deploy a game server with metaplay-auth.`)
|
|
851
808
|
}
|
|
852
809
|
|
|
853
810
|
// Throw on Helm non-success exit code
|
|
@@ -895,9 +852,7 @@ program
|
|
|
895
852
|
|
|
896
853
|
program
|
|
897
854
|
.command('check-server-status')
|
|
898
|
-
.description(
|
|
899
|
-
'check the status of a deployed server and print out information that is helpful in debugging failed deployments'
|
|
900
|
-
)
|
|
855
|
+
.description('check the status of a deployed server and print out information that is helpful in debugging failed deployments')
|
|
901
856
|
.argument('[gameserver]', 'address of gameserver (e.g. metaplay-idler-develop or idler-develop.p1.metaplay.io)')
|
|
902
857
|
.hook('preAction', async () => {
|
|
903
858
|
await extendCurrentSession()
|
|
@@ -941,9 +896,7 @@ program
|
|
|
941
896
|
|
|
942
897
|
program
|
|
943
898
|
.command('check-deployment')
|
|
944
|
-
.description(
|
|
945
|
-
'[deprecated] check that a game server was successfully deployed, or print out useful error messages in case of failure'
|
|
946
|
-
)
|
|
899
|
+
.description('[deprecated] check that a game server was successfully deployed, or print out useful error messages in case of failure')
|
|
947
900
|
.argument('[namespace]', 'kubernetes namespace of the deployment')
|
|
948
901
|
.action(async (namespace: string) => {
|
|
949
902
|
console.error(
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metaplay/metaplay-auth",
|
|
3
3
|
"description": "Utility CLI for authenticating with the Metaplay Auth and making authenticated calls to infrastructure endpoints.",
|
|
4
|
-
"version": "1.6.
|
|
4
|
+
"version": "1.6.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
7
7
|
"homepage": "https://metaplay.io",
|
|
@@ -17,8 +17,6 @@
|
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@metaplay/eslint-config": "workspace:*",
|
|
20
|
-
"@metaplay/prettier-config": "workspace:^",
|
|
21
|
-
"@prettier/plugin-pug": "workspace:^",
|
|
22
20
|
"@types/dockerode": "^3.3.31",
|
|
23
21
|
"@types/express": "^4.17.21",
|
|
24
22
|
"@types/js-yaml": "^4.0.9",
|
|
@@ -30,7 +28,7 @@
|
|
|
30
28
|
"tsx": "^4.19.0",
|
|
31
29
|
"typescript": "5.5.4",
|
|
32
30
|
"vitest": "^2.0.5",
|
|
33
|
-
"@aws-sdk/client-ecr": "^3.
|
|
31
|
+
"@aws-sdk/client-ecr": "^3.645.0",
|
|
34
32
|
"@kubernetes/client-node": "^1.0.0-rc6",
|
|
35
33
|
"@ory/client": "^1.14.5",
|
|
36
34
|
"commander": "^12.1.0",
|
|
@@ -41,7 +39,6 @@
|
|
|
41
39
|
"jwk-to-pem": "^2.0.6",
|
|
42
40
|
"open": "^8.4.2",
|
|
43
41
|
"semver": "^7.6.3",
|
|
44
|
-
"tslog": "^4.9.3"
|
|
45
|
-
"prettier": "3.3.3"
|
|
42
|
+
"tslog": "^4.9.3"
|
|
46
43
|
}
|
|
47
44
|
}
|
package/src/auth.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-misused-promises */
|
|
2
|
-
|
|
3
|
-
import { createServer } from 'node:http'
|
|
4
2
|
import { toNodeListener, createApp, defineEventHandler, getQuery, sendError } from 'h3'
|
|
5
|
-
|
|
6
|
-
import open from 'open'
|
|
7
|
-
import { randomBytes, createHash } from 'node:crypto'
|
|
8
3
|
import jwt from 'jsonwebtoken'
|
|
9
4
|
import jwkToPem from 'jwk-to-pem'
|
|
5
|
+
import { randomBytes, createHash } from 'node:crypto'
|
|
6
|
+
import { createServer } from 'node:http'
|
|
7
|
+
import open from 'open'
|
|
8
|
+
|
|
10
9
|
import { Configuration, WellknownApi, OidcApi } from '@ory/client'
|
|
11
|
-
|
|
10
|
+
|
|
12
11
|
import { portalBaseUrl } from './config.js'
|
|
13
12
|
import { logger } from './logging.js'
|
|
13
|
+
import { setSecret, getSecret, removeSecret } from './secret_store.js'
|
|
14
14
|
|
|
15
15
|
export interface TokenSet {
|
|
16
16
|
id_token?: string
|
|
@@ -241,9 +241,7 @@ export async function extendCurrentSession(): Promise<void> {
|
|
|
241
241
|
|
|
242
242
|
// Check that the refresh_token exists (machine users don't have it)
|
|
243
243
|
if (!tokens.refresh_token) {
|
|
244
|
-
throw new Error(
|
|
245
|
-
'Cannot refresh an access_token without a refresh_token. With machine users, should just login again instead.'
|
|
246
|
-
)
|
|
244
|
+
throw new Error('Cannot refresh an access_token without a refresh_token. With machine users, should just login again instead.')
|
|
247
245
|
}
|
|
248
246
|
|
|
249
247
|
logger.debug('Access token is no longer valid, trying to extend the current session with a refresh token.')
|
|
@@ -295,9 +293,7 @@ async function extendCurrentSessionWithRefreshToken(
|
|
|
295
293
|
logger.error(`Failed to refresh tokens via endpoint ${tokenEndpoint}`)
|
|
296
294
|
logger.error('Fetch error details:', error)
|
|
297
295
|
if (error.cause?.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {
|
|
298
|
-
throw new Error(
|
|
299
|
-
`Failed to refresh tokens: SSL certificate validation failed for ${tokenEndpoint}. Is someone trying to tamper with your internet connection?`
|
|
300
|
-
)
|
|
296
|
+
throw new Error(`Failed to refresh tokens: SSL certificate validation failed for ${tokenEndpoint}. Is someone trying to tamper with your internet connection?`)
|
|
301
297
|
}
|
|
302
298
|
throw new Error(`Failed to refresh tokens via ${tokenEndpoint}: ${error}`)
|
|
303
299
|
}
|
|
@@ -386,9 +382,7 @@ export async function saveTokens(tokens: Record<string, string>): Promise<void>
|
|
|
386
382
|
|
|
387
383
|
// All tokens must have an access_token (machine users only have it)
|
|
388
384
|
if (!tokens.access_token) {
|
|
389
|
-
throw new Error(
|
|
390
|
-
'Metaplay token has no access_token. Please log in again and make sure all checkboxes of permissions are selected before proceeding.'
|
|
391
|
-
)
|
|
385
|
+
throw new Error('Metaplay token has no access_token. Please log in again and make sure all checkboxes of permissions are selected before proceeding.')
|
|
392
386
|
}
|
|
393
387
|
|
|
394
388
|
logger.debug('Token verification completed, storing tokens...')
|
package/src/buildCommand.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
|
-
import { exit } from 'process'
|
|
3
2
|
import { existsSync } from 'fs'
|
|
4
|
-
import { pathJoin, executeCommand, ExecuteCommandResult } from './utils.js'
|
|
5
|
-
import { logger } from './logging.js'
|
|
6
3
|
import path from 'path'
|
|
4
|
+
import { exit } from 'process'
|
|
5
|
+
|
|
6
|
+
import { logger } from './logging.js'
|
|
7
|
+
import { pathJoin, executeCommand, ExecuteCommandResult } from './utils.js'
|
|
7
8
|
|
|
8
9
|
function resolveBuildEngine(engine?: string): string {
|
|
9
10
|
const validBuildEngines = ['buildx', 'buildkit']
|
|
@@ -32,22 +33,10 @@ export function registerBuildCommand(program: Command): void {
|
|
|
32
33
|
.description('build the game server docker image')
|
|
33
34
|
.option('-t, --image-tag <image-tag>', 'tag for the output image, eg, "myserver:d08747679d"', 'gameserver:<timestamp>')
|
|
34
35
|
.option('--sdk-root <directory>', 'relative path to the MetaplaySDK directory', 'MetaplaySDK')
|
|
35
|
-
.option(
|
|
36
|
-
'--project-root <directory>',
|
|
37
|
-
'relative path to the project root (where Backend/ directory is located)',
|
|
38
|
-
'.'
|
|
39
|
-
)
|
|
36
|
+
.option('--project-root <directory>', 'relative path to the project root (where Backend/ directory is located)', '.')
|
|
40
37
|
.option('--backend-dir <directory>', '[for legacy projects] name of the Backend/ directory', 'Backend')
|
|
41
|
-
.option(
|
|
42
|
-
|
|
43
|
-
'path to the shared code directory of the project, relative to --project-root',
|
|
44
|
-
'Assets/SharedCode'
|
|
45
|
-
)
|
|
46
|
-
.option(
|
|
47
|
-
'--engine <engine>',
|
|
48
|
-
'docker build engine to use (buildx or buildkit), auto-detected if not specified',
|
|
49
|
-
'buildx'
|
|
50
|
-
)
|
|
38
|
+
.option('--shared-code-dir <directory>', 'path to the shared code directory of the project, relative to --project-root', 'Assets/SharedCode')
|
|
39
|
+
.option('--engine <engine>', 'docker build engine to use (buildx or buildkit), auto-detected if not specified', 'buildx')
|
|
51
40
|
.option('--architecture <architecture>', 'target platform architecture (amd64 or arm64)', 'amd64')
|
|
52
41
|
.option('--build-number <build-number>', 'number of this build (eg, 153)')
|
|
53
42
|
.option('--commit-id <commit-id>', 'commit id of this build (eg, d08747679d1e7fc9c1c685b396636da689ae476d)')
|
|
@@ -72,7 +61,9 @@ export function registerBuildCommand(program: Command): void {
|
|
|
72
61
|
console.log(`Building docker image '${imageTag}'..`)
|
|
73
62
|
|
|
74
63
|
if (imageTag.endsWith(':latest')) {
|
|
75
|
-
console.error(
|
|
64
|
+
console.error(
|
|
65
|
+
'Building docker image with "latest" tag is not allowed as it won\'t update the cloud environments reliably. Use commit id like git sha or timestamp instead.'
|
|
66
|
+
)
|
|
76
67
|
exit(1)
|
|
77
68
|
}
|
|
78
69
|
|
|
@@ -207,17 +198,16 @@ export function registerBuildCommand(program: Command): void {
|
|
|
207
198
|
logger.debug(`Using docker build engine: ${buildEngine}`)
|
|
208
199
|
|
|
209
200
|
// Check that docker is installed and running
|
|
210
|
-
const checkDockerResult = await executeCommand('docker', ['
|
|
201
|
+
const checkDockerResult = await executeCommand('docker', ['info'], { inheritStdio: false })
|
|
211
202
|
if (checkDockerResult.exitCode !== 0) {
|
|
212
|
-
console.error(
|
|
203
|
+
console.error(`Failed to invoke docker, please make sure that docker is installed and running (exit code = ${checkDockerResult.exitCode})`)
|
|
213
204
|
exit(1)
|
|
214
205
|
}
|
|
215
206
|
|
|
216
207
|
// If buildx engine specified, check that it works
|
|
217
208
|
if (buildEngine === 'buildx') {
|
|
218
209
|
const checkBuildxResult = await executeCommand('docker', ['buildx', 'version'], {
|
|
219
|
-
inheritStdio: false
|
|
220
|
-
env: {},
|
|
210
|
+
inheritStdio: false
|
|
221
211
|
})
|
|
222
212
|
if (checkBuildxResult.exitCode !== 0) {
|
|
223
213
|
console.warn('Docker buildx is not supported on this machine, falling back to --engine=buildkit')
|
package/src/deployment.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { unlink, writeFile } from 'fs/promises'
|
|
2
|
+
import os from 'os'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import { exit } from 'process'
|
|
5
|
+
import { TargetEnvironment } from 'targetenvironment.js'
|
|
6
|
+
|
|
1
7
|
import {
|
|
2
8
|
KubeConfig,
|
|
3
9
|
CoreV1Api,
|
|
@@ -5,13 +11,9 @@ import {
|
|
|
5
11
|
type CoreV1ApiListNamespacedPodRequest,
|
|
6
12
|
type CoreV1ApiReadNamespacedPodLogRequest,
|
|
7
13
|
} from '@kubernetes/client-node'
|
|
14
|
+
|
|
8
15
|
import { logger } from './logging.js'
|
|
9
|
-
import { TargetEnvironment } from 'targetenvironment.js'
|
|
10
|
-
import { exit } from 'process'
|
|
11
|
-
import { unlink, writeFile } from 'fs/promises'
|
|
12
16
|
import { executeCommand } from './utils.js'
|
|
13
|
-
import os from 'os'
|
|
14
|
-
import path from 'path'
|
|
15
17
|
|
|
16
18
|
enum GameServerPodPhase {
|
|
17
19
|
Ready = 'Ready', // Successfully started and ready to accept traffic
|
package/src/secret_store.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { promises as fs } from 'fs'
|
|
2
|
-
import { join } from 'path'
|
|
3
1
|
import { randomBytes, createCipheriv, createDecipheriv, scryptSync } from 'crypto'
|
|
2
|
+
import { promises as fs } from 'fs'
|
|
4
3
|
import { homedir } from 'os'
|
|
4
|
+
import { join } from 'path'
|
|
5
|
+
|
|
5
6
|
import { logger } from './logging.js'
|
|
6
7
|
|
|
7
8
|
const filePath: string = process.env.METAPLAY_AUTH_FILE ?? join(homedir(), '.metaplay_auth.json')
|
package/src/targetenvironment.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { logger } from './logging.js'
|
|
2
1
|
import { dump } from 'js-yaml'
|
|
2
|
+
|
|
3
|
+
import { ECRClient, GetAuthorizationTokenCommand } from '@aws-sdk/client-ecr'
|
|
4
|
+
|
|
3
5
|
import { getUserinfo } from './auth.js'
|
|
6
|
+
import { logger } from './logging.js'
|
|
4
7
|
import { isRunningUnderNpx } from './utils.js'
|
|
5
|
-
import { ECRClient, GetAuthorizationTokenCommand } from '@aws-sdk/client-ecr'
|
|
6
8
|
|
|
7
9
|
interface AwsCredentialsResponse {
|
|
8
10
|
AccessKeyId: string
|
|
@@ -124,9 +126,7 @@ export class TargetEnvironment {
|
|
|
124
126
|
} catch (error: any) {
|
|
125
127
|
logger.error(`Failed to fetch ${method} ${url}:`, error)
|
|
126
128
|
if (error.cause?.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {
|
|
127
|
-
throw new Error(
|
|
128
|
-
`Failed to to fetch ${url}: SSL certificate validation failed. Is someone trying to tamper with your internet connection?`
|
|
129
|
-
)
|
|
129
|
+
throw new Error(`Failed to to fetch ${url}: SSL certificate validation failed. Is someone trying to tamper with your internet connection?`)
|
|
130
130
|
}
|
|
131
131
|
throw new Error(`Failed to fetch ${url}: ${error}`)
|
|
132
132
|
}
|
package/src/utils.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { spawn } from 'child_process'
|
|
2
|
-
import { logger } from './logging.js'
|
|
3
|
-
import path from 'path'
|
|
4
2
|
import yaml from 'js-yaml'
|
|
3
|
+
import path from 'path'
|
|
5
4
|
import * as semver from 'semver'
|
|
6
5
|
|
|
6
|
+
import { logger } from './logging.js'
|
|
7
|
+
|
|
7
8
|
/**
|
|
8
9
|
* Checks if the given string is a fully qualified domain name (FQDN).
|
|
9
10
|
*
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = "1.6.
|
|
1
|
+
export const PACKAGE_VERSION = "1.6.1"
|
package/.prettierignore
DELETED
package/prettier.config.js
DELETED