UNPKG

@xrengine/server-core

Version:

Shared components for XREngine server

250 lines (214 loc) 6.58 kB
import * as k8s from '@kubernetes/client-node' import { Op } from 'sequelize' import { Channel } from '@xrengine/common/src/interfaces/Channel' import { Instance } from '@xrengine/common/src/interfaces/Instance' import { ServerContainerInfo, ServerInfoInterface, ServerPodInfo } from '@xrengine/common/src/interfaces/ServerInfo' import { Application } from '../../../declarations' import config from '../../appconfig' import logger from '../../ServerLogger' export const getServerInfo = async (app: Application): Promise<ServerInfoInterface[]> => { let serverInfo: ServerInfoInterface[] = [] try { logger.info('Attempting to check k8s server info') if (app.k8DefaultClient) { const builderPods = await getPodsData( `app.kubernetes.io/instance=${config.server.releaseName}-builder`, 'builder', 'Builder', app ) serverInfo.push(builderPods) const clientPods = await getPodsData( `app.kubernetes.io/instance=${config.server.releaseName},app.kubernetes.io/component=client`, 'client', 'Client', app ) serverInfo.push(clientPods) const apiPods = await getPodsData( `app.kubernetes.io/instance=${config.server.releaseName},app.kubernetes.io/component=api`, 'api', 'Api', app ) serverInfo.push(apiPods) const instancePods = await getPodsData( 'agones.dev/role=gameserver', 'instance', 'Instance', app, `${config.server.releaseName}-instanceserver-` ) await populateInstanceServerType(app, instancePods.pods) serverInfo.push(instancePods) const taskPods = await getPodsData( `app.kubernetes.io/instance=${config.server.releaseName},app.kubernetes.io/component=taskserver`, 'task', 'Task', app ) serverInfo.push(taskPods) const projectUpdatePods = await getPodsData( `etherealengine/release=${config.server.releaseName},etherealengine/projectUpdater=true`, 'projectUpdate', 'Project Updater', app ) serverInfo.push(projectUpdatePods) } // if (app.k8AgonesClient) { // const instancePods = await getGameserversData(`agones.dev/fleet=${config.server.releaseName}-instanceserver`, 'instance', 'Instance', app) // serverInfo.push(instancePods) // } } catch (e) { logger.error(e) return e } return serverInfo } export const removePod = async (app: Application, podName: string): Promise<ServerPodInfo | undefined> => { try { logger.info(`Attempting to remove k8s pod ${podName}`) if (app.k8DefaultClient) { const podsResponse = await app.k8DefaultClient.deleteNamespacedPod(podName, 'default') const pod = getServerPodInfo(podsResponse.body) return pod } } catch (e) { logger.error(e) return e } } export const getPodsData = async ( labelSelector: string, id: string, label: string, app: Application, nameFilter?: string ) => { let pods: ServerPodInfo[] = [] try { const podsResponse = await app.k8DefaultClient.listNamespacedPod( 'default', undefined, false, undefined, undefined, labelSelector ) let items = podsResponse.body.items if (nameFilter) { items = items.filter((item) => item.metadata?.name?.startsWith(nameFilter)) } pods = getServerPodsInfo(items) } catch (err) { logger.error('Failed to get pods info.', err) } return { id, label, pods } } const getGameserversData = async (labelSelector: string, id: string, label: string, app: Application) => { let gameservers: ServerPodInfo[] = [] try { const gameserversResponse = await app.k8AgonesClient.listNamespacedCustomObject( 'agones.dev', 'v1', 'default', 'gameservers', undefined, false, undefined, undefined, labelSelector ) gameservers = getServerPodsInfo((gameserversResponse.body as any).items) } catch (err) { logger.error('Failed to get pods info.', err) } return { id, label, pods: gameservers } } const getServerPodsInfo = (items: k8s.V1Pod[]) => { return items.map((item) => { return getServerPodInfo(item) }) } const getServerPodInfo = (item: k8s.V1Pod) => { return { name: item.metadata?.name, status: item.status?.phase, age: item.status?.startTime, containers: getServerContainerInfo(item.status?.containerStatuses!) } as ServerPodInfo } const getServerContainerInfo = (items: k8s.V1ContainerStatus[]) => { return items.map((item) => { return { name: item.name, status: item.state?.running ? 'Running' : item.state?.terminated ? 'Terminated' : item.state?.waiting ? 'Waiting' : 'Undefined', ready: item.ready, started: item.started, restarts: item.restartCount, image: item.image } as ServerContainerInfo }) } const populateInstanceServerType = async (app: Application, items: ServerPodInfo[]) => { if (items.length === 0) { return } const instances = (await app.service('instance').Model.findAll({ where: { ended: false }, include: [ { model: app.service('location').Model, required: false } ] })) as Instance[] if (instances.length === 0) { return } const channelInstances = instances.filter((item) => item.channelId) let channels: Channel[] = [] if (channelInstances) { channels = (await app.service('channel').Model.findAll({ where: { instanceId: { [Op.in]: channelInstances.map((item) => item.channelId) } } })) as Channel[] } for (const item of items) { const instanceExists = instances.find((instance) => instance.podName === item.name) item.instanceId = instanceExists ? instanceExists.id : '' item.currentUsers = instanceExists ? instanceExists.currentUsers : 0 if (instanceExists && instanceExists.locationId) { item.type = `World (${instanceExists.location.name})` item.locationSlug = instanceExists.location.slugifiedName } else if (instanceExists && instanceExists.channelId) { item.type = 'Media' const channelExists = channels.find((channel) => channel.instanceId === instanceExists.id) if (channelExists && channelExists.channelType) { item.type = `Media (${channelExists.channelType})` } } else { item.type = 'Unassigned' } } }