UNPKG

@controlplane/cli

Version:

Control Plane Corporation CLI

285 lines 12.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.decodeReleaseFromSecret = exports.encodeRelease = exports.getReleaseSecretNameLegacy = exports.getReleaseSecretNameWithoutRevision = exports.getReleaseSecretName = exports.extractHelmConfig = exports.extractHelmDefaultValues = exports.extractHelmCustomValues = exports.extractHelmChartMetadata = exports.getTemplateResources = exports.generateHelmTemplate = exports.processHelmArgs = void 0; const path = require("path"); const jsyaml = require("js-yaml"); const child_process_1 = require("child_process"); const names_1 = require("../util/names"); const fs_1 = require("fs"); const io_1 = require("../util/io"); const pako_1 = require("pako"); const constants_1 = require("./constants"); const objects_1 = require("../util/objects"); // Exported // function processHelmArgs(args) { // A user cannot specify a generate release name and a release name at the same time if (args.release && args.chart && args.generateName) { throw new Error('ERROR: Cannot set --generate-name and also specify a release name'); } // Generate a random name if (args.generateName || !args.release) { // If the release positional is defined with a value, then it must be the path to the // chart since generate name and release cannot be specified together if (args.release && !args.chart) { args.chart = args.release; } // Release will now have a random name args.release = (0, names_1.nextName)(); // Will produce an 8 character long random string } else { // If we got here, then the release name has been specified by the user, in // that case, let's validate the length of the specified relase name if (args.release.length > constants_1.CPLN_HELM_RELEASE_MAX_LENGTH) { throw new Error(`ERROR: Release name "${args.release}" exceeds max length of ${constants_1.CPLN_HELM_RELEASE_MAX_LENGTH}.`); } } // Use current directory for the chart path if it is not specified if (!args.chart) { args.chart = '.'; } } exports.processHelmArgs = processHelmArgs; function generateHelmTemplate(args, org, gvc, debug) { var _a, _b, _c, _d, _e, _f; let options = []; const customOptions = [ // Placeholder comment to ensure each item is on a new line `--set cpln.org=${org}`, `--set globals.cpln.org=${org}`, `--set global.cpln.org=${org}`, ]; if (gvc) { customOptions.push(`--set cpln.gvc=${gvc}`); customOptions.push(`--set globals.cpln.gvc=${gvc}`); customOptions.push(`--set global.cpln.gvc=${gvc}`); } // Handle helm template options if (args.set && args.set.length > 0) { if (typeof args.set === 'string') { args.set = [args.set]; } options.push(args.set.map((set) => `--set ${safeSet(set)}`).join(' ')); } if (args.setString) { if (typeof args.setString === 'string') { args.setString = [args.setString]; } options.push(args.setString.map((setString) => `--set-string ${safeSet(setString)}`).join(' ')); } if (args.setFile) { if (typeof args.setFile === 'string') { args.setFile = [args.setFile]; } options.push(args.setFile.map((setFile) => `--set-file ${safeSet(setFile)}`).join(' ')); } if (args.dependencyUpdate) { options.push(`--dependency-update`); } if (args.description) { options.push(`--description "${args.description}"`); } if (args.postRenderer) { options.push(`--post-renderer ${args.postRenderer}`); } if (args.postRendererArgs && args.postRendererArgs.length > 0) { if (typeof args.postRendererArgs === 'string') { args.postRendererArgs = [args.postRendererArgs]; } options.push(args.postRendererArgs.map((postRendererArgs) => `--post-renderer-args ${safeSet(postRendererArgs)}`).join(' ')); } if (args.repo) { options.push(`--repo ${args.repo}`); } if (args.values && args.values.length > 0) { if (typeof args.values === 'string') { args.values = [args.values]; } options.push(args.values.map((values) => `--values ${values}`).join(' ')); } if (args.verify) { options.push(`--verify`); } if (debug) { options.push(`--debug`); } const helmTemplateCommand = `helm template ${args.release} ${args.chart} ${options.join(' ')} ${customOptions.join(' ')}`; try { // Make sure output is NOT inherited by the parent process return (0, child_process_1.execSync)(helmTemplateCommand, { stdio: 'pipe', encoding: 'utf8', maxBuffer: 10 * 1024 * 1024, }); } catch (e) { const stderr = (_c = (_b = (_a = e === null || e === void 0 ? void 0 : e.stderr) === null || _a === void 0 ? void 0 : _a.toString) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : ''; const stdout = (_f = (_e = (_d = e === null || e === void 0 ? void 0 : e.stdout) === null || _d === void 0 ? void 0 : _d.toString) === null || _e === void 0 ? void 0 : _e.call(_d)) !== null && _f !== void 0 ? _f : ''; // Helm sometimes mixes channels const combined = `${stderr}${stdout}`.trim(); // Check for the specific "missing dependencies" failure if (combined.includes(constants_1.HELM_DEPENDENCY_MISSING_ERROR)) { throw new Error('ERROR: Helm chart dependencies are missing. You may need to re-run the command with the `--dependency-update` option to fetch missing dependencies.'); } // Otherwise, surface only the tool's message (not the Node stack) throw new Error(combined || e.message || 'ERROR: helm template command failed for unknown reasons.'); } } exports.generateHelmTemplate = generateHelmTemplate; function getTemplateResources(session, args, org, gvc) { // Print verbose if (args.debug || args.verbose) { session.out(generateHelmTemplate(args, org, gvc, (args.debug || args.verbose))); } // Generate a Helm template using the Helm template CLI command const template = generateHelmTemplate(args, org, gvc); // Load template output into cpln resources const templateResources = jsyaml.safeLoadAll(template).filter((item) => item !== null && typeof item === 'object'); // Sort by kind priority (0, objects_1.sortIHasKindByPriority)(templateResources, false); // Template resources cannot be empty if (templateResources.length === 0) { session.abort({ message: 'ERROR: There were no resources found in the generated template. Make sure you have templates in your chart.', }); } // Return the template resources return templateResources; } exports.getTemplateResources = getTemplateResources; function extractHelmChartMetadata(chartDirPath) { const filePath = path.join(chartDirPath, 'Chart.yaml'); return (0, io_1.loadObject)((0, fs_1.readFileSync)(filePath, 'utf-8')); } exports.extractHelmChartMetadata = extractHelmChartMetadata; function extractHelmCustomValues(pathsToValues) { let values = []; // Read and add custom values if specified if (pathsToValues) { if (typeof pathsToValues === 'string') { pathsToValues = [pathsToValues]; } // Iterate over each custom values path and add it for (const path of pathsToValues) { const customValues = (0, fs_1.readFileSync)(path, 'utf-8'); if (customValues) { values.push(customValues.trim()); } } } return values; } exports.extractHelmCustomValues = extractHelmCustomValues; function extractHelmDefaultValues(chartDirPath) { return jsyaml.load((0, child_process_1.execSync)(`helm show values ${chartDirPath}`).toString()); } exports.extractHelmDefaultValues = extractHelmDefaultValues; function extractHelmConfig(args, valuesFiles) { let config = {}; // Apply "values" for (const valuesFile of valuesFiles) { Object.assign(config, jsyaml.safeLoad(valuesFile)); } // Apply "set" applySetProperty(config, args.set); // Apply "set-string" applySetProperty(config, args.setString); // Apply "set-file" applySetFileProperty(config, args.setFile); return config; } exports.extractHelmConfig = extractHelmConfig; function getReleaseSecretName(release, revision) { // Construct the name of the secret const name = `${constants_1.CPLN_RELEASE_NAME_PREFIX}-${release}`; // Make the name safe const safeName = (0, names_1.safeCplnName)(59, name); // Append the version number to the safe name and return it return `${safeName}-v${revision}`; } exports.getReleaseSecretName = getReleaseSecretName; function getReleaseSecretNameWithoutRevision(release) { // Get the secret name of the release using 0 as the version number const name = getReleaseSecretName(release, 0); // The length of the version part is 3 ('-v0'.length === 3) const versionPartLength = 3; // Trim out the verion part and return the secret name return name.substring(0, name.length - versionPartLength); } exports.getReleaseSecretNameWithoutRevision = getReleaseSecretNameWithoutRevision; function getReleaseSecretNameLegacy(release) { return `${constants_1.CPLN_RELEASE_NAME_PREFIX_LEGACY}-${release}`; } exports.getReleaseSecretNameLegacy = getReleaseSecretNameLegacy; async function encodeRelease(release) { // Gzip the release object const gzipped = (0, pako_1.gzip)(JSON.stringify(release)); // Base64-encode and return return Buffer.from(gzipped).toString('base64'); } exports.encodeRelease = encodeRelease; function decodeReleaseFromSecret(secret) { // If the secret is not valid, throw an error if (!secret.data || !secret.data.payload) { throw new Error('ERROR: Invalid release revision secret data.'); } // Decode the base64-encoded payload const decoded = Buffer.from(secret.data.payload, 'base64'); // Gunzip the decoded data const gunzipped = (0, pako_1.ungzip)(new Uint8Array(decoded), { to: 'string' }); // Parse the JSON and return the release object return JSON.parse(gunzipped); } exports.decodeReleaseFromSecret = decodeReleaseFromSecret; // Local // function safeSet(input) { const index = input.indexOf('='); if (index === -1) { return input; } const key = input.substring(0, index); const value = input.substring(index + 1); return `"${key}"="${value}"`; } function applySetProperty(config, input) { if (!input) { return; } // Make sure we have an array const entries = Array.isArray(input) ? input : [input]; // Iterate over each entry and update config for (const entry of entries) { const index = entry.indexOf('='); // Skip entry if it doesn't have an equal sign, it will be caught later by helm template command if (index === -1) { continue; } const key = entry.substring(0, index); const value = entry.substring(index + 1); // Update helm config config[key] = value; } } function applySetFileProperty(config, input) { if (!input) { return; } // Make sure we have an array const entries = Array.isArray(input) ? input : [input]; // Iterate over each entry and update config for (const entry of entries) { const index = entry.indexOf('='); // Skip entry if it doesn't have an equal sign, it will be caught later by helm template command if (index === -1) { continue; } const key = entry.substring(0, index); const value = entry.substring(index + 1); // Skip if the path in value doesn't exists, it will be caught later by helm template command if (!(0, fs_1.existsSync)(value)) { continue; } // Update helm config config[key] = (0, fs_1.readFileSync)(value, 'utf-8'); } } //# sourceMappingURL=functions.js.map