diff --git a/dist/index.js b/dist/index.js index 1d3dcd24..ee958f34 100644 Binary files a/dist/index.js and b/dist/index.js differ diff --git a/dist/index.js.map b/dist/index.js.map index 83cdd4d3..69eec677 100644 Binary files a/dist/index.js.map and b/dist/index.js.map differ diff --git a/src/model/cloud-runner/providers/k8s/index.ts b/src/model/cloud-runner/providers/k8s/index.ts index 8151271e..12c734da 100644 --- a/src/model/cloud-runner/providers/k8s/index.ts +++ b/src/model/cloud-runner/providers/k8s/index.ts @@ -16,7 +16,6 @@ import { ProviderResource } from '../provider-resource'; import { ProviderWorkflow } from '../provider-workflow'; import { RemoteClientLogger } from '../../remote-client/remote-client-logger'; import { KubernetesRole } from './kubernetes-role'; -import KubernetesLogService from './kubernetes-log-service'; import { CloudRunnerSystem } from '../../services/core/cloud-runner-system'; class Kubernetes implements ProviderInterface { @@ -159,8 +158,6 @@ class Kubernetes implements ProviderInterface { await KubernetesSecret.createSecret(secrets, this.secretName, this.namespace, this.kubeClient); let output = ''; try { - this.ip = - (await KubernetesLogService.createLogDeployment(this.namespace, this.kubeClientApps, this.kubeClient)) || ``; CloudRunnerLogger.log('Job does not exist'); await this.createJob(commands, image, mountdir, workingdir, environment, secrets); CloudRunnerLogger.log('Watching pod until running'); @@ -271,7 +268,6 @@ class Kubernetes implements ProviderInterface { CloudRunnerLogger.log(`Build job created`); await new Promise((promise) => setTimeout(promise, 5000)); CloudRunnerLogger.log('Job created'); - await KubernetesLogService.cleanupLogDeployment(this.namespace, this.kubeClientApps, this.kubeClient); return result.body.metadata?.name; } catch (error) { @@ -292,7 +288,6 @@ class Kubernetes implements ProviderInterface { await this.kubeClientBatch.deleteNamespacedJob(this.jobName, this.namespace); await this.kubeClient.deleteNamespacedPod(this.podName, this.namespace); await KubernetesRole.deleteRole(this.serviceAccountName, this.namespace, this.rbacAuthorizationV1Api); - await KubernetesLogService.cleanupLogDeployment(this.namespace, this.kubeClientApps, this.kubeClient); } catch (error: any) { CloudRunnerLogger.log(`Failed to cleanup`); if (error.response.body.reason !== `NotFound`) { diff --git a/src/model/cloud-runner/providers/k8s/kubernetes-log-service.ts b/src/model/cloud-runner/providers/k8s/kubernetes-log-service.ts deleted file mode 100644 index eb118237..00000000 --- a/src/model/cloud-runner/providers/k8s/kubernetes-log-service.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { CoreV1Api } from '@kubernetes/client-node'; -import * as k8s from '@kubernetes/client-node'; -import CloudRunnerLogger from '../../services/core/cloud-runner-logger'; -import { CloudRunnerSystem } from '../../services/core/cloud-runner-system'; -class KubernetesLogService { - static async cleanupLogDeployment(namespace: string, kubeClientApps: k8s.AppsV1Api, kubeClient: CoreV1Api) { - if (!process.env.LOG_SERVICE_IP) { - return Promise.resolve(); - } - await kubeClient.deleteNamespacedService('http-fileserver', namespace); - await kubeClientApps.deleteNamespacedDeployment('http-fileserver', namespace); - } - - static async createLogService(serviceAccountName: string, namespace: string, kubeClient: CoreV1Api) { - const serviceAccount = new k8s.V1ServiceAccount(); - serviceAccount.apiVersion = 'v1'; - serviceAccount.kind = 'ServiceAccount'; - serviceAccount.metadata = { - name: serviceAccountName, - }; - serviceAccount.automountServiceAccountToken = true; - - return kubeClient.createNamespacedServiceAccount(namespace, serviceAccount); - } - - static async createLogDeployment(namespace: string, kubeClient: k8s.AppsV1Api, kubeClientCore: CoreV1Api) { - if (!process.env.LOG_SERVICE_IP) { - return `0.0.0.0`; - } - - // create a deployment with above json - const deployment = new k8s.V1Deployment(); - deployment.apiVersion = 'apps/v1'; - deployment.kind = 'Deployment'; - deployment.metadata = { - name: 'http-fileserver', - labels: { - service: 'http-fileserver', - }, - }; - deployment.spec = { - selector: { - matchLabels: { - service: 'http-fileserver', - }, - }, - replicas: 1, - strategy: {}, - template: { - metadata: { - labels: { - service: 'http-fileserver', - }, - }, - spec: { - containers: [ - { - image: 'node:18', - imagePullPolicy: 'Always', - name: 'http-fileserver', - ports: [{ containerPort: 80 }], - command: [ - 'bash', - '-c', - 'while true; do sleep 30; npm i files-upload-server -g; files-upload-server "downloads"; done;', - ], - resources: { - requests: { - memory: '750M', - cpu: '0.25', - }, - }, - }, - ], - restartPolicy: 'Always', - }, - }, - }; - await kubeClient.createNamespacedDeployment(namespace, deployment); - await this.createLogServiceExpose(namespace, kubeClientCore); - - // wait in loop until serivce ip address is exposed - - for (let index = 0; index < 10; index++) { - // wait for service to share ip address - await new Promise((resolve) => setTimeout(resolve, 10000)); - - // get cluster ip address of service - const service = await kubeClientCore.readNamespacedService('http-fileserver', namespace); - - // get podname of deployment - - const podname = await CloudRunnerSystem.Run( - `kubectl get pods -n ${namespace} -l service=http-fileserver -o jsonpath='{.items[0].metadata.name}'`, - false, - true, - ); - - // if status of pod is not running, then continue - const podStatus = await CloudRunnerSystem.Run( - `kubectl get pods -n ${namespace} ${podname} -o jsonpath='{.status.phase}'`, - false, - true, - ); - if (podStatus !== 'Running') { - CloudRunnerLogger.log(`Pod status: ${podStatus}`); - continue; - } - - const logs = await CloudRunnerSystem.Run(`kubectl logs ${podname} -f --timestamps -p`, false, true); - CloudRunnerLogger.log(`Logs: ${logs}`); - - // get cluster ip - const ip = service.body?.spec?.clusterIP; - if (ip && ip.length > 0) { - // log service json - CloudRunnerLogger.log(`Service: ${JSON.stringify(service.body, undefined, 4)}`); - CloudRunnerLogger.log(`Service IP: ${ip}`); - - return ip; - } - } - } - - // create kubernetes service to expose deployment - static async createLogServiceExpose(namespace: string, kubeClient: CoreV1Api) { - if (!process.env.LOG_SERVICE_IP) { - return; - } - - // create a service with above json - const service = new k8s.V1Service(); - service.apiVersion = 'v1'; - service.kind = 'Service'; - service.metadata = { - name: 'http-fileserver', - labels: { - service: 'http-fileserver', - }, - }; - service.spec = { - ports: [ - { - name: '80-80', - port: 80, - protocol: 'TCP', - targetPort: 80, - }, - ], - selector: { - service: 'http-fileserver', - }, - type: 'LoadBalancer', - }; - await kubeClient.createNamespacedService(namespace, service); - } -} -export default KubernetesLogService; diff --git a/src/model/cloud-runner/remote-client/index.ts b/src/model/cloud-runner/remote-client/index.ts index a1d11556..64ccdb2a 100644 --- a/src/model/cloud-runner/remote-client/index.ts +++ b/src/model/cloud-runner/remote-client/index.ts @@ -83,7 +83,7 @@ export class RemoteClient { await RemoteClient.runCustomHookFiles(`after-build`); // WIP - need to give the pod permissions to create config map - await RemoteClientLogger.printCollectedLogs(); + await RemoteClientLogger.handleLogManagementPostJob(); return new Promise((result) => result(``)); } diff --git a/src/model/cloud-runner/remote-client/remote-client-logger.ts b/src/model/cloud-runner/remote-client/remote-client-logger.ts index 84c1b7f6..3ebbca7f 100644 --- a/src/model/cloud-runner/remote-client/remote-client-logger.ts +++ b/src/model/cloud-runner/remote-client/remote-client-logger.ts @@ -3,7 +3,6 @@ import fs from 'node:fs'; import path from 'node:path'; import CloudRunner from '../cloud-runner'; import CloudRunnerOptions from '../options/cloud-runner-options'; -import Kubernetes from '../providers/k8s'; export class RemoteClientLogger { private static get LogFilePath() { @@ -34,14 +33,20 @@ export class RemoteClientLogger { } } - public static async printCollectedLogs() { + public static async handleLogManagementPostJob() { if (CloudRunnerOptions.providerStrategy !== 'k8s') { return; } CloudRunnerLogger.log(`Collected Logs`); - CloudRunnerLogger.log(process.env[`LOG_SERVICE_IP`] || ``); + const hashedLogs = fs.readFileSync(RemoteClientLogger.LogFilePath).toString(); + CloudRunnerLogger.log(hashedLogs); const logs = fs.readFileSync(RemoteClientLogger.LogFilePath).toString(); CloudRunnerLogger.log(logs); - await Kubernetes.Instance.PushLogUpdate(logs); + + // loop for 5 mins logging the logs every minute + for (let index = 0; index < 5; index++) { + await new Promise((resolve) => setTimeout(resolve, 60000)); + CloudRunnerLogger.log(logs); + } } } diff --git a/src/model/cloud-runner/tests/cloud-runner-kubernetes.test.ts b/src/model/cloud-runner/tests/cloud-runner-kubernetes.test.ts deleted file mode 100644 index d51c26ce..00000000 --- a/src/model/cloud-runner/tests/cloud-runner-kubernetes.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -import BuildParameters from '../../build-parameters'; -import { Cli } from '../../cli/cli'; -import UnityVersioning from '../../unity-versioning'; -import CloudRunner from '../cloud-runner'; -import CloudRunnerOptions from '../options/cloud-runner-options'; -import KubernetesLogService from '../providers/k8s/kubernetes-log-service'; -import CloudRunnerLogger from '../services/core/cloud-runner-logger'; -import setups from './cloud-runner-suite.test'; -import { v4 as uuidv4 } from 'uuid'; -import * as k8s from '@kubernetes/client-node'; -import ImageTag from '../../image-tag'; - -async function CreateParameters(overrides: any) { - if (overrides) { - Cli.options = overrides; - } - - return await BuildParameters.create(); -} - -describe('Cloud Runner Kubernetes', () => { - it('Responds', () => {}); - setups(); - if (CloudRunnerOptions.cloudRunnerDebug) { - it('Build create log service', async () => { - const overrides = { - versioning: 'None', - projectPath: 'test-project', - unityVersion: UnityVersioning.determineUnityVersion('test-project', UnityVersioning.read('test-project')), - targetPlatform: 'StandaloneLinux64', - cacheKey: `test-case-${uuidv4()}`, - customJob: ` - - name: 'step 1' - image: 'ubuntu' - commands: 'curl http://$LOG_SERVICE_IP:80''`, - }; - if (CloudRunnerOptions.providerStrategy !== `k8s`) { - return; - } - const buildParameter = await CreateParameters(overrides); - expect(buildParameter.projectPath).toEqual(overrides.projectPath); - - await CloudRunner.setup(buildParameter); - const kubeConfig = new k8s.KubeConfig(); - kubeConfig.loadFromDefault(); - const kubeClient = kubeConfig.makeApiClient(k8s.CoreV1Api); - const kubeClientApps = kubeConfig.makeApiClient(k8s.AppsV1Api); - - await KubernetesLogService.createLogDeployment('test', kubeClientApps, kubeClient); - - CloudRunnerLogger.log(`run 1 succeeded`); - }, 1_000_000_000); - it('curl log service', async () => { - const overrides = { - versioning: 'None', - projectPath: 'test-project', - unityVersion: UnityVersioning.read('test-project'), - targetPlatform: 'StandaloneLinux64', - cacheKey: `test-case-${uuidv4()}`, - customJob: ` - - name: 'step 1' - image: 'ubuntu' - commands: | - apt-get update - apt-get install curl -y - curl http://$LOG_SERVICE_IP:80`, - }; - if (CloudRunnerOptions.providerStrategy !== `k8s`) { - return; - } - const buildParameter = await CreateParameters(overrides); - expect(buildParameter.projectPath).toEqual(overrides.projectPath); - - const baseImage = new ImageTag(buildParameter); - const results = await CloudRunner.run(buildParameter, baseImage.toString()); - const buildSucceededString = 'Build succeeded'; - expect(results).toContain(buildSucceededString); - - CloudRunnerLogger.log(`run 1 succeeded`); - }, 1_000_000_000); - } -});