@metaplay/metaplay-auth 1.4.1 → 1.5.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.
@@ -1,250 +0,0 @@
1
- import { KubeConfig, CoreV1Api, V1Pod } from '@kubernetes/client-node';
2
- import { logger } from './logging.js';
3
- var GameServerPodPhase;
4
- (function (GameServerPodPhase) {
5
- GameServerPodPhase["Ready"] = "Ready";
6
- GameServerPodPhase["Running"] = "Running";
7
- GameServerPodPhase["Pending"] = "Pending";
8
- GameServerPodPhase["Unknown"] = "Unknown";
9
- GameServerPodPhase["Failed"] = "Failed";
10
- })(GameServerPodPhase || (GameServerPodPhase = {}));
11
- async function fetchGameServerPods(k8sApi, namespace) {
12
- // Define label selector for gameserver
13
- logger.debug(`Fetching game server pods from Kubernetes: namespace=${namespace}`);
14
- const param = {
15
- namespace,
16
- labelSelector: 'app=metaplay-server'
17
- };
18
- try {
19
- // Get gameserver pods in the namespace
20
- const response = await k8sApi.listNamespacedPod(param);
21
- // Return pod statuses
22
- return response.items;
23
- }
24
- catch (error) {
25
- // \todo Better error handling ..
26
- console.log('Failed to fetch pods from Kubernetes:', error);
27
- throw new Error('Failed to fetch pods from Kubernetes');
28
- }
29
- }
30
- function resolvePodContainersConditions(pod) {
31
- const containerStatuses = pod.status?.containerStatuses;
32
- if (!containerStatuses || containerStatuses.length === 0) {
33
- return { phase: GameServerPodPhase.Unknown, message: 'Unable to determine pod container statuses: pod.status.containerStatuses is empty' };
34
- }
35
- // Find the shard-server container from the pod (ignore others)
36
- const containerStatus = containerStatuses.find(status => status.name === 'shard-server');
37
- if (!containerStatus) {
38
- return { phase: GameServerPodPhase.Unknown, message: 'Unable to find container shard-server from the pod' };
39
- }
40
- // Handle missing container state
41
- logger.debug(`Container status for pod ${pod.metadata?.name ?? '<unnamed>'}: ${JSON.stringify(containerStatus, undefined, 2)}`);
42
- const containerState = containerStatus.state;
43
- if (!containerState) {
44
- return { phase: GameServerPodPhase.Unknown, message: 'Unable to get container state' };
45
- }
46
- // Check if container running & ready
47
- const containerName = containerStatus.name;
48
- if (containerState.running) {
49
- if (containerStatus.ready) {
50
- return { phase: GameServerPodPhase.Ready, message: `Container ${containerName} is in ready phase`, details: containerState.running };
51
- }
52
- else {
53
- return { phase: GameServerPodPhase.Running, message: `Container ${containerName} is in running phase`, details: containerState.running };
54
- }
55
- }
56
- // \note these may not be complete (or completely accurate)
57
- const knownContainerFailureReasons = ['CrashLoopBackOff', 'Error', 'ImagePullBackOff', 'CreateContainerConfigError', 'OOMKilled', 'ContainerCannotRun', 'BackOff', 'InvalidImageName'];
58
- const knownContainerPendingReasons = ['Init', 'Pending', 'PodInitializing'];
59
- // Check if there's a previous terminated state (usually indicates a crash during server initialization)
60
- const lastState = containerStatus.lastState;
61
- if (lastState) {
62
- if (lastState.terminated) {
63
- // Try to detecth why the previous launch failed
64
- if (containerState.waiting) {
65
- const reason = containerState.waiting.reason;
66
- if (knownContainerFailureReasons.includes(reason)) {
67
- return { phase: GameServerPodPhase.Failed, message: `Container ${containerName} is in waiting state, reason=${reason}`, details: containerState.waiting };
68
- }
69
- else if (knownContainerPendingReasons.includes(reason)) {
70
- return { phase: GameServerPodPhase.Pending, message: `Container ${containerName} is in waiting state, reason=${reason}`, details: containerState.waiting };
71
- }
72
- else {
73
- return { phase: GameServerPodPhase.Unknown, message: `Container ${containerName} is in waiting state, reason=${reason}`, details: containerState.waiting };
74
- }
75
- }
76
- else if (containerState.running) {
77
- // This happens when the container is still initializing
78
- return { phase: GameServerPodPhase.Pending, message: `Container ${containerName} is in running state`, details: containerState.running };
79
- }
80
- else if (containerState.terminated) {
81
- return { phase: GameServerPodPhase.Failed, message: `Container ${containerName} is in terminated state`, details: containerState.terminated };
82
- }
83
- // Unable to determine launch failure reason, just return previous launch
84
- return { phase: GameServerPodPhase.Failed, message: `Container ${containerName} previous launch failed with exitCode=${lastState.terminated.exitCode} and reason=${lastState.terminated.reason}`, details: lastState.terminated };
85
- }
86
- // \todo handle containerState.running states (including various initialization states)
87
- // \todo handle containerState.terminated states (what do these even mean)
88
- }
89
- logger.debug('Game server pod container in unknown state:', containerState);
90
- return { phase: GameServerPodPhase.Unknown, message: 'Container in unknown state', details: containerState };
91
- }
92
- function resolvePodStatusConditions(pod) {
93
- const conditions = pod.status?.conditions;
94
- if (!conditions || conditions.length === 0) {
95
- return { phase: GameServerPodPhase.Unknown, message: 'Unable to determine pod status: pod.status.conditions is empty', details: pod.status };
96
- }
97
- // Bail if 'PodScheduled' is not yet true
98
- const condPodScheduled = conditions.find(cond => cond.type === 'PodScheduled');
99
- if (condPodScheduled?.status !== 'True') {
100
- return { phase: GameServerPodPhase.Pending, message: `Pod has not yet been scheduled on a node: ${condPodScheduled?.message}`, details: condPodScheduled };
101
- }
102
- // Bail if 'Initialized' not is yet true
103
- const condInitialized = conditions.find(cond => cond.type === 'Initialized');
104
- if (condInitialized?.status !== 'True') {
105
- return { phase: GameServerPodPhase.Pending, message: `Pod has not yet been initialized: ${condInitialized?.message}`, details: condInitialized };
106
- }
107
- // Bail if 'ContainersReady' is not yet true
108
- const condContainersReady = conditions.find(cond => cond.type === 'ContainersReady');
109
- if (condContainersReady?.status !== 'True') {
110
- if (condContainersReady?.reason === 'ContainersNotReady') {
111
- return resolvePodContainersConditions(pod);
112
- }
113
- return { phase: GameServerPodPhase.Pending, message: `Pod containers are not yet ready: ${condContainersReady?.message}`, details: condContainersReady };
114
- }
115
- // Bail if 'Ready' is not yet true
116
- const condReady = conditions.find(cond => cond.type === 'Ready');
117
- if (condReady?.status !== 'True') {
118
- return { phase: GameServerPodPhase.Pending, message: `Pod is not yet ready: ${condReady?.message}`, details: condReady };
119
- }
120
- // resolvePodContainersConditions(pod) // DEBUG DEBUG enable to print container state for running pods
121
- return { phase: GameServerPodPhase.Ready, message: 'Pod is ready to serve traffic' };
122
- }
123
- function resolvePodStatus(pod) {
124
- // logger.debug('resolvePodStatus(): pod =', JSON.stringify(pod, undefined, 2))
125
- if (!pod) {
126
- return { phase: GameServerPodPhase.Unknown, message: 'Received empty pod from Kubernetes' };
127
- }
128
- if (!pod.status) {
129
- return { phase: GameServerPodPhase.Unknown, message: 'Unable to access pod.status from Kubernetes' };
130
- }
131
- // Handle status.phase
132
- const podPhase = pod.status?.phase;
133
- switch (podPhase) {
134
- case 'Pending':
135
- // Pod not yet scheduled
136
- return { phase: GameServerPodPhase.Pending, message: 'Pod is still in Pending phase' };
137
- case 'Running':
138
- // Pod has been scheduled and start -- note that the containers may have failed!
139
- return resolvePodStatusConditions(pod);
140
- case 'Succeeded': // Should not happen, the game server pods should never stop
141
- case 'Failed': // Should not happen, the game server pods should never stop
142
- case 'Unknown':
143
- default:
144
- return { phase: GameServerPodPhase.Unknown, message: `Invalid pod.status.phase: ${podPhase}` };
145
- }
146
- }
147
- async function fetchPodLogs(k8sApi, pod) {
148
- const podName = pod.metadata?.name;
149
- logger.debug(`Fetching logs for pod '${podName}'..`);
150
- const namespace = pod.metadata?.namespace;
151
- const containerName = pod.spec?.containers[0].name; // \todo Handle multiple containers?
152
- if (!podName || !namespace || !containerName) {
153
- throw new Error('Unable to determine pod and container metadata');
154
- }
155
- const params = {
156
- name: podName,
157
- namespace,
158
- container: containerName,
159
- pretty: 'true',
160
- previous: false,
161
- tailLines: 100,
162
- timestamps: true
163
- };
164
- try {
165
- const response = await k8sApi.readNamespacedPodLog(params);
166
- return response;
167
- }
168
- catch (error) {
169
- // \todo Better error handling ..
170
- console.log('Failed to fetch pod logs from Kubernetes:', error);
171
- throw new Error('Failed to fetch pod logs from Kubernetes');
172
- }
173
- }
174
- async function checkGameServerPod(k8sApi, pod) {
175
- // console.log('Pod:', JSON.stringify(pod, undefined, 2))
176
- // Classify game server status
177
- const podStatus = resolvePodStatus(pod);
178
- const podName = pod.metadata?.name ?? '<unable to resolve name>';
179
- // If game server launch failed, get the error logs
180
- if (podStatus.phase === GameServerPodPhase.Failed) {
181
- const logs = await fetchPodLogs(k8sApi, pod);
182
- console.log(`Logs from pod '${podName}':\n${logs}`);
183
- }
184
- logger.debug(`Pod ${podName} status: ${JSON.stringify(podStatus, undefined, 2)}`);
185
- return podStatus;
186
- }
187
- async function delay(ms) {
188
- return await new Promise(resolve => setTimeout(resolve, ms));
189
- }
190
- function anyPodsInPhase(podStatuses, phase) {
191
- return podStatuses.some(status => status.phase === phase);
192
- }
193
- function allPodsInPhase(podStatuses, phase) {
194
- return podStatuses.every(status => status.phase === phase);
195
- }
196
- export async function checkGameServerDeployment(namespace, kubeconfig) {
197
- const k8sApi = kubeconfig.makeApiClient(CoreV1Api);
198
- // Figure out when to stop
199
- const startTime = Date.now();
200
- const timeoutAt = startTime + 1 * 60 * 1000; // 5min
201
- while (true) {
202
- // Check pod states
203
- const pods = await fetchGameServerPods(k8sApi, namespace);
204
- logger.debug(`Found ${pods?.length} pod(s) deployed in Kubernetes`);
205
- if (pods.length > 0) {
206
- // Resolve status for all pods
207
- const podStatuses = await Promise.all(pods.map(async (pod) => await checkGameServerPod(k8sApi, pod)));
208
- logger.debug(`Pod phases: ${podStatuses.map(status => status.phase)}`);
209
- // Handle state of the deployment
210
- if (anyPodsInPhase(podStatuses, GameServerPodPhase.Failed)) {
211
- logger.error(`Gameserver start failed with pod statuses: ${JSON.stringify(podStatuses, undefined, 2)}`);
212
- console.log('Gameserver failed to start due to the pods not starting properly! See above for details.');
213
- for (let ndx = 0; ndx < pods.length; ndx += 1) {
214
- const status = podStatuses[ndx];
215
- const suffix = (status.phase !== GameServerPodPhase.Ready) ? ` -- ${status.message}` : '';
216
- console.log(` ${pods[ndx].metadata?.name}: ${status.phase}${suffix}`);
217
- }
218
- return 1;
219
- }
220
- else if (anyPodsInPhase(podStatuses, GameServerPodPhase.Unknown) || anyPodsInPhase(podStatuses, GameServerPodPhase.Pending) || anyPodsInPhase(podStatuses, GameServerPodPhase.Running)) {
221
- console.log('Waiting for gameserver(s) to be ready...');
222
- for (let ndx = 0; ndx < pods.length; ndx += 1) {
223
- const status = podStatuses[ndx];
224
- const suffix = (status.phase !== GameServerPodPhase.Ready) ? ` -- ${status.message}` : '';
225
- console.log(` ${pods[ndx].metadata?.name}: ${status.phase}${suffix}`);
226
- }
227
- }
228
- else if (allPodsInPhase(podStatuses, GameServerPodPhase.Ready)) {
229
- console.log('Gameserver is up and ready to serve!');
230
- // \todo add further readiness checks -- ping endpoint, ping dashboard, other checks?
231
- return 0;
232
- }
233
- else {
234
- console.log('Deployment in inconsistent state, waiting...');
235
- for (let ndx = 0; ndx < pods.length; ndx += 1) {
236
- const status = podStatuses[ndx];
237
- const suffix = (status.phase !== GameServerPodPhase.Ready) ? ` -- ${status.message}` : '';
238
- console.log(` ${pods[ndx].metadata?.name}: ${status.phase}${suffix}`);
239
- }
240
- }
241
- }
242
- if (Date.now() >= timeoutAt) {
243
- console.log('Deployment failed! Timeout while waiting for gameserver to initialize.');
244
- return 124; // timeout
245
- }
246
- // Sleep a bit to avoid spamming the log
247
- await delay(2000);
248
- }
249
- }
250
- //# sourceMappingURL=deployment.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"deployment.js","sourceRoot":"","sources":["../../src/deployment.ts"],"names":[],"mappings":"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"}
@@ -1,18 +0,0 @@
1
- import { Logger } from 'tslog';
2
- /**
3
- * The logger instance. Use this to log messages.
4
- */
5
- export const logger = new Logger({
6
- overwrite: {
7
- transportFormatted(logMetaMarkup, logArgs, logErrors, settings) {
8
- console.error(`${logMetaMarkup} ${logArgs.join('')} ${logErrors.join('')}`);
9
- }
10
- }
11
- });
12
- /**
13
- * Set the log level. We use 0 and 10.
14
- */
15
- export function setLogLevel(level) {
16
- logger.settings.minLevel = level;
17
- }
18
- //# sourceMappingURL=logging.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"logging.js","sourceRoot":"","sources":["../../src/logging.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAE9B;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC;IAC/B,SAAS,EAAE;QACT,kBAAkB,CAAE,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ;YAC7D,OAAO,CAAC,KAAK,CAAC,GAAG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;QAC7E,CAAC;KACF;CACF,CAAC,CAAA;AAEF;;GAEG;AACH,MAAM,UAAU,WAAW,CAAE,KAAa;IACxC,MAAM,CAAC,QAAQ,CAAC,QAAQ,GAAG,KAAK,CAAA;AAClC,CAAC"}
@@ -1,79 +0,0 @@
1
- import { promises as fs } from 'fs';
2
- import { join } from 'path';
3
- import { randomBytes, createCipheriv, createDecipheriv, scryptSync } from 'crypto';
4
- import { homedir } from 'os';
5
- import { logger } from './logging.js';
6
- const filePath = process.env.METAPLAY_AUTH_FILE ?? join(homedir(), '.metaplay_auth.json');
7
- const algorithm = 'aes-256-cbc';
8
- const password = process.env.METAPLAY_AUTH_PASSWORD ?? '';
9
- const salt = process.env.METAPLAY_AUTH_SALT ?? 'saltysalt';
10
- async function loadSecrets() {
11
- try {
12
- logger.debug(`Loading secrets from ${filePath}...`);
13
- await fs.access(filePath);
14
- const data = await fs.readFile(filePath, 'utf8');
15
- // if password is not provided, treat as unencrypted
16
- if (password.length === 0) {
17
- logger.debug('No password provided. Treating as unencrypted.');
18
- return JSON.parse(data);
19
- }
20
- logger.debug('Decrypting data...');
21
- const decryptedData = decrypt(data);
22
- return JSON.parse(decryptedData);
23
- }
24
- catch (error) {
25
- const nodeError = error;
26
- if (nodeError.code === 'ENOENT') {
27
- // file does not exist, just revert to an empty object
28
- return {};
29
- }
30
- if (password.length === 0) {
31
- throw new Error('The file is encrypted. Please set the METAPLAY_AUTH_PASSWORD environment variable.');
32
- }
33
- throw error;
34
- }
35
- }
36
- function encrypt(text) {
37
- const key = scryptSync(password, salt, 32);
38
- const iv = randomBytes(16); // Generate a 16-byte IV
39
- const cipher = createCipheriv(algorithm, key, iv);
40
- const encrypted = Buffer.concat([cipher.update(text), cipher.final()]);
41
- return iv.toString('hex') + ':' + encrypted.toString('hex'); // Store IV with the encrypted data
42
- }
43
- function decrypt(text) {
44
- const textParts = text.split(':');
45
- if (textParts.length !== 2) {
46
- throw new Error('Invalid encrypted data format.');
47
- }
48
- const iv = Buffer.from(textParts[0], 'hex');
49
- if (iv.length !== 16) { // Ensure the IV is 16 bytes
50
- throw new Error('Invalid IV length.');
51
- }
52
- const encryptedText = Buffer.from(textParts[1], 'hex');
53
- const key = scryptSync(password, salt, 32);
54
- const decipher = createDecipheriv(algorithm, key, iv);
55
- const decrypted = Buffer.concat([decipher.update(encryptedText), decipher.final()]);
56
- return decrypted.toString();
57
- }
58
- export async function setSecret(key, value) {
59
- logger.debug(`Setting secret ${key}...`);
60
- const secrets = await loadSecrets();
61
- secrets[key] = value;
62
- const secretJson = JSON.stringify(secrets);
63
- const content = password.length !== 0 ? encrypt(secretJson) : secretJson;
64
- await fs.writeFile(filePath, content);
65
- }
66
- export async function getSecret(key) {
67
- logger.debug(`Getting secret ${key}...`);
68
- const secrets = await loadSecrets();
69
- return secrets[key];
70
- }
71
- export async function removeSecret(key) {
72
- logger.debug(`Removing secret ${key}...`);
73
- const currentSecrets = await loadSecrets();
74
- const { [key]: _, ...secrets } = currentSecrets; // remove key from secrets
75
- const secretJson = JSON.stringify(secrets);
76
- const content = password.length !== 0 ? encrypt(secretJson) : secretJson;
77
- await fs.writeFile(filePath, content);
78
- }
79
- //# sourceMappingURL=secret_store.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"secret_store.js","sourceRoot":"","sources":["../../src/secret_store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAA;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAClF,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAA;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAErC,MAAM,QAAQ,GAAW,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,qBAAqB,CAAC,CAAA;AACjG,MAAM,SAAS,GAAG,aAAa,CAAA;AAC/B,MAAM,QAAQ,GAAW,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,EAAE,CAAA;AACjE,MAAM,IAAI,GAAW,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,WAAW,CAAA;AAIlE,KAAK,UAAU,WAAW;IACxB,IAAI;QACF,MAAM,CAAC,KAAK,CAAC,wBAAwB,QAAQ,KAAK,CAAC,CAAA;QAEnD,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACzB,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;QAEhD,oDAAoD;QACpD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;YACzB,MAAM,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAA;YAC9D,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;SACxB;QAED,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAA;QAClC,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QAEnC,OAAO,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAA;KACjC;IAAC,OAAO,KAAK,EAAE;QACd,MAAM,SAAS,GAAG,KAA8B,CAAA;QAChD,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ,EAAE;YAC/B,sDAAsD;YACtD,OAAO,EAAE,CAAA;SACV;QACD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;YACzB,MAAM,IAAI,KAAK,CAAC,oFAAoF,CAAC,CAAA;SACtG;QACD,MAAM,KAAK,CAAA;KACZ;AACH,CAAC;AAED,SAAS,OAAO,CAAE,IAAY;IAC5B,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,CAAA;IAC1C,MAAM,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC,CAAA,CAAC,wBAAwB;IACnD,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IACtE,OAAO,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA,CAAC,mCAAmC;AACjG,CAAC;AAED,SAAS,OAAO,CAAE,IAAY;IAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACjC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;QAC1B,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;KAClD;IACD,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;IAC3C,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE,EAAE,EAAE,4BAA4B;QAClD,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAA;KACtC;IACD,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;IACtD,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,CAAA;IAC1C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,CAAC,CAAA;IACrD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IACnF,OAAO,SAAS,CAAC,QAAQ,EAAE,CAAA;AAC7B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAE,GAAW,EAAE,KAAU;IACtD,MAAM,CAAC,KAAK,CAAC,kBAAkB,GAAG,KAAK,CAAC,CAAA;IAExC,MAAM,OAAO,GAAG,MAAM,WAAW,EAAE,CAAA;IACnC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;IACpB,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IAC1C,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAA;IACxE,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;AACvC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAE,GAAW;IAC1C,MAAM,CAAC,KAAK,CAAC,kBAAkB,GAAG,KAAK,CAAC,CAAA;IAExC,MAAM,OAAO,GAAG,MAAM,WAAW,EAAE,CAAA;IACnC,OAAO,OAAO,CAAC,GAAG,CAAC,CAAA;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAE,GAAW;IAC7C,MAAM,CAAC,KAAK,CAAC,mBAAmB,GAAG,KAAK,CAAC,CAAA;IAEzC,MAAM,cAAc,GAAG,MAAM,WAAW,EAAE,CAAA;IAC1C,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,cAAc,CAAA,CAAC,0BAA0B;IAE1E,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IAC1C,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAA;IACxE,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;AACvC,CAAC"}
@@ -1,264 +0,0 @@
1
- import { isValidFQDN, getGameserverAdminUrl } from './utils.js';
2
- import { logger } from './logging.js';
3
- import { dump } from 'js-yaml';
4
- import { getUserinfo } from './auth.js';
5
- export class StackAPI {
6
- accessToken;
7
- _stackApiBaseUrl;
8
- constructor(accessToken, stackApiBaseUrl) {
9
- if (accessToken == null) {
10
- throw new Error('accessToken must be provided');
11
- }
12
- this.accessToken = accessToken;
13
- if (stackApiBaseUrl) {
14
- this._stackApiBaseUrl = stackApiBaseUrl.replace(/\/$/, ''); // Remove trailing slash
15
- }
16
- else {
17
- this._stackApiBaseUrl = 'https://infra.p1.metaplay.io/stackapi';
18
- }
19
- }
20
- async getAwsCredentials(gs) {
21
- let url = '';
22
- if (gs.gameserver != null) {
23
- if (isValidFQDN(gs.gameserver)) {
24
- const adminUrl = getGameserverAdminUrl(gs.gameserver);
25
- url = `https://${adminUrl}/.infra/credentials/aws`;
26
- }
27
- else {
28
- url = `${this._stackApiBaseUrl}/v0/credentials/${gs.gameserver}/aws`;
29
- }
30
- }
31
- else if (gs.organization != null && gs.project != null && gs.environment != null) {
32
- url = `${this._stackApiBaseUrl}/v1/servers/${gs.organization}/${gs.project}/${gs.environment}/credentials/aws`;
33
- }
34
- else {
35
- throw new Error('Invalid arguments for getAwsCredentials');
36
- }
37
- logger.debug(`Getting AWS credentials from ${url}...`);
38
- const response = await fetch(url, {
39
- method: 'POST',
40
- headers: {
41
- Authorization: `Bearer ${this.accessToken}`,
42
- 'Content-Type': 'application/json'
43
- }
44
- });
45
- if (response.status !== 200) {
46
- throw new Error(`Failed to fetch AWS credentials: ${response.statusText}, response code=${response.status}`);
47
- }
48
- return await response.json();
49
- }
50
- async getKubeConfig(gs) {
51
- let url = '';
52
- if (gs.gameserver != null) {
53
- if (isValidFQDN(gs.gameserver)) {
54
- const adminUrl = getGameserverAdminUrl(gs.gameserver);
55
- url = `https://${adminUrl}/.infra/credentials/k8s`;
56
- }
57
- else {
58
- url = `${this._stackApiBaseUrl}/v0/credentials/${gs.gameserver}/k8s`;
59
- }
60
- }
61
- else if (gs.organization != null && gs.project != null && gs.environment != null) {
62
- url = `${this._stackApiBaseUrl}/v1/servers/${gs.organization}/${gs.project}/${gs.environment}/credentials/k8s`;
63
- }
64
- else {
65
- throw new Error('Invalid arguments for getKubeConfig');
66
- }
67
- logger.debug(`Getting KubeConfig from ${url}...`);
68
- let response;
69
- try {
70
- response = await fetch(url, {
71
- method: 'POST',
72
- headers: {
73
- Authorization: `Bearer ${this.accessToken}`,
74
- 'Content-Type': 'application/json'
75
- }
76
- });
77
- }
78
- catch (error) {
79
- logger.error(`Failed to fetch kubeconfig from ${url}`);
80
- logger.error('Fetch error details:', error);
81
- if (error.cause?.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {
82
- throw new Error(`Failed to to fetch kubeconfig: SSL certificate validation failed for ${url}. Is someone trying to tamper with your internet connection?`);
83
- }
84
- throw new Error(`Failed to fetch kubeconfig from ${url}: ${error}`);
85
- }
86
- if (response.status !== 200) {
87
- throw new Error(`Failed to fetch KubeConfigs: ${response.statusText}`);
88
- }
89
- return await response.text();
90
- }
91
- /**
92
- * Get a `kubeconfig` payload which invokes `metaplay-auth get-kubernetes-execcredential` to get the actual
93
- * access credentials each time the kubeconfig is used.
94
- * @param gs Game server environment to get credentials for.
95
- * @returns The kubeconfig YAML.
96
- */
97
- async getKubeConfigExecCredential(gs) {
98
- let url = '';
99
- let gsSlug = '';
100
- const execArgs = ['get-kubernetes-execcredential'];
101
- if (gs.gameserver != null) {
102
- const adminUrl = getGameserverAdminUrl(gs.gameserver);
103
- url = `https://${adminUrl}/.infra/credentials/k8s?type=execcredential`;
104
- gsSlug = gs.gameserver;
105
- execArgs.push('--gameserver', gs.gameserver);
106
- }
107
- else if (gs.organization != null && gs.project != null && gs.environment != null) {
108
- url = `${this._stackApiBaseUrl}/v1/servers/${gs.organization}/${gs.project}/${gs.environment}/credentials/k8s?type=execcredential`;
109
- gsSlug = `${gs.organization}.${gs.project}.${gs.environment}`;
110
- execArgs.push(`${gs.organization}-${gs.project}-${gs.environment}`);
111
- }
112
- else {
113
- throw new Error('Invalid arguments for getKubeConfigExecCredential');
114
- }
115
- logger.debug(`Getting Kubernetes KubeConfig from ${url}...`);
116
- let response;
117
- try {
118
- response = await fetch(url, {
119
- method: 'POST',
120
- headers: {
121
- Authorization: `Bearer ${this.accessToken}`,
122
- 'Content-Type': 'application/json'
123
- }
124
- });
125
- }
126
- catch (error) {
127
- logger.error(`Failed to fetch kubeconfig from ${url}`);
128
- logger.error('Fetch error details:', error);
129
- if (error.cause?.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {
130
- throw new Error(`Failed to to fetch kubeconfig: SSL certificate validation failed for ${url}. Is someone trying to tamper with your internet connection?`);
131
- }
132
- throw new Error(`Failed to fetch kubeconfig from ${url}: ${error}`);
133
- }
134
- if (response.status !== 200) {
135
- throw new Error(`Failed to fetch Kubernetes KubeConfig: ${response.statusText}`);
136
- }
137
- // get the execcredential and morph it into a kubeconfig which calls metaplay-auth for the token
138
- let kubeExecCredential;
139
- try {
140
- kubeExecCredential = await response.json();
141
- }
142
- catch {
143
- throw new Error('Failed to fetch Kubernetes KubeConfig: the server response is not JSON');
144
- }
145
- if (!kubeExecCredential.spec.cluster) {
146
- throw new Error('Received kubeExecCredential with missing spec.cluster');
147
- }
148
- let namespace = 'default';
149
- let user = 'user';
150
- try {
151
- const environment = await this.getEnvironmentDetails(gs);
152
- namespace = environment.deployment?.kubernetes_namespace ?? namespace;
153
- }
154
- catch (e) {
155
- logger.debug('Failed to get environment details, using defaults', e);
156
- }
157
- try {
158
- const userinfo = await getUserinfo(this.accessToken);
159
- user = userinfo.sub ?? user;
160
- }
161
- catch (e) {
162
- logger.debug('Failed to get userinfo, using defaults', e);
163
- }
164
- const kubeConfig = {
165
- apiVersion: 'v1',
166
- kind: 'Config',
167
- 'current-context': gsSlug,
168
- clusters: [
169
- {
170
- cluster: {
171
- 'certificate-authority-data': kubeExecCredential.spec.cluster.certificateAuthorityData,
172
- server: kubeExecCredential.spec.cluster.server
173
- },
174
- name: kubeExecCredential.spec.cluster.server
175
- }
176
- ],
177
- contexts: [
178
- {
179
- context: {
180
- cluster: kubeExecCredential.spec.cluster.server,
181
- namespace,
182
- user
183
- },
184
- name: gsSlug,
185
- }
186
- ],
187
- users: [
188
- {
189
- name: user,
190
- user: {
191
- exec: {
192
- apiVersion: 'client.authentication.k8s.io/v1beta1',
193
- command: 'metaplay-auth',
194
- args: execArgs,
195
- }
196
- }
197
- }
198
- ],
199
- };
200
- // return as yaml for easier consumption
201
- return dump(kubeConfig);
202
- }
203
- async getKubeExecCredential(gs) {
204
- let url = '';
205
- if (gs.gameserver != null) {
206
- if (isValidFQDN(gs.gameserver)) {
207
- const adminUrl = getGameserverAdminUrl(gs.gameserver);
208
- url = `https://${adminUrl}/.infra/credentials/k8s?type=execcredential`;
209
- }
210
- else {
211
- url = `${this._stackApiBaseUrl}/v0/credentials/${gs.gameserver}/k8s?type=execcredential`;
212
- }
213
- }
214
- else if (gs.organization != null && gs.project != null && gs.environment != null) {
215
- url = `${this._stackApiBaseUrl}/v1/servers/${gs.organization}/${gs.project}/${gs.environment}/credentials/k8s?type=execcredential`;
216
- }
217
- else {
218
- throw new Error('Invalid arguments for getKubeConfig');
219
- }
220
- logger.debug(`Getting Kubernetes ExecCredential from ${url}...`);
221
- const response = await fetch(url, {
222
- method: 'POST',
223
- headers: {
224
- Authorization: `Bearer ${this.accessToken}`,
225
- 'Content-Type': 'application/json'
226
- }
227
- });
228
- if (response.status !== 200) {
229
- throw new Error(`Failed to fetch Kubernetes ExecCredential: ${response.statusText}`);
230
- }
231
- return await response.text();
232
- }
233
- async getEnvironmentDetails(gs) {
234
- let url = '';
235
- if (gs.gameserver != null) {
236
- if (isValidFQDN(gs.gameserver)) {
237
- const adminUrl = getGameserverAdminUrl(gs.gameserver);
238
- url = `https://${adminUrl}/.infra/environment`;
239
- }
240
- else {
241
- url = `${this._stackApiBaseUrl}/v0/deployments/${gs.gameserver}`;
242
- }
243
- }
244
- else if (gs.organization != null && gs.project != null && gs.environment != null) {
245
- url = `${this._stackApiBaseUrl}/v1/servers/${gs.organization}/${gs.project}/${gs.environment}`;
246
- }
247
- else {
248
- throw new Error('Invalid arguments for environment details');
249
- }
250
- logger.debug(`Getting environment details from ${url}...`);
251
- const response = await fetch(url, {
252
- method: 'GET',
253
- headers: {
254
- Authorization: `Bearer ${this.accessToken}`,
255
- 'Content-Type': 'application/json'
256
- }
257
- });
258
- if (response.status !== 200) {
259
- throw new Error(`Failed to fetch environment details: ${response.statusText}`);
260
- }
261
- return await response.json();
262
- }
263
- }
264
- //# sourceMappingURL=stackapi.js.map