@metaplay/metaplay-auth 1.7.2 → 1.8.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.
package/src/utils.ts CHANGED
@@ -4,6 +4,9 @@ import path from 'path'
4
4
  import * as semver from 'semver'
5
5
 
6
6
  import { logger } from './logging.js'
7
+ import { tmpdir } from 'os'
8
+ import { randomBytes } from 'crypto'
9
+ import { unlink, writeFile } from 'fs/promises'
7
10
 
8
11
  /**
9
12
  * Checks if the given string is a fully qualified domain name (FQDN).
@@ -47,10 +50,11 @@ export function splitUrlComponents(urlString: string): {
47
50
  }
48
51
  }
49
52
 
53
+ /** Output from executing a shell command with executeCommand(). */
50
54
  export interface ExecuteCommandResult {
51
55
  exitCode: number | null
52
- stdout: any[]
53
- stderr: any[]
56
+ stdout: string[]
57
+ stderr: string[]
54
58
  }
55
59
 
56
60
  export interface ExecuteCommandOptions {
@@ -215,3 +219,77 @@ export function resolveBestMatchingVersion(versions: string[], range: semver.Ran
215
219
  const sortedVersions = satisfyingVersions.sort(semver.rcompare)
216
220
  return sortedVersions[0]
217
221
  }
222
+
223
+ /**
224
+ * Execute a Helm command by invoking the Helm CLI client with the given kubeconfig and arguments to `helm`.
225
+ * The provided kubeconfig is written to a temporary file and cleaned up after, and passed to `helm` with
226
+ * `--kubeconfig <path>`.
227
+ */
228
+ export async function executeHelmCommand(kubeconfigPayload: string, args: string[]): Promise<ExecuteCommandResult> {
229
+ // Store kubeconfig in a temporary file.
230
+ const kubeconfigPath = pathJoin(tmpdir(), randomBytes(20).toString('hex'))
231
+ logger.debug(`Write temporary kubeconfig in ${kubeconfigPath}`)
232
+ await writeFile(kubeconfigPath, kubeconfigPayload, { mode: 0o600 })
233
+ args = args.concat(['--kubeconfig', kubeconfigPath])
234
+
235
+ // Use try-finally to remove the temp kubeconfig at the end
236
+ try {
237
+ // Execute the Helm invocation
238
+ let helmResult: ExecuteCommandResult
239
+ try {
240
+ helmResult = await executeCommand('helm', args)
241
+ // \todo output something from Helm result?
242
+ } catch (error) {
243
+ const errMessage = error instanceof Error ? error.message : String(error)
244
+ throw new Error(`Failed to execute 'helm': ${errMessage}. You need to have Helm v3 installed to deploy a game server with metaplay-auth.`)
245
+ }
246
+
247
+ // Throw on Helm non-success exit code
248
+ if (helmResult.exitCode !== 0) {
249
+ throw new Error(`Helm invocation failed with exit code ${helmResult.exitCode}: ${String(helmResult.stderr)}`)
250
+ }
251
+
252
+ // Return stdout as string
253
+ return helmResult
254
+ } finally {
255
+ // Remove temporary kubeconfig file
256
+ await unlink(kubeconfigPath)
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Information about a Helm release. The results of 'helm ls -o=json'.
262
+ */
263
+ export interface HelmRelease {
264
+ name: string // Eg, "gameserver"
265
+ namespace: string // Eg, "idler-develop"
266
+ revision: string // Eg, "334"
267
+ updated: string // Eg, "2024-11-21 10:38:06.105016472 +0000 UTC"
268
+ status: string // Eg, "deployed"
269
+ chart: string // Eg, "metaplay-gameserver-0.6.4"
270
+ app_version: string // Eg, ""
271
+ }
272
+
273
+ /**
274
+ * Get the game server Helm release details (or null if no server deployed).
275
+ * Assumes that the kubeconfig is already targeting a tenant namespace.
276
+ */
277
+ export async function getGameServerHelmRelease(kubeconfigPayload: string): Promise<HelmRelease | null> {
278
+ // Fetch all Helm releases.
279
+ const result = await executeHelmCommand(kubeconfigPayload, ['ls', '-o=json'])
280
+
281
+ // Parse the releases from output JSON.
282
+ const helmReleases = JSON.parse(result.stdout.join('')) as HelmRelease[]
283
+
284
+ // Only select any that are game servers.
285
+ const serverReleases = helmReleases.filter(r => r.chart.startsWith('metaplay-gameserver-'))
286
+
287
+ // Cannot have multiple game servers installed.
288
+ if (serverReleases.length === 0) {
289
+ return null
290
+ } else if (serverReleases.length === 1) {
291
+ return serverReleases[0]
292
+ } else {
293
+ throw new Error(`Multiple game server Helm charts installed: ${JSON.stringify(serverReleases, undefined, 2)}`)
294
+ }
295
+ }
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const PACKAGE_VERSION = "1.7.2"
1
+ export const PACKAGE_VERSION = "1.8.0"
Binary file