UNPKG

@controlplane/cli

Version:

Control Plane Corporation CLI

187 lines 8.96 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WorkloadReadiness = void 0; exports.getWorkloadHealth = getWorkloadHealth; exports.describeDeploymentStatus = describeDeploymentStatus; exports.getWorkloadEndpoint = getWorkloadEndpoint; exports.extractSecretNames = extractSecretNames; // ANCHOR - Types /** * Possible values of the `readiness` string in a workload's server-computed health object (`workload.health.readiness`). * The numeric prefix orders the values from most to least ready (0 = best, 2 = worst), mirroring the data-service. */ var WorkloadReadiness; (function (WorkloadReadiness) { // The latest workload version is ready in every active location. WorkloadReadiness["LatestReady"] = "0_latestReady"; // At least one location is ready, but the latest version is not ready everywhere. WorkloadReadiness["Ready"] = "1_ready"; // No location is ready. WorkloadReadiness["NotReady"] = "2_notReady"; })(WorkloadReadiness || (exports.WorkloadReadiness = WorkloadReadiness = {})); // SECTION - Functions /** * Derives readiness flags from a workload's server-computed health object instead of fetching its deployments. * * @param {WorkloadHealth | undefined} health - The health object returned on the workload (`workload.health`). * @returns {WorkloadHealthObject} The derived readiness flags and the time the check was evaluated. */ function getWorkloadHealth(health) { // Timestamp to record when the readiness was evaluated const readyCheckTimestamp = new Date().toISOString(); // Parse the readiness string from the health object const readiness = health === null || health === void 0 ? void 0 : health.readiness; // Map the readiness string onto the ready/readyLatest flags switch (readiness) { // Latest version is ready everywhere case WorkloadReadiness.LatestReady: return { ready: true, readyLatest: true, readyCheckTimestamp }; // Ready, but not on the latest version in every location case WorkloadReadiness.Ready: return { ready: true, readyLatest: false, readyCheckTimestamp }; // Not ready, unknown, or missing health (older server / not yet computed) case WorkloadReadiness.NotReady: default: return { ready: false, readyLatest: false, readyCheckTimestamp }; } } /** * Describes what the platform reports about a deployment's expected version. * * @param {Deployment} deployment - The deployment to describe, as returned from `.../deployment/<location>`. * @param {string} containerName - The name of the container the caller is waiting on. * @returns {DeploymentStatusReport} Whether the target container is ready, a summary, and the remote endpoint. */ function describeDeploymentStatus(deployment, containerName) { var _a, _b; const status = deployment.status; // The platform has not created a deployment record for this location yet if (!status || !status.remote) { return { isContainerReady: false, summary: 'no deployment record yet' }; } const remote = status.remote; const expectedVersion = status.expectedDeploymentVersion; // The platform has not reported on the version we are waiting for yet const version = (_a = status.versions) === null || _a === void 0 ? void 0 : _a.find((candidate) => candidate.workload === expectedVersion); if (!version) { return { isContainerReady: false, summary: `waiting for the platform to report on version ${expectedVersion}`, remote }; } // The target container is ready to accept the command const container = (_b = version.containers) === null || _b === void 0 ? void 0 : _b[containerName]; if (container === null || container === void 0 ? void 0 : container.ready) { return { isContainerReady: true, summary: `container '${containerName}' is ready`, remote }; } return { isContainerReady: false, summary: summarizeVersion(version, status, containerName), remote }; } /** * Summarizes a version that is not ready, naming the pending containers and the platform's messages. * * @param {DeploymentVersion} version - The deployment version the caller is waiting on. * @param {DeploymentStatus} status - The enclosing deployment status. * @param {string} containerName - The name of the container the caller is waiting on. * @returns {string} A semicolon-separated summary of the version's current state. */ function summarizeVersion(version, status, containerName) { const parts = [`version ${version.workload}`]; // The platform omits this flag unless it is actively rolling the version out if (status.deploying === true) { parts.push('rolling out'); } const pending = pendingContainerNames(version); if (pending.length > 0) { parts.push(`containers not ready: ${pending.join(', ')}`); } const messages = platformMessages(version, status, containerName); if (messages.length > 0) { parts.push(messages.join(' | ')); } return parts.join('; '); } /** * Returns the names of the version's containers that have not become ready yet. * * @param {DeploymentVersion} version - The deployment version whose containers to inspect. * @returns {string[]} The names of the containers that are not ready, in the order the platform lists them. */ function pendingContainerNames(version) { const containers = version.containers; if (!containers) { return []; } return Object.entries(containers) .filter(([, container]) => !container.ready) .map(([name]) => name); } /** * Collects the distinct messages on the version, its containers, and the deployment status, leading * with the target container's own message. * * @param {DeploymentVersion} version - The deployment version to read messages from. * @param {DeploymentStatus} status - The enclosing deployment status. * @param {string} containerName - The name of the container the caller is waiting on. * @returns {string[]} The distinct non-blank messages, trimmed, in order of relevance. */ function platformMessages(version, status, containerName) { var _a; const containers = version.containers; const siblingMessages = Object.entries(containers !== null && containers !== void 0 ? containers : {}) .filter(([name]) => name !== containerName) .map(([, sibling]) => sibling.message); const candidates = [(_a = containers === null || containers === void 0 ? void 0 : containers[containerName]) === null || _a === void 0 ? void 0 : _a.message, ...siblingMessages, version.message, status.message]; const distinct = new Set(); for (const candidate of candidates) { if (candidate && candidate.trim().length > 0) { distinct.add(candidate.trim()); } } return Array.from(distinct); } /** * Returns the workload's canonical published endpoint, if it has one. Single source of * truth for reading `workload.status.canonicalEndpoint` — the stable endpoint, not the input. * * @param {Workload} workload - The workload to read the endpoint from. * @returns {string | undefined} The canonical endpoint URL, or undefined if not present. */ function getWorkloadEndpoint(workload) { var _a; return (_a = workload.status) === null || _a === void 0 ? void 0 : _a.canonicalEndpoint; } function extractSecretNames(workload) { var _a, _b; // Initialize an empty set for secret names const secretNames = new Set(); // Regex to match secret references const secretRegex = /cpln:\/\/secret\/(.+)|\/org\/[^/]+\/secret\/(.+)/; // Process containers in the workload (_b = (_a = workload.spec) === null || _a === void 0 ? void 0 : _a.containers) === null || _b === void 0 ? void 0 : _b.forEach((container) => { var _a, _b; // Process environment variables (_a = container.env) === null || _a === void 0 ? void 0 : _a.forEach((envVar) => addSecretName(envVar.value, secretNames, secretRegex)); // Process volumes (_b = container.volumes) === null || _b === void 0 ? void 0 : _b.forEach((volume) => addSecretName(volume.uri, secretNames, secretRegex)); }); // Return the set of unique secret names return secretNames; } function addSecretName(value, secretNames, secretRegex) { var _a; // Skip if the value is undefined or null or not a string if (!value || typeof value !== 'string') { return; } // Match secret reference in the value const match = value.match(secretRegex); // Skip if there was no match if (!match) { return; } // Extract the name before the dot const secretName = (_a = (match[1] || match[2])) === null || _a === void 0 ? void 0 : _a.split('.')[0]; // Add the secret name to the set if found if (secretName) { secretNames.add(secretName); } } // !SECTION //# sourceMappingURL=workload.js.map