PVC handling refactoring and logging
parent
09ed77c94a
commit
08db6c5022
|
|
@ -580,8 +580,8 @@ const unity_1 = __importDefault(__webpack_require__(70498));
|
|||
exports.Unity = unity_1.default;
|
||||
const versioning_1 = __importDefault(__webpack_require__(88729));
|
||||
exports.Versioning = versioning_1.default;
|
||||
const kubernetes_1 = __importDefault(__webpack_require__(7352));
|
||||
exports.Kubernetes = kubernetes_1.default;
|
||||
const kubernetes_build_platform_1 = __importDefault(__webpack_require__(81730));
|
||||
exports.Kubernetes = kubernetes_build_platform_1.default;
|
||||
const remote_builder_1 = __importDefault(__webpack_require__(49358));
|
||||
exports.RemoteBuilder = remote_builder_1.default;
|
||||
|
||||
|
|
@ -693,450 +693,6 @@ class Input {
|
|||
exports.default = Input;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 7352:
|
||||
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
const k8s = __importStar(__webpack_require__(89679));
|
||||
const core = __importStar(__webpack_require__(42186));
|
||||
const client_node_1 = __webpack_require__(89679);
|
||||
const stream_1 = __webpack_require__(92413);
|
||||
const async_wait_until_1 = __webpack_require__(41299);
|
||||
const base64 = __webpack_require__(85848);
|
||||
class Kubernetes {
|
||||
constructor(buildParameters, baseImage) {
|
||||
this.buildId = '';
|
||||
this.pvcName = '';
|
||||
this.secretName = '';
|
||||
this.jobName = '';
|
||||
this.podName = '';
|
||||
this.containerName = '';
|
||||
const kc = new k8s.KubeConfig();
|
||||
kc.loadFromDefault();
|
||||
const k8sApi = kc.makeApiClient(k8s.CoreV1Api);
|
||||
const k8sBatchApi = kc.makeApiClient(k8s.BatchV1Api);
|
||||
core.info('Loaded default Kubernetes configuration for this environment');
|
||||
this.kubeConfig = kc;
|
||||
this.kubeClient = k8sApi;
|
||||
this.kubeClientBatch = k8sBatchApi;
|
||||
this.namespace = 'default';
|
||||
this.buildParameters = buildParameters;
|
||||
this.baseImage = baseImage;
|
||||
this.setUniqueBuildId();
|
||||
}
|
||||
setUniqueBuildId() {
|
||||
const buildId = Kubernetes.uuidv4();
|
||||
const pvcName = `unity-builder-pvc-${buildId}`;
|
||||
const secretName = `build-credentials-${buildId}`;
|
||||
const jobName = `unity-builder-job-${buildId}`;
|
||||
this.buildId = buildId;
|
||||
this.pvcName = pvcName;
|
||||
this.secretName = secretName;
|
||||
this.jobName = jobName;
|
||||
}
|
||||
run() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
core.info('Running Remote Builder on Kubernetes');
|
||||
const defaultSecretsArray = [
|
||||
{
|
||||
ParameterKey: 'GithubToken',
|
||||
EnvironmentVariable: 'GITHUB_TOKEN',
|
||||
ParameterValue: this.buildParameters.githubToken,
|
||||
},
|
||||
{
|
||||
ParameterKey: 'UNITY_LICENSE',
|
||||
EnvironmentVariable: 'UNITY_LICENSE',
|
||||
ParameterValue: process.env.UNITY_LICENSE || '',
|
||||
},
|
||||
{
|
||||
ParameterKey: 'ANDROID_KEYSTORE_BASE64',
|
||||
EnvironmentVariable: 'ANDROID_KEYSTORE_BASE64',
|
||||
ParameterValue: this.buildParameters.androidKeystoreBase64,
|
||||
},
|
||||
{
|
||||
ParameterKey: 'ANDROID_KEYSTORE_PASS',
|
||||
EnvironmentVariable: 'ANDROID_KEYSTORE_PASS',
|
||||
ParameterValue: this.buildParameters.androidKeystorePass,
|
||||
},
|
||||
{
|
||||
ParameterKey: 'ANDROID_KEYALIAS_PASS',
|
||||
EnvironmentVariable: 'ANDROID_KEYALIAS_PASS',
|
||||
ParameterValue: this.buildParameters.androidKeyaliasPass,
|
||||
},
|
||||
];
|
||||
try {
|
||||
// setup
|
||||
yield this.createSecret(defaultSecretsArray);
|
||||
yield this.createPersistentVolumeClaim();
|
||||
// run
|
||||
yield this.runCloneJob();
|
||||
yield this.runBuildJob();
|
||||
yield this.cleanup();
|
||||
}
|
||||
catch (error) {
|
||||
core.error(JSON.stringify(error.response, undefined, 4));
|
||||
throw error;
|
||||
}
|
||||
core.setOutput('volume', this.pvcName);
|
||||
});
|
||||
}
|
||||
createSecret(secrets) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const secret = new k8s.V1Secret();
|
||||
secret.apiVersion = 'v1';
|
||||
secret.kind = 'Secret';
|
||||
secret.type = 'Opaque';
|
||||
secret.metadata = {
|
||||
name: this.secretName,
|
||||
};
|
||||
secret.data = {};
|
||||
for (const buildSecret of secrets) {
|
||||
secret.data[buildSecret.EnvironmentVariable] = base64.encode(buildSecret.ParameterValue);
|
||||
secret.data[`${buildSecret.EnvironmentVariable}_NAME`] = base64.encode(buildSecret.ParameterKey);
|
||||
}
|
||||
try {
|
||||
yield this.kubeClient.createNamespacedSecret(this.namespace, secret);
|
||||
}
|
||||
catch (error) {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
getPVCPhase() {
|
||||
var _a;
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
return (_a = (yield this.kubeClient.readNamespacedPersistentVolumeClaimStatus(this.pvcName, this.namespace)).body.status) === null || _a === void 0 ? void 0 : _a.phase;
|
||||
});
|
||||
}
|
||||
createPersistentVolumeClaim() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (this.buildParameters.kubeVolume) {
|
||||
core.info(this.buildParameters.kubeVolume);
|
||||
this.pvcName = this.buildParameters.kubeVolume;
|
||||
return;
|
||||
}
|
||||
const pvc = new k8s.V1PersistentVolumeClaim();
|
||||
pvc.apiVersion = 'v1';
|
||||
pvc.kind = 'PersistentVolumeClaim';
|
||||
pvc.metadata = {
|
||||
name: this.pvcName,
|
||||
};
|
||||
pvc.spec = {
|
||||
accessModes: ['ReadWriteOnce'],
|
||||
volumeMode: 'Filesystem',
|
||||
resources: {
|
||||
requests: {
|
||||
storage: this.buildParameters.kubeVolumeSize,
|
||||
},
|
||||
},
|
||||
};
|
||||
yield this.kubeClient.createNamespacedPersistentVolumeClaim(this.namespace, pvc);
|
||||
core.info(`Persistent Volume created, ${yield this.getPVCPhase()}`);
|
||||
});
|
||||
}
|
||||
getJobSpec(command, image) {
|
||||
const job = new k8s.V1Job();
|
||||
job.apiVersion = 'batch/v1';
|
||||
job.kind = 'Job';
|
||||
job.metadata = {
|
||||
name: this.jobName,
|
||||
labels: {
|
||||
app: 'unity-builder',
|
||||
},
|
||||
};
|
||||
job.spec = {
|
||||
template: {
|
||||
spec: {
|
||||
volumes: [
|
||||
{
|
||||
name: 'data',
|
||||
persistentVolumeClaim: {
|
||||
claimName: this.pvcName,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'credentials',
|
||||
secret: {
|
||||
secretName: this.secretName,
|
||||
},
|
||||
},
|
||||
],
|
||||
containers: [
|
||||
{
|
||||
name: 'main',
|
||||
image,
|
||||
command,
|
||||
resources: {
|
||||
requests: {
|
||||
memory: this.buildParameters.remoteBuildMemory,
|
||||
cpu: this.buildParameters.remoteBuildCpu,
|
||||
},
|
||||
},
|
||||
env: [
|
||||
{
|
||||
name: 'GITHUB_SHA',
|
||||
value: this.buildId,
|
||||
},
|
||||
{
|
||||
name: 'GITHUB_WORKSPACE',
|
||||
value: '/data/repo',
|
||||
},
|
||||
{
|
||||
name: 'PROJECT_PATH',
|
||||
value: this.buildParameters.projectPath,
|
||||
},
|
||||
{
|
||||
name: 'BUILD_PATH',
|
||||
value: this.buildParameters.buildPath,
|
||||
},
|
||||
{
|
||||
name: 'BUILD_FILE',
|
||||
value: this.buildParameters.buildFile,
|
||||
},
|
||||
{
|
||||
name: 'BUILD_NAME',
|
||||
value: this.buildParameters.buildName,
|
||||
},
|
||||
{
|
||||
name: 'BUILD_METHOD',
|
||||
value: this.buildParameters.buildMethod,
|
||||
},
|
||||
{
|
||||
name: 'CUSTOM_PARAMETERS',
|
||||
value: this.buildParameters.customParameters,
|
||||
},
|
||||
{
|
||||
name: 'CHOWN_FILES_TO',
|
||||
value: this.buildParameters.chownFilesTo,
|
||||
},
|
||||
{
|
||||
name: 'BUILD_TARGET',
|
||||
value: this.buildParameters.platform,
|
||||
},
|
||||
{
|
||||
name: 'ANDROID_VERSION_CODE',
|
||||
value: this.buildParameters.androidVersionCode.toString(),
|
||||
},
|
||||
{
|
||||
name: 'ANDROID_KEYSTORE_NAME',
|
||||
value: this.buildParameters.androidKeystoreName,
|
||||
},
|
||||
{
|
||||
name: 'ANDROID_KEYALIAS_NAME',
|
||||
value: this.buildParameters.androidKeyaliasName,
|
||||
},
|
||||
],
|
||||
volumeMounts: [
|
||||
{
|
||||
name: 'data',
|
||||
mountPath: '/data',
|
||||
},
|
||||
{
|
||||
name: 'credentials',
|
||||
mountPath: '/credentials',
|
||||
readOnly: true,
|
||||
},
|
||||
],
|
||||
lifecycle: {
|
||||
preStop: {
|
||||
exec: {
|
||||
command: [
|
||||
'bin/bash',
|
||||
'-c',
|
||||
`cd /data/builder/action/steps;
|
||||
chmod +x /return_license.sh;
|
||||
/return_license.sh;`,
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
restartPolicy: 'Never',
|
||||
},
|
||||
},
|
||||
};
|
||||
job.spec.backoffLimit = 1;
|
||||
return job;
|
||||
}
|
||||
runJob(command, image) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
this.setUniqueBuildId();
|
||||
const jobSpec = this.getJobSpec(command, image);
|
||||
core.info('Creating build job');
|
||||
yield this.kubeClientBatch.createNamespacedJob(this.namespace, jobSpec);
|
||||
core.info('Job created');
|
||||
yield this.watchPersistentVolumeClaimUntilBoundToContainer();
|
||||
core.info('PVC Bound');
|
||||
this.setPodNameAndContainerName(yield this.getPod());
|
||||
core.info('Watching pod and streaming logs');
|
||||
yield this.watchUntilPodRunning();
|
||||
yield this.streamLogs();
|
||||
yield this.cleanup();
|
||||
}
|
||||
catch (error) {
|
||||
yield this.cleanup();
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
getPod() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (this.podName === '') {
|
||||
const pod = (yield this.kubeClient.listNamespacedPod(this.namespace)).body.items.find((x) => { var _a, _b; return ((_b = (_a = x.metadata) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b['job-name']) === this.jobName; });
|
||||
if (pod === undefined) {
|
||||
throw new Error("pod with job-name label doesn't exist");
|
||||
}
|
||||
return pod;
|
||||
}
|
||||
else {
|
||||
return (yield this.kubeClient.readNamespacedPod(this.podName, this.namespace)).body;
|
||||
}
|
||||
});
|
||||
}
|
||||
runCloneJob() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield this.runJob([
|
||||
'/bin/ash',
|
||||
'-c',
|
||||
`apk update;
|
||||
apk add git-lfs;
|
||||
ls /credentials/
|
||||
export GITHUB_TOKEN=$(cat /credentials/GITHUB_TOKEN);
|
||||
cd /data;
|
||||
git clone https://github.com/${process.env.GITHUB_REPOSITORY}.git repo;
|
||||
git clone https://github.com/webbertakken/unity-builder.git builder;
|
||||
cd repo;
|
||||
git checkout $GITHUB_SHA;
|
||||
ls
|
||||
echo "end"`,
|
||||
], 'alpine/git');
|
||||
});
|
||||
}
|
||||
runBuildJob() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield this.runJob([
|
||||
'bin/bash',
|
||||
'-c',
|
||||
`ls
|
||||
for f in ./credentials/*; do export $(basename $f)="$(cat $f)"; done
|
||||
ls /data
|
||||
ls /data/builder
|
||||
ls /data/builder/dist
|
||||
cp -r /data/builder/dist/default-build-script /UnityBuilderAction
|
||||
cp -r /data/builder/dist/entrypoint.sh /entrypoint.sh
|
||||
cp -r /data/builder/dist/steps /steps
|
||||
chmod -R +x /entrypoint.sh
|
||||
chmod -R +x /steps
|
||||
/entrypoint.sh
|
||||
`,
|
||||
], this.baseImage.toString());
|
||||
});
|
||||
}
|
||||
watchPersistentVolumeClaimUntilBoundToContainer() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield async_wait_until_1.waitUntil(() => __awaiter(this, void 0, void 0, function* () { return (yield this.getPVCPhase()) !== 'Pending'; }));
|
||||
});
|
||||
}
|
||||
getPodStatusPhase() {
|
||||
var _a, _b;
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
return (_b = (_a = (yield this.kubeClient.readNamespacedPod(this.podName, this.namespace))) === null || _a === void 0 ? void 0 : _a.body.status) === null || _b === void 0 ? void 0 : _b.phase;
|
||||
});
|
||||
}
|
||||
watchUntilPodRunning() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield async_wait_until_1.waitUntil(() => __awaiter(this, void 0, void 0, function* () {
|
||||
(yield this.getPodStatusPhase()) !== 'Pending';
|
||||
}));
|
||||
const phase = yield this.getPodStatusPhase();
|
||||
if (phase === 'Running') {
|
||||
core.info('Pod no longer pending');
|
||||
}
|
||||
else {
|
||||
core.error('Pod failed to reach running phase');
|
||||
}
|
||||
});
|
||||
}
|
||||
setPodNameAndContainerName(pod) {
|
||||
var _a, _b, _c;
|
||||
this.podName = ((_a = pod.metadata) === null || _a === void 0 ? void 0 : _a.name) || '';
|
||||
this.containerName = ((_c = (_b = pod.status) === null || _b === void 0 ? void 0 : _b.containerStatuses) === null || _c === void 0 ? void 0 : _c[0].name) || '';
|
||||
}
|
||||
streamLogs() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
core.info(`Streaming logs from pod: ${this.podName} container: ${this.containerName} namespace: ${this.namespace}`);
|
||||
const stream = new stream_1.Writable();
|
||||
stream._write = (chunk, encoding, next) => {
|
||||
core.info(chunk.toString());
|
||||
next();
|
||||
};
|
||||
const logOptions = {
|
||||
follow: true,
|
||||
pretty: true,
|
||||
previous: true,
|
||||
};
|
||||
try {
|
||||
yield new Promise((resolve) => new client_node_1.Log(this.kubeConfig).log(this.namespace, this.podName, this.containerName, stream, resolve, logOptions));
|
||||
}
|
||||
catch (error) {
|
||||
throw error;
|
||||
}
|
||||
core.info('end of log stream');
|
||||
});
|
||||
}
|
||||
cleanup() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
core.info('cleaning up');
|
||||
yield this.kubeClientBatch.deleteNamespacedJob(this.jobName, this.namespace);
|
||||
yield this.kubeClient.deleteNamespacedPersistentVolumeClaim(this.pvcName, this.namespace);
|
||||
yield this.kubeClient.deleteNamespacedSecret(this.secretName, this.namespace);
|
||||
});
|
||||
}
|
||||
static uuidv4() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
||||
const r = Math.trunc(Math.random() * 16);
|
||||
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.default = Kubernetes;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 85487:
|
||||
|
|
@ -1655,6 +1211,503 @@ class AWSBuildRunner {
|
|||
exports.default = AWSBuildRunner;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 81730:
|
||||
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
const k8s = __importStar(__webpack_require__(89679));
|
||||
const core = __importStar(__webpack_require__(42186));
|
||||
const client_node_1 = __webpack_require__(89679);
|
||||
const stream_1 = __webpack_require__(92413);
|
||||
const async_wait_until_1 = __webpack_require__(41299);
|
||||
const kubernetes_storage_1 = __importDefault(__webpack_require__(38941));
|
||||
const base64 = __webpack_require__(85848);
|
||||
class Kubernetes {
|
||||
constructor(buildParameters, baseImage) {
|
||||
this.buildId = '';
|
||||
this.pvcName = '';
|
||||
this.secretName = '';
|
||||
this.jobName = '';
|
||||
this.podName = '';
|
||||
this.containerName = '';
|
||||
const kc = new k8s.KubeConfig();
|
||||
kc.loadFromDefault();
|
||||
const k8sApi = kc.makeApiClient(k8s.CoreV1Api);
|
||||
const k8sBatchApi = kc.makeApiClient(k8s.BatchV1Api);
|
||||
core.info('Loaded default Kubernetes configuration for this environment');
|
||||
this.kubeConfig = kc;
|
||||
this.kubeClient = k8sApi;
|
||||
this.kubeClientBatch = k8sBatchApi;
|
||||
this.namespace = 'default';
|
||||
this.buildParameters = buildParameters;
|
||||
this.baseImage = baseImage;
|
||||
this.setUniqueBuildId();
|
||||
}
|
||||
setUniqueBuildId() {
|
||||
const buildId = Kubernetes.uuidv4();
|
||||
const pvcName = `unity-builder-pvc-${buildId}`;
|
||||
const secretName = `build-credentials-${buildId}`;
|
||||
const jobName = `unity-builder-job-${buildId}`;
|
||||
this.buildId = buildId;
|
||||
this.pvcName = pvcName;
|
||||
this.secretName = secretName;
|
||||
this.jobName = jobName;
|
||||
}
|
||||
run() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
core.info('Running Remote Builder on Kubernetes');
|
||||
const defaultSecretsArray = [
|
||||
{
|
||||
ParameterKey: 'GithubToken',
|
||||
EnvironmentVariable: 'GITHUB_TOKEN',
|
||||
ParameterValue: this.buildParameters.githubToken,
|
||||
},
|
||||
{
|
||||
ParameterKey: 'UNITY_LICENSE',
|
||||
EnvironmentVariable: 'UNITY_LICENSE',
|
||||
ParameterValue: process.env.UNITY_LICENSE || '',
|
||||
},
|
||||
{
|
||||
ParameterKey: 'ANDROID_KEYSTORE_BASE64',
|
||||
EnvironmentVariable: 'ANDROID_KEYSTORE_BASE64',
|
||||
ParameterValue: this.buildParameters.androidKeystoreBase64,
|
||||
},
|
||||
{
|
||||
ParameterKey: 'ANDROID_KEYSTORE_PASS',
|
||||
EnvironmentVariable: 'ANDROID_KEYSTORE_PASS',
|
||||
ParameterValue: this.buildParameters.androidKeystorePass,
|
||||
},
|
||||
{
|
||||
ParameterKey: 'ANDROID_KEYALIAS_PASS',
|
||||
EnvironmentVariable: 'ANDROID_KEYALIAS_PASS',
|
||||
ParameterValue: this.buildParameters.androidKeyaliasPass,
|
||||
},
|
||||
];
|
||||
try {
|
||||
// setup
|
||||
yield this.createSecret(defaultSecretsArray);
|
||||
yield kubernetes_storage_1.default.createPersistentVolumeClaim(this.buildParameters, this.pvcName, this.kubeClient, this.namespace);
|
||||
// run
|
||||
yield this.runCloneJob();
|
||||
yield this.runBuildJob();
|
||||
yield this.cleanup();
|
||||
}
|
||||
catch (error) {
|
||||
core.error(JSON.stringify(error.response, undefined, 4));
|
||||
throw error;
|
||||
}
|
||||
core.setOutput('volume', this.pvcName);
|
||||
});
|
||||
}
|
||||
createSecret(secrets) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const secret = new k8s.V1Secret();
|
||||
secret.apiVersion = 'v1';
|
||||
secret.kind = 'Secret';
|
||||
secret.type = 'Opaque';
|
||||
secret.metadata = {
|
||||
name: this.secretName,
|
||||
};
|
||||
secret.data = {};
|
||||
for (const buildSecret of secrets) {
|
||||
secret.data[buildSecret.EnvironmentVariable] = base64.encode(buildSecret.ParameterValue);
|
||||
secret.data[`${buildSecret.EnvironmentVariable}_NAME`] = base64.encode(buildSecret.ParameterKey);
|
||||
}
|
||||
try {
|
||||
yield this.kubeClient.createNamespacedSecret(this.namespace, secret);
|
||||
}
|
||||
catch (error) {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
getJobSpec(command, image) {
|
||||
const job = new k8s.V1Job();
|
||||
job.apiVersion = 'batch/v1';
|
||||
job.kind = 'Job';
|
||||
job.metadata = {
|
||||
name: this.jobName,
|
||||
labels: {
|
||||
app: 'unity-builder',
|
||||
},
|
||||
};
|
||||
job.spec = {
|
||||
template: {
|
||||
spec: {
|
||||
volumes: [
|
||||
{
|
||||
name: 'data',
|
||||
persistentVolumeClaim: {
|
||||
claimName: this.pvcName,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'credentials',
|
||||
secret: {
|
||||
secretName: this.secretName,
|
||||
},
|
||||
},
|
||||
],
|
||||
containers: [
|
||||
{
|
||||
name: 'main',
|
||||
image,
|
||||
command,
|
||||
resources: {
|
||||
requests: {
|
||||
memory: this.buildParameters.remoteBuildMemory,
|
||||
cpu: this.buildParameters.remoteBuildCpu,
|
||||
},
|
||||
},
|
||||
env: [
|
||||
{
|
||||
name: 'GITHUB_SHA',
|
||||
value: this.buildId,
|
||||
},
|
||||
{
|
||||
name: 'GITHUB_WORKSPACE',
|
||||
value: '/data/repo',
|
||||
},
|
||||
{
|
||||
name: 'PROJECT_PATH',
|
||||
value: this.buildParameters.projectPath,
|
||||
},
|
||||
{
|
||||
name: 'BUILD_PATH',
|
||||
value: this.buildParameters.buildPath,
|
||||
},
|
||||
{
|
||||
name: 'BUILD_FILE',
|
||||
value: this.buildParameters.buildFile,
|
||||
},
|
||||
{
|
||||
name: 'BUILD_NAME',
|
||||
value: this.buildParameters.buildName,
|
||||
},
|
||||
{
|
||||
name: 'BUILD_METHOD',
|
||||
value: this.buildParameters.buildMethod,
|
||||
},
|
||||
{
|
||||
name: 'CUSTOM_PARAMETERS',
|
||||
value: this.buildParameters.customParameters,
|
||||
},
|
||||
{
|
||||
name: 'CHOWN_FILES_TO',
|
||||
value: this.buildParameters.chownFilesTo,
|
||||
},
|
||||
{
|
||||
name: 'BUILD_TARGET',
|
||||
value: this.buildParameters.platform,
|
||||
},
|
||||
{
|
||||
name: 'ANDROID_VERSION_CODE',
|
||||
value: this.buildParameters.androidVersionCode.toString(),
|
||||
},
|
||||
{
|
||||
name: 'ANDROID_KEYSTORE_NAME',
|
||||
value: this.buildParameters.androidKeystoreName,
|
||||
},
|
||||
{
|
||||
name: 'ANDROID_KEYALIAS_NAME',
|
||||
value: this.buildParameters.androidKeyaliasName,
|
||||
},
|
||||
],
|
||||
volumeMounts: [
|
||||
{
|
||||
name: 'data',
|
||||
mountPath: '/data',
|
||||
},
|
||||
{
|
||||
name: 'credentials',
|
||||
mountPath: '/credentials',
|
||||
readOnly: true,
|
||||
},
|
||||
],
|
||||
lifecycle: {
|
||||
preStop: {
|
||||
exec: {
|
||||
command: [
|
||||
'bin/bash',
|
||||
'-c',
|
||||
`cd /data/builder/action/steps;
|
||||
chmod +x /return_license.sh;
|
||||
/return_license.sh;`,
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
restartPolicy: 'Never',
|
||||
},
|
||||
},
|
||||
};
|
||||
job.spec.backoffLimit = 1;
|
||||
return job;
|
||||
}
|
||||
runJob(command, image) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
this.setUniqueBuildId();
|
||||
const jobSpec = this.getJobSpec(command, image);
|
||||
core.info('Creating build job');
|
||||
yield this.kubeClientBatch.createNamespacedJob(this.namespace, jobSpec);
|
||||
core.info('Job created');
|
||||
yield kubernetes_storage_1.default.watchPersistentVolumeClaimUntilBoundToContainer(this.kubeClient, this.pvcName, this.namespace);
|
||||
core.info('PVC Bound');
|
||||
this.setPodNameAndContainerName(yield this.getPod());
|
||||
core.info('Watching pod and streaming logs');
|
||||
yield this.watchUntilPodRunning();
|
||||
yield this.streamLogs();
|
||||
yield this.cleanup();
|
||||
}
|
||||
catch (error) {
|
||||
yield this.cleanup();
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
getPod() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (this.podName === '') {
|
||||
const pod = (yield this.kubeClient.listNamespacedPod(this.namespace)).body.items.find((x) => { var _a, _b; return ((_b = (_a = x.metadata) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b['job-name']) === this.jobName; });
|
||||
if (pod === undefined) {
|
||||
throw new Error("pod with job-name label doesn't exist");
|
||||
}
|
||||
return pod;
|
||||
}
|
||||
else {
|
||||
return (yield this.kubeClient.readNamespacedPod(this.podName, this.namespace)).body;
|
||||
}
|
||||
});
|
||||
}
|
||||
runCloneJob() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield this.runJob([
|
||||
'/bin/ash',
|
||||
'-c',
|
||||
`apk update;
|
||||
apk add git-lfs;
|
||||
ls /credentials/
|
||||
export GITHUB_TOKEN=$(cat /credentials/GITHUB_TOKEN);
|
||||
cd /data;
|
||||
git clone https://github.com/${process.env.GITHUB_REPOSITORY}.git repo;
|
||||
git clone https://github.com/webbertakken/unity-builder.git builder;
|
||||
cd repo;
|
||||
git checkout $GITHUB_SHA;
|
||||
ls
|
||||
echo "end"`,
|
||||
], 'alpine/git');
|
||||
});
|
||||
}
|
||||
runBuildJob() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield this.runJob([
|
||||
'bin/bash',
|
||||
'-c',
|
||||
`ls
|
||||
for f in ./credentials/*; do export $(basename $f)="$(cat $f)"; done
|
||||
ls /data
|
||||
ls /data/builder
|
||||
ls /data/builder/dist
|
||||
cp -r /data/builder/dist/default-build-script /UnityBuilderAction
|
||||
cp -r /data/builder/dist/entrypoint.sh /entrypoint.sh
|
||||
cp -r /data/builder/dist/steps /steps
|
||||
chmod -R +x /entrypoint.sh
|
||||
chmod -R +x /steps
|
||||
/entrypoint.sh
|
||||
`,
|
||||
], this.baseImage.toString());
|
||||
});
|
||||
}
|
||||
getPodStatusPhase() {
|
||||
var _a, _b;
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
return (_b = (_a = (yield this.kubeClient.readNamespacedPod(this.podName, this.namespace))) === null || _a === void 0 ? void 0 : _a.body.status) === null || _b === void 0 ? void 0 : _b.phase;
|
||||
});
|
||||
}
|
||||
watchUntilPodRunning() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield async_wait_until_1.waitUntil(() => __awaiter(this, void 0, void 0, function* () {
|
||||
(yield this.getPodStatusPhase()) !== 'Pending';
|
||||
}));
|
||||
const phase = yield this.getPodStatusPhase();
|
||||
if (phase === 'Running') {
|
||||
core.info('Pod no longer pending');
|
||||
}
|
||||
else {
|
||||
core.error('Pod failed to reach running phase');
|
||||
}
|
||||
});
|
||||
}
|
||||
setPodNameAndContainerName(pod) {
|
||||
var _a, _b, _c;
|
||||
this.podName = ((_a = pod.metadata) === null || _a === void 0 ? void 0 : _a.name) || '';
|
||||
this.containerName = ((_c = (_b = pod.status) === null || _b === void 0 ? void 0 : _b.containerStatuses) === null || _c === void 0 ? void 0 : _c[0].name) || '';
|
||||
}
|
||||
streamLogs() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
core.info(`Streaming logs from pod: ${this.podName} container: ${this.containerName} namespace: ${this.namespace}`);
|
||||
const stream = new stream_1.Writable();
|
||||
stream._write = (chunk, encoding, next) => {
|
||||
core.info(chunk.toString());
|
||||
next();
|
||||
};
|
||||
const logOptions = {
|
||||
follow: true,
|
||||
pretty: true,
|
||||
previous: true,
|
||||
};
|
||||
try {
|
||||
yield new Promise((resolve) => new client_node_1.Log(this.kubeConfig).log(this.namespace, this.podName, this.containerName, stream, resolve, logOptions));
|
||||
}
|
||||
catch (error) {
|
||||
throw error;
|
||||
}
|
||||
core.info('end of log stream');
|
||||
});
|
||||
}
|
||||
cleanup() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
core.info('cleaning up');
|
||||
yield this.kubeClientBatch.deleteNamespacedJob(this.jobName, this.namespace);
|
||||
yield this.kubeClient.deleteNamespacedPersistentVolumeClaim(this.pvcName, this.namespace);
|
||||
yield this.kubeClient.deleteNamespacedSecret(this.secretName, this.namespace);
|
||||
});
|
||||
}
|
||||
static uuidv4() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
||||
const r = Math.trunc(Math.random() * 16);
|
||||
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.default = Kubernetes;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 38941:
|
||||
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
const async_wait_until_1 = __importDefault(__webpack_require__(41299));
|
||||
const core = __importStar(__webpack_require__(42186));
|
||||
const k8s = __importStar(__webpack_require__(89679));
|
||||
class KubernetesStorage {
|
||||
static getPVCPhase(kubeClient, name, namespace) {
|
||||
var _a;
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
return (_a = (yield kubeClient.readNamespacedPersistentVolumeClaimStatus(name, namespace)).body.status) === null || _a === void 0 ? void 0 : _a.phase;
|
||||
});
|
||||
}
|
||||
static watchPersistentVolumeClaimUntilBoundToContainer(kubeClient, name, namespace) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield async_wait_until_1.default(() => __awaiter(this, void 0, void 0, function* () { return (yield this.getPVCPhase(kubeClient, name, namespace)) !== 'Pending'; }));
|
||||
});
|
||||
}
|
||||
static createPersistentVolumeClaim(buildParameters, pvcName, kubeClient, namespace) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (buildParameters.kubeVolume) {
|
||||
core.info(buildParameters.kubeVolume);
|
||||
pvcName = buildParameters.kubeVolume;
|
||||
return;
|
||||
}
|
||||
const pvc = new k8s.V1PersistentVolumeClaim();
|
||||
pvc.apiVersion = 'v1';
|
||||
pvc.kind = 'PersistentVolumeClaim';
|
||||
pvc.metadata = {
|
||||
name: pvcName,
|
||||
};
|
||||
pvc.spec = {
|
||||
accessModes: ['ReadWriteOnce'],
|
||||
volumeMode: 'Filesystem',
|
||||
resources: {
|
||||
requests: {
|
||||
storage: buildParameters.kubeVolumeSize,
|
||||
},
|
||||
},
|
||||
};
|
||||
yield kubeClient.createNamespacedPersistentVolumeClaim(namespace, pvc);
|
||||
core.info(`Persistent Volume created, ${yield KubernetesStorage.getPVCPhase(kubeClient, pvcName, namespace)}`);
|
||||
yield this.watchPersistentVolumeClaimUntilBoundToContainer(kubeClient, pvcName, pvcName);
|
||||
core.info(JSON.stringify((yield kubeClient.readNamespacedPersistentVolumeClaimStatus(pvcName, namespace)).body, undefined, 4));
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.default = KubernetesStorage;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 92560:
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -9,7 +9,7 @@ import Platform from './platform';
|
|||
import Project from './project';
|
||||
import Unity from './unity';
|
||||
import Versioning from './versioning';
|
||||
import Kubernetes from './kubernetes';
|
||||
import Kubernetes from './remote-builder/kubernetes-build-platform';
|
||||
import RemoteBuilder from './remote-builder/remote-builder';
|
||||
|
||||
export {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import * as k8s from '@kubernetes/client-node';
|
||||
import { BuildParameters } from '.';
|
||||
import { BuildParameters } from '..';
|
||||
import * as core from '@actions/core';
|
||||
import { KubeConfig, Log } from '@kubernetes/client-node';
|
||||
import { Writable } from 'stream';
|
||||
import { RemoteBuilderProviderInterface } from './remote-builder/remote-builder-provider-interface';
|
||||
import RemoteBuilderSecret from './remote-builder/remote-builder-secret';
|
||||
import { RemoteBuilderProviderInterface } from './remote-builder-provider-interface';
|
||||
import RemoteBuilderSecret from './remote-builder-secret';
|
||||
import { waitUntil } from 'async-wait-until';
|
||||
import KubernetesStorage from './kubernetes-storage';
|
||||
|
||||
const base64 = require('base-64');
|
||||
|
||||
|
|
@ -85,7 +86,13 @@ class Kubernetes implements RemoteBuilderProviderInterface {
|
|||
try {
|
||||
// setup
|
||||
await this.createSecret(defaultSecretsArray);
|
||||
await this.createPersistentVolumeClaim();
|
||||
await KubernetesStorage.createPersistentVolumeClaim(
|
||||
this.buildParameters,
|
||||
this.pvcName,
|
||||
this.kubeClient,
|
||||
this.namespace,
|
||||
);
|
||||
|
||||
// run
|
||||
await this.runCloneJob();
|
||||
await this.runBuildJob();
|
||||
|
|
@ -119,36 +126,6 @@ class Kubernetes implements RemoteBuilderProviderInterface {
|
|||
}
|
||||
}
|
||||
|
||||
async getPVCPhase() {
|
||||
return (await this.kubeClient.readNamespacedPersistentVolumeClaimStatus(this.pvcName, this.namespace)).body.status
|
||||
?.phase;
|
||||
}
|
||||
|
||||
async createPersistentVolumeClaim() {
|
||||
if (this.buildParameters.kubeVolume) {
|
||||
core.info(this.buildParameters.kubeVolume);
|
||||
this.pvcName = this.buildParameters.kubeVolume;
|
||||
return;
|
||||
}
|
||||
const pvc = new k8s.V1PersistentVolumeClaim();
|
||||
pvc.apiVersion = 'v1';
|
||||
pvc.kind = 'PersistentVolumeClaim';
|
||||
pvc.metadata = {
|
||||
name: this.pvcName,
|
||||
};
|
||||
pvc.spec = {
|
||||
accessModes: ['ReadWriteOnce'],
|
||||
volumeMode: 'Filesystem',
|
||||
resources: {
|
||||
requests: {
|
||||
storage: this.buildParameters.kubeVolumeSize,
|
||||
},
|
||||
},
|
||||
};
|
||||
await this.kubeClient.createNamespacedPersistentVolumeClaim(this.namespace, pvc);
|
||||
core.info(`Persistent Volume created, ${await this.getPVCPhase()}`);
|
||||
}
|
||||
|
||||
getJobSpec(command: string[], image: string) {
|
||||
const job = new k8s.V1Job();
|
||||
job.apiVersion = 'batch/v1';
|
||||
|
|
@ -282,7 +259,11 @@ class Kubernetes implements RemoteBuilderProviderInterface {
|
|||
core.info('Creating build job');
|
||||
await this.kubeClientBatch.createNamespacedJob(this.namespace, jobSpec);
|
||||
core.info('Job created');
|
||||
await this.watchPersistentVolumeClaimUntilBoundToContainer();
|
||||
await KubernetesStorage.watchPersistentVolumeClaimUntilBoundToContainer(
|
||||
this.kubeClient,
|
||||
this.pvcName,
|
||||
this.namespace,
|
||||
);
|
||||
core.info('PVC Bound');
|
||||
this.setPodNameAndContainerName(await this.getPod());
|
||||
core.info('Watching pod and streaming logs');
|
||||
|
|
@ -352,10 +333,6 @@ class Kubernetes implements RemoteBuilderProviderInterface {
|
|||
);
|
||||
}
|
||||
|
||||
async watchPersistentVolumeClaimUntilBoundToContainer() {
|
||||
await waitUntil(async () => (await this.getPVCPhase()) !== 'Pending');
|
||||
}
|
||||
|
||||
async getPodStatusPhase() {
|
||||
return (await this.kubeClient.readNamespacedPod(this.podName, this.namespace))?.body.status?.phase;
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import waitUntil from 'async-wait-until';
|
||||
import * as core from '@actions/core';
|
||||
import * as k8s from '@kubernetes/client-node';
|
||||
|
||||
class KubernetesStorage {
|
||||
public static async getPVCPhase(kubeClient, name, namespace) {
|
||||
return (await kubeClient.readNamespacedPersistentVolumeClaimStatus(name, namespace)).body.status?.phase;
|
||||
}
|
||||
public static async watchPersistentVolumeClaimUntilBoundToContainer(kubeClient, name, namespace) {
|
||||
await waitUntil(async () => (await this.getPVCPhase(kubeClient, name, namespace)) !== 'Pending');
|
||||
}
|
||||
|
||||
public static async createPersistentVolumeClaim(buildParameters, pvcName, kubeClient, namespace) {
|
||||
if (buildParameters.kubeVolume) {
|
||||
core.info(buildParameters.kubeVolume);
|
||||
pvcName = buildParameters.kubeVolume;
|
||||
return;
|
||||
}
|
||||
const pvc = new k8s.V1PersistentVolumeClaim();
|
||||
pvc.apiVersion = 'v1';
|
||||
pvc.kind = 'PersistentVolumeClaim';
|
||||
pvc.metadata = {
|
||||
name: pvcName,
|
||||
};
|
||||
pvc.spec = {
|
||||
accessModes: ['ReadWriteOnce'],
|
||||
volumeMode: 'Filesystem',
|
||||
resources: {
|
||||
requests: {
|
||||
storage: buildParameters.kubeVolumeSize,
|
||||
},
|
||||
},
|
||||
};
|
||||
await kubeClient.createNamespacedPersistentVolumeClaim(namespace, pvc);
|
||||
core.info(`Persistent Volume created, ${await KubernetesStorage.getPVCPhase(kubeClient, pvcName, namespace)}`);
|
||||
await this.watchPersistentVolumeClaimUntilBoundToContainer(kubeClient, pvcName, pvcName);
|
||||
core.info(
|
||||
JSON.stringify(
|
||||
(await kubeClient.readNamespacedPersistentVolumeClaimStatus(pvcName, namespace)).body,
|
||||
undefined,
|
||||
4,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default KubernetesStorage;
|
||||
Loading…
Reference in New Issue