Log stream attempt #2

pull/273/head
Frostebite 2021-06-06 03:01:49 +01:00
parent 926e500b89
commit 464e5f0caa
3 changed files with 120 additions and 175 deletions

222
dist/index.js vendored
View File

@ -729,7 +729,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}); });
}; };
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
// @ts-ignore
const k8s = __importStar(__webpack_require__(89679)); const k8s = __importStar(__webpack_require__(89679));
const core = __importStar(__webpack_require__(42186)); const core = __importStar(__webpack_require__(42186));
const base64 = __webpack_require__(85848); const base64 = __webpack_require__(85848);
@ -743,11 +742,6 @@ class Kubernetes {
const k8sApi = kc.makeApiClient(k8s.CoreV1Api); const k8sApi = kc.makeApiClient(k8s.CoreV1Api);
const k8sBatchApi = kc.makeApiClient(k8s.BatchV1Api); const k8sBatchApi = kc.makeApiClient(k8s.BatchV1Api);
core.info('loaded from default'); core.info('loaded from default');
// const kubeconfig = new KubeConfig();
// kubeconfig.loadFromString(base64.decode(buildParameters.kubeConfig));
// const backend = new Request({ kubeconfig });
// const kubeClient = new Client(backend);
// await kubeClient.loadSpec();
const buildId = Kubernetes.uuidv4(); const buildId = Kubernetes.uuidv4();
const pvcName = `unity-builder-pvc-${buildId}`; const pvcName = `unity-builder-pvc-${buildId}`;
const secretName = `build-credentials-${buildId}`; const secretName = `build-credentials-${buildId}`;
@ -1028,12 +1022,12 @@ class Kubernetes {
}); });
} }
static watchBuildJobUntilFinished() { static watchBuildJobUntilFinished() {
var _a, _b; var _a, _b, _c, _d;
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
try { try {
const pod = yield Kubernetes.watchPodUntilRunningAndRead(); const pod = yield Kubernetes.watchPodUntilRunningAndRead();
core.info(`Watching build job ${(_a = pod === null || pod === void 0 ? void 0 : pod.metadata) === null || _a === void 0 ? void 0 : _a.name}`); core.info(`Watching build job ${(_a = pod === null || pod === void 0 ? void 0 : pod.metadata) === null || _a === void 0 ? void 0 : _a.name}`);
yield Kubernetes.streamLogs(((_b = pod === null || pod === void 0 ? void 0 : pod.metadata) === null || _b === void 0 ? void 0 : _b.name) || '', this.namespace); yield Kubernetes.streamLogs(((_b = pod === null || pod === void 0 ? void 0 : pod.metadata) === null || _b === void 0 ? void 0 : _b.name) || '', this.namespace, ((_d = (_c = pod === null || pod === void 0 ? void 0 : pod.status) === null || _c === void 0 ? void 0 : _c.containerStatuses) === null || _d === void 0 ? void 0 : _d[0].name) || '');
} }
catch (error) { catch (error) {
core.error('Failed while watching build job'); core.error('Failed while watching build job');
@ -1041,45 +1035,21 @@ class Kubernetes {
} }
}); });
} }
static streamLogs(name, namespace) { static streamLogs(name, namespace, container) {
var _a, _b; var _a;
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
try { try {
let running = true; let running = true;
let mostRecentLogTime = 999;
let mostRecentLine = '';
while (running) { while (running) {
const pod = yield this.kubeClient.readNamespacedPod(name, namespace); const pod = yield this.kubeClient.readNamespacedPod(name, namespace);
running = ((_a = pod.body.status) === null || _a === void 0 ? void 0 : _a.phase) === 'Running'; running = ((_a = pod.body.status) === null || _a === void 0 ? void 0 : _a.phase) === 'Running';
yield new Promise((resolve) => setTimeout(resolve, pollInterval)); yield new Promise((resolve) => setTimeout(resolve, pollInterval));
core.info('Polling logs...'); core.info('Polling logs...');
let logs; const logs = yield this.kubeClient.readNamespacedPodLog(name, namespace, container, true, undefined, undefined, undefined, undefined, undefined, undefined, true);
try { logs.response.on('data', (data) => {
logs = yield this.kubeClient.readNamespacedPodLog(name, namespace, undefined, undefined, undefined, undefined, undefined, undefined, mostRecentLogTime, undefined, true); core.info('LOGS RECEIVED');
} core.info(data);
catch (error) { });
core.info(error);
if (error.message === 'HTTP request failed') {
core.info('!warning - K8S HTTP FAILED');
continue;
}
}
const arrayOfLines = (_b = logs === null || logs === void 0 ? void 0 : logs.body.match(/[^\n\r]+/g)) === null || _b === void 0 ? void 0 : _b.reverse();
if (arrayOfLines) {
for (const element of arrayOfLines) {
const [time, ...line] = element.split(' ');
const lineString = line.join(' ');
const lineDate = Date.parse(time);
if (mostRecentLine !== lineString || lineDate > mostRecentLogTime) {
core.info(lineString);
mostRecentLogTime = lineDate;
mostRecentLine = lineString;
}
else {
break;
}
}
}
} }
} }
catch (error) { catch (error) {
@ -1745,60 +1715,60 @@ class RemoteBuilder {
core.info('Starting step 1/4 clone and restore cache)'); core.info('Starting step 1/4 clone and restore cache)');
yield aws_build_platform_1.default.runBuild(buildUid, buildParameters.awsStackName, 'alpine/git', [ yield aws_build_platform_1.default.runBuild(buildUid, buildParameters.awsStackName, 'alpine/git', [
'-c', '-c',
`apk update; `apk update;
apk add unzip; apk add unzip;
apk add git-lfs; apk add git-lfs;
apk add jq; apk add jq;
# Get source repo for project to be built and game-ci repo for utilties # Get source repo for project to be built and game-ci repo for utilties
git clone https://${buildParameters.githubToken}@github.com/${process.env.GITHUB_REPOSITORY}.git ${buildUid}/${repositoryDirectoryName} -q git clone https://${buildParameters.githubToken}@github.com/${process.env.GITHUB_REPOSITORY}.git ${buildUid}/${repositoryDirectoryName} -q
git clone https://${buildParameters.githubToken}@github.com/game-ci/unity-builder.git ${buildUid}/builder -q git clone https://${buildParameters.githubToken}@github.com/game-ci/unity-builder.git ${buildUid}/builder -q
git clone https://${buildParameters.githubToken}@github.com/game-ci/steam-deploy.git ${buildUid}/steam -q git clone https://${buildParameters.githubToken}@github.com/game-ci/steam-deploy.git ${buildUid}/steam -q
cd /${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/ cd /${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/
git checkout $GITHUB_SHA git checkout $GITHUB_SHA
cd /${efsDirectoryName}/ cd /${efsDirectoryName}/
# Look for usable cache # Look for usable cache
if [ ! -d ${cacheDirectoryName} ]; then if [ ! -d ${cacheDirectoryName} ]; then
mkdir ${cacheDirectoryName} mkdir ${cacheDirectoryName}
fi fi
cd ${cacheDirectoryName} cd ${cacheDirectoryName}
if [ ! -d "${branchName}" ]; then if [ ! -d "${branchName}" ]; then
mkdir "${branchName}" mkdir "${branchName}"
fi fi
cd "${branchName}" cd "${branchName}"
echo '' echo ''
echo "Cached Libraries for ${branchName} from previous builds:" echo "Cached Libraries for ${branchName} from previous builds:"
ls ls
echo '' echo ''
ls "/${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/${buildParameters.projectPath}" ls "/${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/${buildParameters.projectPath}"
libDir="/${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/${buildParameters.projectPath}/Library" libDir="/${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/${buildParameters.projectPath}/Library"
if [ -d "$libDir" ]; then if [ -d "$libDir" ]; then
rm -r "$libDir" rm -r "$libDir"
echo "Setup .gitignore to ignore Library folder and remove it from builds" echo "Setup .gitignore to ignore Library folder and remove it from builds"
fi fi
echo 'Checking cache' echo 'Checking cache'
# Restore cache # Restore cache
latest=$(ls -t | head -1) latest=$(ls -t | head -1)
if [ ! -z "$latest" ]; then if [ ! -z "$latest" ]; then
echo "Library cache exists from build $latest from ${branchName}" echo "Library cache exists from build $latest from ${branchName}"
echo 'Creating empty Library folder for cache' echo 'Creating empty Library folder for cache'
mkdir $libDir mkdir $libDir
unzip -q $latest -d $libDir unzip -q $latest -d $libDir
# purge cache # purge cache
${process.env.PURGE_REMOTE_BUILDER_CACHE === undefined ? '#' : ''} rm -r $libDir ${process.env.PURGE_REMOTE_BUILDER_CACHE === undefined ? '#' : ''} rm -r $libDir
else else
echo 'Cache does not exist' echo 'Cache does not exist'
fi fi
# Print out important directories # Print out important directories
echo '' echo ''
echo 'Repo:' echo 'Repo:'
ls /${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/ ls /${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/
echo '' echo ''
echo 'Project:' echo 'Project:'
ls /${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/${buildParameters.projectPath} ls /${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/${buildParameters.projectPath}
echo '' echo ''
echo 'Library:' echo 'Library:'
ls /${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/${buildParameters.projectPath}/Library/ ls /${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/${buildParameters.projectPath}/Library/
echo '' echo ''
`, `,
], `/${efsDirectoryName}`, `/${efsDirectoryName}/`, [ ], `/${efsDirectoryName}`, `/${efsDirectoryName}/`, [
{ {
@ -1857,13 +1827,13 @@ class RemoteBuilder {
core.info('Starting part 2/4 (build unity project)'); core.info('Starting part 2/4 (build unity project)');
yield aws_build_platform_1.default.runBuild(buildUid, buildParameters.awsStackName, baseImage.toString(), [ yield aws_build_platform_1.default.runBuild(buildUid, buildParameters.awsStackName, baseImage.toString(), [
'-c', '-c',
` `
cp -r /${efsDirectoryName}/${buildUid}/builder/dist/default-build-script/ /UnityBuilderAction; cp -r /${efsDirectoryName}/${buildUid}/builder/dist/default-build-script/ /UnityBuilderAction;
cp -r /${efsDirectoryName}/${buildUid}/builder/dist/entrypoint.sh /entrypoint.sh; cp -r /${efsDirectoryName}/${buildUid}/builder/dist/entrypoint.sh /entrypoint.sh;
cp -r /${efsDirectoryName}/${buildUid}/builder/dist/steps/ /steps; cp -r /${efsDirectoryName}/${buildUid}/builder/dist/steps/ /steps;
chmod -R +x /entrypoint.sh; chmod -R +x /entrypoint.sh;
chmod -R +x /steps; chmod -R +x /steps;
/entrypoint.sh; /entrypoint.sh;
`, `,
], `/${efsDirectoryName}`, `/${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/`, [ ], `/${efsDirectoryName}`, `/${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/`, [
{ {
@ -1927,18 +1897,18 @@ class RemoteBuilder {
// Cleanup // Cleanup
yield aws_build_platform_1.default.runBuild(buildUid, buildParameters.awsStackName, 'alpine', [ yield aws_build_platform_1.default.runBuild(buildUid, buildParameters.awsStackName, 'alpine', [
'-c', '-c',
` `
apk update apk update
apk add zip apk add zip
cd Library cd Library
zip -r lib-${buildUid}.zip .* zip -r lib-${buildUid}.zip .*
mv lib-${buildUid}.zip /${efsDirectoryName}/${cacheDirectoryName}/${branchName}/lib-${buildUid}.zip mv lib-${buildUid}.zip /${efsDirectoryName}/${cacheDirectoryName}/${branchName}/lib-${buildUid}.zip
cd ../../ cd ../../
ls ls
echo ' ' echo ' '
ls ${buildParameters.buildPath} ls ${buildParameters.buildPath}
zip -r build-${buildUid}.zip ${buildParameters.buildPath}/* zip -r build-${buildUid}.zip ${buildParameters.buildPath}/*
mv build-${buildUid}.zip /${efsDirectoryName}/${buildUid}/build-${buildUid}.zip mv build-${buildUid}.zip /${efsDirectoryName}/${buildUid}/build-${buildUid}.zip
`, `,
], `/${efsDirectoryName}`, `/${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/${buildParameters.projectPath}`, [ ], `/${efsDirectoryName}`, `/${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/${buildParameters.projectPath}`, [
{ {
@ -1954,11 +1924,11 @@ class RemoteBuilder {
core.info('Starting step 4/4 upload build to s3'); core.info('Starting step 4/4 upload build to s3');
yield aws_build_platform_1.default.runBuild(buildUid, buildParameters.awsStackName, 'amazon/aws-cli', [ yield aws_build_platform_1.default.runBuild(buildUid, buildParameters.awsStackName, 'amazon/aws-cli', [
'-c', '-c',
` `
aws s3 cp ${buildUid}/build-${buildUid}.zip s3://game-ci-storage/ aws s3 cp ${buildUid}/build-${buildUid}.zip s3://game-ci-storage/
# no need to upload Library cache for now # no need to upload Library cache for now
# aws s3 cp /${efsDirectoryName}/${cacheDirectoryName}/${branchName}/lib-${buildUid}.zip s3://game-ci-storage/ # aws s3 cp /${efsDirectoryName}/${cacheDirectoryName}/${branchName}/lib-${buildUid}.zip s3://game-ci-storage/
${this.SteamDeploy ? '#' : ''} rm -r ${buildUid} ${this.SteamDeploy ? '#' : ''} rm -r ${buildUid}
`, `,
], `/${efsDirectoryName}`, `/${efsDirectoryName}/`, [ ], `/${efsDirectoryName}`, `/${efsDirectoryName}/`, [
{ {
@ -1989,15 +1959,15 @@ class RemoteBuilder {
core.info('Starting steam deployment'); core.info('Starting steam deployment');
yield aws_build_platform_1.default.runBuild(buildUid, buildParameters.awsStackName, 'cm2network/steamcmd:root', [ yield aws_build_platform_1.default.runBuild(buildUid, buildParameters.awsStackName, 'cm2network/steamcmd:root', [
'-c', '-c',
` `
ls ls
ls / ls /
cp -r /${efsDirectoryName}/${buildUid}/steam/action/entrypoint.sh /entrypoint.sh; cp -r /${efsDirectoryName}/${buildUid}/steam/action/entrypoint.sh /entrypoint.sh;
cp -r /${efsDirectoryName}/${buildUid}/steam/action/steps/ /steps; cp -r /${efsDirectoryName}/${buildUid}/steam/action/steps/ /steps;
chmod -R +x /entrypoint.sh; chmod -R +x /entrypoint.sh;
chmod -R +x /steps; chmod -R +x /steps;
/entrypoint.sh; /entrypoint.sh;
rm -r /${efsDirectoryName}/${buildUid} rm -r /${efsDirectoryName}/${buildUid}
`, `,
], `/${efsDirectoryName}`, `/${efsDirectoryName}/${buildUid}/steam/action/`, [ ], `/${efsDirectoryName}`, `/${efsDirectoryName}/${buildUid}/steam/action/`, [
{ {

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,3 @@
// @ts-ignore
import * as k8s from '@kubernetes/client-node'; import * as k8s from '@kubernetes/client-node';
import { BuildParameters } from '.'; import { BuildParameters } from '.';
import * as core from '@actions/core'; import * as core from '@actions/core';
@ -25,12 +24,6 @@ class Kubernetes {
const k8sBatchApi = kc.makeApiClient(k8s.BatchV1Api); const k8sBatchApi = kc.makeApiClient(k8s.BatchV1Api);
core.info('loaded from default'); core.info('loaded from default');
// const kubeconfig = new KubeConfig();
// kubeconfig.loadFromString(base64.decode(buildParameters.kubeConfig));
// const backend = new Request({ kubeconfig });
// const kubeClient = new Client(backend);
// await kubeClient.loadSpec();
const buildId = Kubernetes.uuidv4(); const buildId = Kubernetes.uuidv4();
const pvcName = `unity-builder-pvc-${buildId}`; const pvcName = `unity-builder-pvc-${buildId}`;
const secretName = `build-credentials-${buildId}`; const secretName = `build-credentials-${buildId}`;
@ -317,60 +310,42 @@ class Kubernetes {
try { try {
const pod = await Kubernetes.watchPodUntilRunningAndRead(); const pod = await Kubernetes.watchPodUntilRunningAndRead();
core.info(`Watching build job ${pod?.metadata?.name}`); core.info(`Watching build job ${pod?.metadata?.name}`);
await Kubernetes.streamLogs(pod?.metadata?.name || '', this.namespace); await Kubernetes.streamLogs(
pod?.metadata?.name || '',
this.namespace,
pod?.status?.containerStatuses?.[0].name || '',
);
} catch (error) { } catch (error) {
core.error('Failed while watching build job'); core.error('Failed while watching build job');
throw error; throw error;
} }
} }
static async streamLogs(name: string, namespace: string) { static async streamLogs(name: string, namespace: string, container: string) {
try { try {
let running = true; let running = true;
let mostRecentLogTime: number = 999;
let mostRecentLine: string = '';
while (running) { while (running) {
const pod = await this.kubeClient.readNamespacedPod(name, namespace); const pod = await this.kubeClient.readNamespacedPod(name, namespace);
running = pod.body.status?.phase === 'Running'; running = pod.body.status?.phase === 'Running';
await new Promise((resolve) => setTimeout(resolve, pollInterval)); await new Promise((resolve) => setTimeout(resolve, pollInterval));
core.info('Polling logs...'); core.info('Polling logs...');
let logs; const logs = await this.kubeClient.readNamespacedPodLog(
try { name,
logs = await this.kubeClient.readNamespacedPodLog( namespace,
name, container,
namespace, true,
undefined, undefined,
undefined, undefined,
undefined, undefined,
undefined, undefined,
undefined, undefined,
undefined, undefined,
mostRecentLogTime, true,
undefined, );
true, logs.response.on('data', (data) => {
); core.info('LOGS RECEIVED');
} catch (error) { core.info(data);
core.info(error); });
if (error.message === 'HTTP request failed') {
core.info('!warning - K8S HTTP FAILED');
continue;
}
}
const arrayOfLines = logs?.body.match(/[^\n\r]+/g)?.reverse();
if (arrayOfLines) {
for (const element of arrayOfLines) {
const [time, ...line] = element.split(' ');
const lineString: string = line.join(' ');
const lineDate: number = Date.parse(time);
if (mostRecentLine !== lineString || lineDate > mostRecentLogTime) {
core.info(lineString);
mostRecentLogTime = lineDate;
mostRecentLine = lineString;
} else {
break;
}
}
}
} }
} catch (error) { } catch (error) {
core.error(JSON.stringify(error, undefined, 4)); core.error(JSON.stringify(error, undefined, 4));