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