UNPKG

@multicloud-io/multicloud-connection-js

Version:

Shared TypeScript/JavaScript library for connecting to Multicloud servers with mTLS authentication

328 lines 11.5 kB
"use strict"; /** * Multicloud REST API client * * Provides a comprehensive client for interacting with Multicloud servers * with mTLS authentication and proper error handling. * * IMPORTANT: This is for server-side use only - never expose to client/browser! */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MulticloudRESTClient = exports.TaskStatus = exports.Orchestration = exports.State = void 0; const https_1 = __importDefault(require("https")); const fs_1 = __importDefault(require("fs")); const exceptions_1 = require("./exceptions"); /** * State of the job */ var State; (function (State) { State["LOADED"] = "LOADED"; State["STARTING"] = "STARTING"; State["RUNNING"] = "RUNNING"; State["STOPPING"] = "STOPPING"; State["STOPPED"] = "STOPPED"; State["PENDING_DESTROY"] = "PENDING_DESTROY"; State["FINISHED"] = "FINISHED"; })(State || (exports.State = State = {})); /** * Orchestration types */ var Orchestration; (function (Orchestration) { Orchestration["EXTERNAL"] = "EXTERNAL"; Orchestration["ALL"] = "ALL"; Orchestration["EXACTLY"] = "EXACTLY"; Orchestration["EXACTLY_ONCE"] = "EXACTLY_ONCE"; Orchestration["ACTIVE_STANDBY"] = "ACTIVE_STANDBY"; // Add other values as needed })(Orchestration || (exports.Orchestration = Orchestration = {})); /** * Status of the task */ var TaskStatus; (function (TaskStatus) { TaskStatus["UNKNOWN"] = "UNKNOWN"; TaskStatus["STARTING"] = "STARTING"; TaskStatus["STANDBY"] = "STANDBY"; TaskStatus["RUNNING"] = "RUNNING"; TaskStatus["RESTARTING"] = "RESTARTING"; TaskStatus["STOPPING"] = "STOPPING"; TaskStatus["STOPPED"] = "STOPPED"; TaskStatus["DONE"] = "DONE"; TaskStatus["ERROR"] = "ERROR"; TaskStatus["PENDING_SHUTDOWN"] = "PENDING_SHUTDOWN"; TaskStatus["PENDING_RESTART"] = "PENDING_RESTART"; TaskStatus["CANCELLED"] = "CANCELLED"; })(TaskStatus || (exports.TaskStatus = TaskStatus = {})); /** * REST client for Multicloud API */ class MulticloudRESTClient { constructor(params) { this.baseUrl = params.serverUrl.replace(/\/$/, ''); // Remove trailing slash this.timeout = params.timeout; this.debug = params.debug; this.accessToken = params.accessToken; // Create HTTPS agent with mTLS configuration const agentOptions = { rejectUnauthorized: params.verifySsl, }; // Add client certificates if provided if (params.clientCert && params.clientKey) { try { agentOptions.cert = fs_1.default.readFileSync(params.clientCert); agentOptions.key = fs_1.default.readFileSync(params.clientKey); if (this.debug) { console.log('[MulticloudRESTClient] Loaded mTLS certificates'); } } catch (error) { throw new exceptions_1.MulticloudAuthenticationError(`Failed to load client certificates: ${error}`, error instanceof Error ? error : undefined); } } this.agent = new https_1.default.Agent(agentOptions); if (this.debug) { console.log('[MulticloudRESTClient] Initialized client:', { baseUrl: this.baseUrl, verifySsl: params.verifySsl, timeout: this.timeout, hasCertificates: !!(params.clientCert && params.clientKey) }); } } /** * Make an HTTP request to the Multicloud API */ async makeRequest(method, endpoint, body) { const url = `${this.baseUrl}${endpoint}`; if (this.debug) { console.log(`[MulticloudRESTClient] ${method} ${url}`); } return new Promise((resolve, reject) => { const options = { method, agent: this.agent, timeout: this.timeout, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, }; // Add Authorization header if access token is available if (this.accessToken) { options.headers['Authorization'] = `Bearer ${this.accessToken}`; } const req = https_1.default.request(url, options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { try { if (this.debug) { console.log(`[MulticloudRESTClient] Response status: ${res.statusCode}`); } if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) { reject(new exceptions_1.MulticloudNetworkError(`HTTP ${res.statusCode}: ${res.statusMessage}. Details: ${data}`, res.statusCode)); return; } // Handle empty responses if (!data.trim()) { resolve(null); return; } const result = JSON.parse(data); resolve(result); } catch (error) { reject(new exceptions_1.MulticloudResponseError(`Failed to parse response: ${error}`, error instanceof Error ? error : undefined)); } }); }); req.on('error', (error) => { if (error.message.includes('ECONNREFUSED')) { reject(new exceptions_1.MulticloudConnectionError(`Connection refused to ${this.baseUrl}. Is the Multicloud server running?`, error)); } else if (error.message.includes('certificate')) { reject(new exceptions_1.MulticloudAuthenticationError(`Certificate authentication failed: ${error.message}`, error)); } else { reject(new exceptions_1.MulticloudNetworkError(`Network error: ${error.message}`, undefined, error)); } }); req.on('timeout', () => { req.destroy(); reject(new exceptions_1.MulticloudNetworkError(`Request timeout after ${this.timeout}ms`)); }); // Send request body if provided if (body) { req.write(JSON.stringify(body)); } req.end(); }); } /** * Update the access token for subsequent requests * @param accessToken New JWT access token */ setAccessToken(accessToken) { this.accessToken = accessToken; if (this.debug) { console.log('[MulticloudRESTClient] Access token updated'); } } /** * Clear the access token */ clearAccessToken() { this.accessToken = undefined; if (this.debug) { console.log('[MulticloudRESTClient] Access token cleared'); } } /** * Test connection to the Multicloud server */ async testConnection() { try { // Try to get a simple endpoint to test connectivity await this.makeRequest('GET', '/health'); return true; } catch (error) { if (this.debug) { console.log('[MulticloudRESTClient] Connection test failed:', error); } throw error; } } /** get tasks for a cluster, or if null or it "*" for all clusters */ async getTasks(clusterId) { if (clusterId === null || clusterId === "*" || clusterId === undefined) { return this.makeRequest('GET', '/coordinator/tasks'); } else { return this.makeRequest('GET', `/coordinator/tasks?clusterId=${clusterId}`); } } /** * Get all clusters */ async getClusters() { return this.makeRequest('GET', '/admin/clusters'); } /** * Get clusters for a specific application - Uses application-specific filtering */ async getApplicationClusters(applicationId) { return this.makeRequest('GET', `/applications/clusters?applicationId=${applicationId}`); } /** * Get a specific cluster by ID */ async getCluster(clusterId) { return this.makeRequest('GET', `/admin/clusters/${clusterId}`); } /** * Get all jobs */ async getJobs() { return this.makeRequest('GET', '/coordinator/jobs'); } /** * Get jobs for a specific cluster */ async getClusterJobs(clusterId) { return this.makeRequest('GET', `/coordinator/jobs?clusterId=${clusterId}`); } /** * Get a specific job by ID */ async getJob(jobId) { return this.makeRequest('GET', `/coordinator/jobs/${jobId}`); } /** * Create a new job */ async createJob(clusterId, jobData) { return this.makeRequest('POST', `/coordinator/job?clusterId=${clusterId}`, jobData); } /** * Update a job */ async updateJob(action, jobId, clusterId) { const params = new URLSearchParams({ action }); // Only append clusterId if it's not null if (clusterId) { params.append('clusterId', clusterId); params.append('action', action); } return this.makeRequest('PUT', `/coordinator/job/${jobId}?${params.toString()}`); // Updated to return Response } /** * Delete a job */ async deleteJob(jobId) { return this.makeRequest('DELETE', `/coordinator/jobs/${jobId}`); } /** * Get all servers */ async getServers() { return this.makeRequest('GET', '/admin/servers'); } /** * Get servers for a specific cluster */ async getClusterServers(clusterId) { return this.makeRequest('GET', `/admin/servers?clusterId=${clusterId}`); } /** * Get a specific server by ID */ async getServer(serverId) { return this.makeRequest('GET', `/admin/servers/${serverId}`); } /** * Create a new server */ async createServer(serverData) { return this.makeRequest('POST', '/admin/servers', serverData); } /** * Update a server */ async updateServer(serverId, serverData) { return this.makeRequest('PUT', `/admin/servers/${serverId}`, serverData); } /** * Delete a server */ async deleteServer(serverId) { return this.makeRequest('DELETE', `/admin/servers/${serverId}`); } /** * Get server status */ async getServerStatus(serverId) { return this.makeRequest('GET', `/admin/servers/${serverId}/status`); } /** * Restart a server */ async restartServer(serverId) { return this.makeRequest('POST', `/admin/servers/${serverId}/restart`); } /** * Get all MetaLocations for a cluster (id, name, region, url) */ async getClusterLocations(clusterId) { return this.makeRequest('GET', `/admin/cluster/${clusterId}/locations`); } } exports.MulticloudRESTClient = MulticloudRESTClient; //# sourceMappingURL=client.js.map