zcatalyst-cli
Version:
Command Line Tool for CATALYST
256 lines (255 loc) • 14.7 kB
JavaScript
;
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 });
exports.filterTargets = filterTargets;
exports.validateAppSail = validateAppSail;
const ansi_colors_1 = require("ansi-colors");
const error_1 = __importDefault(require("./error"));
const appsail_1 = require("./util_modules/config/lib/appsail");
const constants_1 = require("./util_modules/constants");
const index_1 = require("./util_modules/logger/index");
const option_1 = require("./util_modules/option");
const container_1 = require("./util_modules/container");
const image_1 = require("@zcatalyst/container-plugin/out/endpoints/image");
const fs_1 = require("./util_modules/fs");
const util_1 = require("util");
const OCI_IMAGE_INDEX_MEDIA_TYPES = [
'application/vnd.oci.image.index.v1+json',
'application/vnd.docker.distribution.manifest.list.v2+json'
];
const OCI_IMAGE_MANIFEST_MEDIA_TYPES = [
'application/vnd.oci.image.manifest.v1+json',
'application/vnd.docker.distribution.manifest.v2+json'
];
function getBlobPathFromDigest(digest, sourceFile) {
const [algorithm, hash] = digest.split(':');
if (!algorithm || !hash) {
throw new error_1.default(`Corrupted image tar :: invalid digest ${digest} found in ${sourceFile}`, { exit: 1 });
}
return `blobs/${algorithm}/${hash}`;
}
function getAppSailFilters(targetStr) {
return targetStr.split(',').reduce((filterArr, target) => {
const opts = target.split(':');
if (opts[0] === 'appsail' && opts[1]) {
filterArr.push(opts[1]);
return filterArr;
}
return filterArr;
}, []);
}
function filterTargets(allTargets) {
const only = (0, option_1.getOptionValue)('only');
if (only !== undefined) {
const onlyTargs = getAppSailFilters(only);
if (onlyTargs.length === 0) {
return allTargets;
}
const refined = onlyTargs.reduce((filtered, filter) => {
const targDetailsIdx = allTargets.findIndex((targ) => targ.name === filter);
if (targDetailsIdx === -1) {
filtered.unmatched.push(filter);
}
else {
const targDetails = allTargets.splice(targDetailsIdx, 1);
filtered.matched.push(targDetails[0]);
}
return filtered;
}, {
matched: [],
unmatched: []
});
if (refined.unmatched.length > 0) {
throw new error_1.default(`The filters ${(0, ansi_colors_1.bold)(refined.unmatched.join(', '))} provided with --only option does not match with any AppSail in ${constants_1.FILENAME.config}.`, { exit: 1 });
}
return refined.matched;
}
const except = (0, option_1.getOptionValue)('except');
if (except !== undefined) {
const exceptTargs = getAppSailFilters(except);
const refined = exceptTargs.reduce((filtered, filter) => {
const targDetailsIdx = allTargets.findIndex((targ) => targ.name === filter);
if (targDetailsIdx === -1) {
filtered.unmatched.push(filter);
}
else {
filtered.matched.splice(targDetailsIdx, 1);
}
return filtered;
}, {
matched: allTargets,
unmatched: []
});
if (refined.unmatched.length > 0) {
(0, index_1.message)(`The filters ${(0, ansi_colors_1.bold)(refined.unmatched.join(', '))} provided with --except option does not match with any AppSail in ${constants_1.FILENAME.config}, hence ignored.`);
}
return refined.matched;
}
return allTargets;
}
function validateAppSail(targDetails) {
return __awaiter(this, void 0, void 0, function* () {
let isSocket;
const getImageInfo = (target) => __awaiter(this, void 0, void 0, function* () {
switch (true) {
case target.source.startsWith(appsail_1.CONTAINER_IMAGE_PROTOCOLS.docker): {
const imgTag = target.source.replace(appsail_1.CONTAINER_IMAGE_PROTOCOLS.docker, '');
return (0, image_1.inspectImage)(imgTag);
}
case target.source.startsWith(appsail_1.CONTAINER_IMAGE_PROTOCOLS.dockerArchive): {
const imgTar = target.source.replace(appsail_1.CONTAINER_IMAGE_PROTOCOLS.dockerArchive, '');
const isFile = yield fs_1.ASYNC.fileExists(imgTar);
if (!isFile) {
throw new error_1.default('Invalid image tar path: ' + imgTar, { exit: 1 });
}
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
var _a;
try {
const manifestJsonStream = yield (0, image_1.getTarEntry)(imgTar, 'manifest.json');
const repositoriesStream = yield (0, image_1.getTarEntry)(imgTar, 'repositories');
const indexJsonStream = yield (0, image_1.getTarEntry)(imgTar, 'index.json');
if (!indexJsonStream) {
if (manifestJsonStream || repositoriesStream) {
throw new error_1.default('Legacy docker-archive format is not supported. Only OCI-compliant docker-archive formats (pure OCI or hybrid OCI) are supported.', { exit: 1 });
}
throw new error_1.default('Corrupted image tar :: required OCI metadata index.json not found in the tar', { exit: 1 });
}
const indexJson = yield fs_1.ASYNC.readStreamAsJSON(indexJsonStream);
if (indexJson.schemaVersion !== 2) {
throw new error_1.default('Corrupted image tar :: invalid index.json file. Unsupported schemaVersion', { exit: 1 });
}
const traversedDigests = new Set();
const resolveImageManifestPath = (manifestIndex, sourceFile) => __awaiter(this, void 0, void 0, function* () {
var _a;
const imageDescriptor = (_a = manifestIndex.manifests) === null || _a === void 0 ? void 0 : _a.find((manifest) => {
if (!(manifest === null || manifest === void 0 ? void 0 : manifest.digest)) {
return false;
}
if (!manifest.mediaType) {
return true;
}
return (OCI_IMAGE_MANIFEST_MEDIA_TYPES.includes(manifest.mediaType) ||
OCI_IMAGE_INDEX_MEDIA_TYPES.includes(manifest.mediaType));
});
if (!(imageDescriptor === null || imageDescriptor === void 0 ? void 0 : imageDescriptor.digest)) {
throw new error_1.default(`Corrupted image tar :: invalid ${sourceFile} file. Unable to identify image manifest`, { exit: 1 });
}
if (traversedDigests.has(imageDescriptor.digest)) {
throw new error_1.default(`Corrupted image tar :: circular descriptor reference found for digest ${imageDescriptor.digest}`, { exit: 1 });
}
if (!imageDescriptor.mediaType ||
OCI_IMAGE_MANIFEST_MEDIA_TYPES.includes(imageDescriptor.mediaType)) {
return getBlobPathFromDigest(imageDescriptor.digest, sourceFile);
}
traversedDigests.add(imageDescriptor.digest);
const nestedIndexPath = getBlobPathFromDigest(imageDescriptor.digest, sourceFile);
const nestedIndexStream = yield (0, image_1.getTarEntry)(imgTar, nestedIndexPath);
if (!nestedIndexStream) {
throw new error_1.default(`Corrupted image tar :: nested image index ${nestedIndexPath} not found in the tar`, { exit: 1 });
}
const nestedIndex = yield fs_1.ASYNC.readStreamAsJSON(nestedIndexStream);
if (nestedIndex.schemaVersion !== 2) {
throw new error_1.default(`Corrupted image tar :: invalid nested image index ${nestedIndexPath}. Unsupported schemaVersion`, { exit: 1 });
}
return resolveImageManifestPath(nestedIndex, nestedIndexPath);
});
const imageManifestPath = yield resolveImageManifestPath(indexJson, 'index.json');
const imageManifestStream = yield (0, image_1.getTarEntry)(imgTar, imageManifestPath);
if (!imageManifestStream) {
throw new error_1.default(`Corrupted image tar :: image manifest ${imageManifestPath} not found in the tar`, { exit: 1 });
}
const imageManifest = yield fs_1.ASYNC.readStreamAsJSON(imageManifestStream);
if (imageManifest.schemaVersion !== 2) {
throw new error_1.default('Corrupted image tar :: invalid image manifest file. Unsupported schemaVersion', { exit: 1 });
}
const configDigest = (_a = imageManifest.config) === null || _a === void 0 ? void 0 : _a.digest;
if (!configDigest) {
throw new error_1.default('Corrupted image tar :: invalid image manifest file. Unable to identify the config blob', { exit: 1 });
}
const configBlobPath = getBlobPathFromDigest(configDigest, imageManifestPath);
const configFileStream = yield (0, image_1.getTarEntry)(imgTar, configBlobPath);
if (!configFileStream) {
throw new error_1.default(`Corrupted image tar :: config blob ${configBlobPath} not found in the tar`, { exit: 1 });
}
const configFile = yield fs_1.ASYNC.readStreamAsJSON(configFileStream);
resolve(configFile);
}
catch (er) {
er instanceof error_1.default
? reject(er)
: reject(error_1.default.getErrorInstance(er));
}
}));
}
default: {
throw new error_1.default('Unsupported image source: ' + target.source, { exit: 1 });
}
}
});
const _details = targDetails.map((targ) => __awaiter(this, void 0, void 0, function* () {
var _a, _b;
if (targ.validity.valid) {
if (targ.runtime === 'custom') {
if (isSocket === undefined) {
isSocket = yield (0, container_1.isSocketAccessible)(false);
}
if (isSocket === false) {
targ.validity = {
valid: false,
reason: 'ZCatalyst-CLI is unable to communicate with the Container runtime'
};
return targ;
}
try {
const imgInfo = (yield getImageInfo(targ));
const os = 'os' in imgInfo ? imgInfo.os : imgInfo.Os;
if ((os === null || os === void 0 ? void 0 : os.toLowerCase()) !== 'linux') {
targ.validity = {
valid: false,
reason: 'container image should be Linux based'
};
return targ;
}
const arch = 'architecture' in imgInfo
? imgInfo.architecture
: imgInfo.Architecture;
if ((arch === null || arch === void 0 ? void 0 : arch.toLowerCase()) !== 'amd64') {
targ.validity = {
valid: false,
reason: 'container image should be amd64 based'
};
return targ;
}
}
catch (er) {
targ.validity = {
valid: false,
reason: er instanceof error_1.default ? er.message : (0, util_1.inspect)(er)
};
}
return targ;
}
if (((_a = targ.config) === null || _a === void 0 ? void 0 : _a.platform) !== 'war' && !((_b = targ.config) === null || _b === void 0 ? void 0 : _b.command)) {
targ.validity = {
valid: false,
reason: 'Start-up command missing'
};
return targ;
}
}
return targ;
}));
return Promise.all(_details);
});
}