@controlplane/cli
Version:
Control Plane Corporation CLI
187 lines • 8.96 kB
JavaScript
;
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