UNPKG

@controlplane/cli

Version:

Control Plane Corporation CLI

327 lines 10.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.kubectl = exports.Kubectl = exports.KubectlError = void 0; const child_process_1 = require("child_process"); /** * Error thrown when kubectl command fails. */ class KubectlError extends Error { constructor(message, command, exitCode, stderr) { super(message); this.command = command; this.exitCode = exitCode; this.stderr = stderr; this.name = 'KubectlError'; } } exports.KubectlError = KubectlError; // ============================================================================ // Kubectl Client Class // ============================================================================ /** * A client for interacting with Kubernetes clusters via kubectl. * * @example * ```typescript * const kubectl = new Kubectl(); * * // Check availability * const status = kubectl.checkAvailability(); * if (!status.installed) { * console.error('kubectl is not installed'); * } * * // Get a secret * const secret = kubectl.getSecret('my-secret', 'my-namespace'); * * // Apply a resource * kubectl.apply(myResource, 'my-namespace'); * ``` */ class Kubectl { // ========================================================================== // Core Execution Methods // ========================================================================== /** * Executes a kubectl command and returns the output. * * @param args - The kubectl arguments (without the 'kubectl' prefix). * @param options - Execution options. * @returns The command output as a string. * @throws {KubectlError} If the command fails and ignoreErrors is false. */ exec(args, options = {}) { var _a; const { input, namespace, ignoreErrors } = options; // Build the full command let command = `kubectl ${args}`; if (namespace) { command += ` -n ${namespace}`; } try { return (0, child_process_1.execSync)(command, { encoding: 'utf8', input, stdio: input ? ['pipe', 'pipe', 'pipe'] : undefined, }).trim(); } catch (error) { if (ignoreErrors) { return ''; } const stderr = ((_a = error.stderr) === null || _a === void 0 ? void 0 : _a.toString().trim()) || error.message; throw new KubectlError(stderr, command, error.status, stderr); } } /** * Executes a kubectl command and parses the JSON output. * * @param args - The kubectl arguments (without the 'kubectl' prefix). * @param options - Execution options. * @returns The parsed JSON output. * @throws {KubectlError} If the command fails. */ execJson(args, options = {}) { const output = this.exec(`${args} -o json`, options); return JSON.parse(output); } // ========================================================================== // Availability & Health Checks // ========================================================================== /** * Checks if kubectl is installed and if the cluster is reachable. * * @returns An object describing kubectl availability. */ checkAvailability() { var _a; const result = { installed: false, clusterReachable: false, }; // Check if kubectl is installed try { const versionOutput = this.exec('version --client -o json', { ignoreErrors: false }); const versionInfo = JSON.parse(versionOutput); result.installed = true; result.version = (_a = versionInfo.clientVersion) === null || _a === void 0 ? void 0 : _a.gitVersion; } catch (error) { result.error = 'kubectl is not installed or not in PATH'; return result; } // Check if the cluster is reachable try { this.exec('cluster-info', { ignoreErrors: false }); result.clusterReachable = true; } catch (error) { result.error = error.message || 'Cluster is not reachable'; } return result; } /** * Checks if kubectl is installed. * * @returns True if kubectl is installed. */ isInstalled() { try { this.exec('version --client', { ignoreErrors: false }); return true; } catch (_a) { return false; } } /** * Checks if the Kubernetes cluster is reachable. * * @returns True if the cluster is reachable. */ isClusterReachable() { try { this.exec('cluster-info', { ignoreErrors: false }); return true; } catch (_a) { return false; } } // ========================================================================== // Namespace Operations // ========================================================================== /** * Gets a namespace by name. * * @param name - The namespace name. * @returns The namespace object, or null if not found. */ getNamespace(name) { try { return this.execJson(`get namespace ${name}`); } catch (error) { if (this.isNotFoundError(error)) { return null; } throw error; } } /** * Creates a namespace. * * @param name - The namespace name to create. * @returns The created namespace object. */ createNamespace(name) { this.exec(`create namespace ${name}`); return this.getNamespace(name); } /** * Ensures a namespace exists, creating it if necessary. * * @param name - The namespace name. * @returns True if the namespace was created, false if it already existed. */ ensureNamespace(name) { if (this.getNamespace(name)) { return false; } this.createNamespace(name); return true; } /** * Deletes a namespace. * * @param name - The namespace name to delete. */ deleteNamespace(name) { this.exec(`delete namespace ${name}`); } // ========================================================================== // Secret Operations // ========================================================================== /** * Gets a secret by name. * * @param name - The secret name. * @param namespace - The namespace (optional). * @returns The secret object, or null if not found. */ getSecret(name, namespace) { try { return this.execJson(`get secret ${name}`, { namespace }); } catch (error) { if (this.isNotFoundError(error)) { return null; } throw error; } } /** * Creates or updates a secret using kubectl apply. * * @param secret - The secret object to apply. * @param namespace - The namespace (optional, can also be in secret.metadata.namespace). */ applySecret(secret, namespace) { const secretJson = JSON.stringify(secret); this.exec('apply -f -', { input: secretJson, namespace }); } /** * Deletes a secret. * * @param name - The secret name. * @param namespace - The namespace (optional). */ deleteSecret(name, namespace) { this.exec(`delete secret ${name}`, { namespace }); } // ========================================================================== // Generic Resource Operations // ========================================================================== /** * Gets a resource by kind and name. * * @param kind - The resource kind (e.g., 'pod', 'deployment'). * @param name - The resource name. * @param namespace - The namespace (optional). * @returns The resource object, or null if not found. */ get(kind, name, namespace) { try { return this.execJson(`get ${kind} ${name}`, { namespace }); } catch (error) { if (this.isNotFoundError(error)) { return null; } throw error; } } /** * Applies a resource using kubectl apply. * * @param resource - The resource object to apply. * @param namespace - The namespace (optional). */ apply(resource, namespace) { const resourceJson = JSON.stringify(resource); this.exec('apply -f -', { input: resourceJson, namespace }); } /** * Deletes a resource by kind and name. * * @param kind - The resource kind. * @param name - The resource name. * @param namespace - The namespace (optional). */ delete(kind, name, namespace) { this.exec(`delete ${kind} ${name}`, { namespace }); } // ========================================================================== // Helper Methods // ========================================================================== /** * Checks if an error is a "not found" error. * * @param error - The error to check. * @returns True if the error indicates the resource was not found. */ isNotFoundError(error) { const message = error.message || error.stderr || ''; return message.includes('NotFound') || message.includes('not found'); } /** * Removes managed fields and other metadata from a resource for clean export. * * @param resource - The resource to clean. * @returns A cleaned copy of the resource. */ cleanForExport(resource) { var _a; const clean = JSON.parse(JSON.stringify(resource)); if ((_a = clean.metadata) === null || _a === void 0 ? void 0 : _a.managedFields) { delete clean.metadata.managedFields; } return clean; } } exports.Kubectl = Kubectl; // ============================================================================ // Default Instance // ============================================================================ /** * Default kubectl client instance for convenience. * * @example * ```typescript * import { kubectl } from './k8s/kubectl'; * * const secret = kubectl.getSecret('my-secret', 'my-namespace'); * ``` */ exports.kubectl = new Kubectl(); //# sourceMappingURL=kubectl.js.map