@multicloud-io/multicloud-connection-js
Version:
Shared TypeScript/JavaScript library for connecting to Multicloud servers with mTLS authentication
557 lines • 21.3 kB
JavaScript
;
/**
* 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.LegacyConstraintType = exports.ConstraintType = exports.TaskAssignmentType = exports.VolumeDescSyncMode = exports.VolumeDescAccessMode = exports.TaskStatus = exports.ProcessorArchitecture = exports.ServerStatus = exports.Orchestration = exports.State = exports.ExtendedLocationRuleType = void 0;
const https_1 = __importDefault(require("https"));
const fs_1 = __importDefault(require("fs"));
const exceptions_1 = require("./exceptions");
/**
* ExtendedLocationRuleType enum for location rules
*/
var ExtendedLocationRuleType;
(function (ExtendedLocationRuleType) {
ExtendedLocationRuleType["INCLUDE_ALL_PROVIDER"] = "INCLUDE_ALL_PROVIDER";
ExtendedLocationRuleType["EXCLUDE_ALL_PROVIDER"] = "EXCLUDE_ALL_PROVIDER";
ExtendedLocationRuleType["INCLUDE_REGION"] = "INCLUDE_REGION";
ExtendedLocationRuleType["EXCLUDE_REGION"] = "EXCLUDE_REGION";
ExtendedLocationRuleType["INCLUDE_PROVIDER_REGION"] = "INCLUDE_PROVIDER_REGION";
ExtendedLocationRuleType["EXCLUDE_PROVIDER_REGION"] = "EXCLUDE_PROVIDER_REGION";
ExtendedLocationRuleType["INCLUDE_LOCATION"] = "INCLUDE_LOCATION";
ExtendedLocationRuleType["EXCLUDE_LOCATION"] = "EXCLUDE_LOCATION";
ExtendedLocationRuleType["INCLUDE_ZONE"] = "INCLUDE_ZONE";
ExtendedLocationRuleType["EXCLUDE_ZONE"] = "EXCLUDE_ZONE";
ExtendedLocationRuleType["INCLUDE_PROVIDER_ZONE"] = "INCLUDE_PROVIDER_ZONE";
ExtendedLocationRuleType["EXCLUDE_PROVIDER_ZONE"] = "EXCLUDE_PROVIDER_ZONE";
})(ExtendedLocationRuleType || (exports.ExtendedLocationRuleType = ExtendedLocationRuleType = {}));
/**
* State enum for job states
*/
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["DONE"] = "DONE";
State["ERROR"] = "ERROR";
})(State || (exports.State = State = {}));
/**
* Orchestration enum for job orchestration types
*/
var Orchestration;
(function (Orchestration) {
Orchestration["EXTERNAL"] = "EXTERNAL";
Orchestration["ALL"] = "ALL";
Orchestration["EXACTLY"] = "EXACTLY";
Orchestration["ACTIVE_STANDBY"] = "ACTIVE_STANDBY";
Orchestration["EXACTLY_ONCE"] = "EXACTLY_ONCE";
Orchestration["CRON"] = "CRON";
})(Orchestration || (exports.Orchestration = Orchestration = {}));
/**
* ServerStatus enum
*/
var ServerStatus;
(function (ServerStatus) {
ServerStatus["PENDING"] = "PENDING";
ServerStatus["UNKNOWN"] = "UNKNOWN";
ServerStatus["INITIALIZING"] = "INITIALIZING";
ServerStatus["STARTING"] = "STARTING";
ServerStatus["RUNNING"] = "RUNNING";
ServerStatus["STOPPING"] = "STOPPING";
ServerStatus["STOPPED"] = "STOPPED";
ServerStatus["ERROR"] = "ERROR";
ServerStatus["PENDING_SHUTDOWN"] = "PENDING_SHUTDOWN";
ServerStatus["TERMINATED"] = "TERMINATED";
})(ServerStatus || (exports.ServerStatus = ServerStatus = {}));
/**
* ProcessorArchitecture enum
*/
var ProcessorArchitecture;
(function (ProcessorArchitecture) {
ProcessorArchitecture["X86_64"] = "X86_64";
ProcessorArchitecture["ARM64"] = "ARM64";
ProcessorArchitecture["UNKNOWN"] = "UNKNOWN";
})(ProcessorArchitecture || (exports.ProcessorArchitecture = ProcessorArchitecture = {}));
/**
* TaskStatus enum
*/
var TaskStatus;
(function (TaskStatus) {
TaskStatus["UNKNOWN"] = "UNKNOWN";
TaskStatus["PENDING"] = "PENDING";
TaskStatus["PENDING_UNASSIGNABLE"] = "PENDING_UNASSIGNABLE";
TaskStatus["ASSIGNED"] = "ASSIGNED";
TaskStatus["STARTING"] = "STARTING";
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 = {}));
/**
* VolumeDesc access mode enum matching Java AccessMode
*/
var VolumeDescAccessMode;
(function (VolumeDescAccessMode) {
VolumeDescAccessMode["RW"] = "rw";
VolumeDescAccessMode["RO"] = "ro";
})(VolumeDescAccessMode || (exports.VolumeDescAccessMode = VolumeDescAccessMode = {}));
/**
* VolumeDesc sync mode enum matching Java SyncMode
*/
var VolumeDescSyncMode;
(function (VolumeDescSyncMode) {
VolumeDescSyncMode["NEVER"] = "NEVER";
VolumeDescSyncMode["ON_EXIT"] = "ON_EXIT";
VolumeDescSyncMode["CONTINUOUS"] = "CONTINUOUS";
VolumeDescSyncMode["PERIODIC"] = "PERIODIC";
VolumeDescSyncMode["ON_MIGRATION"] = "ON_MIGRATION";
})(VolumeDescSyncMode || (exports.VolumeDescSyncMode = VolumeDescSyncMode = {}));
/**
* TaskAssignmentType enum
*/
var TaskAssignmentType;
(function (TaskAssignmentType) {
TaskAssignmentType["NEW_TASK"] = "NEW_TASK";
TaskAssignmentType["TASK_UPDATE"] = "TASK_UPDATE";
TaskAssignmentType["TASK_STOP"] = "TASK_STOP";
})(TaskAssignmentType || (exports.TaskAssignmentType = TaskAssignmentType = {}));
/**
* Constraint type enum matching the Java constraint system
*/
var ConstraintType;
(function (ConstraintType) {
// Resource constraints
ConstraintType["SERVER_RESOURCES"] = "serverResources";
ConstraintType["REQUIRES_MEMORY"] = "requiresMemory";
ConstraintType["REQUIRES_GPU"] = "requiresGpu";
ConstraintType["REQUIRES_CPU_CORES"] = "requiresCpuCores";
ConstraintType["CPU_BENCHMARK"] = "cpuBenchmark";
// Job dependency constraints
ConstraintType["AFTER_JOB"] = "afterJob";
ConstraintType["BEFORE_JOB"] = "beforeJob";
ConstraintType["AT_TIME"] = "atTime";
})(ConstraintType || (exports.ConstraintType = ConstraintType = {}));
/**
* Legacy ConstraintType enum (deprecated - use new ConstraintType instead)
* @deprecated Use ConstraintType instead
*/
var LegacyConstraintType;
(function (LegacyConstraintType) {
LegacyConstraintType["AFTER"] = "after";
LegacyConstraintType["BEFORE"] = "before";
LegacyConstraintType["AT"] = "at";
LegacyConstraintType["REQUIRES"] = "requires";
})(LegacyConstraintType || (exports.LegacyConstraintType = LegacyConstraintType = {}));
/**
* Multicloud REST API client
*/
class MulticloudRestClient {
constructor(params, debug = false) {
this.params = params;
this.debug = debug;
}
/**
* Make an authenticated request to the Multicloud API
*/
async makeRequest(method, path, body) {
const url = `${this.params.serverUrl}${path}`;
// Log request details in non-production environments
// if (process.env.NODE_ENV !== 'production') {
// console.log(`[MulticloudRESTClient] ${method} ${url}`);
// if (body) {
// console.log(`[MulticloudRESTClient] Request body:`, JSON.stringify(body, null, 2));
// }
// }
// Build headers object
const headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
};
// Add Authorization header if accessToken is provided
if (this.params.accessToken) {
headers['Authorization'] = `Bearer ${this.params.accessToken}`;
// if (this.debug) {
// console.log(`[MulticloudRESTClient] Added Authorization header with token length: ${this.params.accessToken.length}`);
// }
}
else if (this.debug) {
console.log('[MulticloudRESTClient] No accessToken provided, skipping Authorization header');
}
const options = {
method,
headers
};
// Add client certificates if provided
if (this.params.clientCert && this.params.clientKey) {
options.cert = fs_1.default.readFileSync(this.params.clientCert);
options.key = fs_1.default.readFileSync(this.params.clientKey);
}
// Log headers in debug mode
// if (this.debug) {
// console.log(`[MulticloudRESTClient] Request headers:`, options.headers);
// }
return new Promise((resolve, reject) => {
const req = https_1.default.request(url, options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
if (this.debug) {
console.log(`[MulticloudRESTClient] ${method} ${path} -> ${res.statusCode}`);
}
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
try {
const result = data ? JSON.parse(data) : null;
resolve(result);
}
catch (error) {
reject(new exceptions_1.MulticloudResponseError(`Failed to parse response: ${error}`));
}
}
else {
reject(new exceptions_1.MulticloudResponseError(`HTTP ${res.statusCode}: ${data}`));
}
});
});
req.on('error', (error) => {
reject(new exceptions_1.MulticloudNetworkError(`Request failed: ${error.message}`));
});
if (body) {
req.write(JSON.stringify(body));
}
req.end();
});
}
/**
* 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;
}
}
/**
* Health check endpoints
*/
async pingCoordinator() {
return this.makeRequest('GET', '/coordinator/ping');
}
async pingAdmin() {
return this.makeRequest('GET', '/admin/ping');
}
async pingApplications() {
return this.makeRequest('GET', '/applications/ping');
}
/**
* Application management endpoints
*/
async getApplications() {
return this.makeRequest('GET', '/applications');
}
async getApplication(applicationId) {
return this.makeRequest('GET', `/applications/${applicationId}`);
}
async createApplication(application) {
return this.makeRequest('POST', '/applications', application);
}
async updateApplication(applicationId, application) {
return this.makeRequest('PUT', `/applications/${applicationId}`, application);
}
async deleteApplication(applicationId) {
return this.makeRequest('DELETE', `/applications/${applicationId}`);
}
async getApplicationJobs(applicationId) {
return this.makeRequest('GET', `/applications/jobs?applicationId=${applicationId}`);
}
async getApplicationClusters(applicationId) {
return this.makeRequest('GET', `/applications/clusters?applicationId=${applicationId}`);
}
/**
* Job management endpoints
*/
async getJobs(clusterId) {
const path = clusterId ? `/coordinator/jobs?clusterId=${clusterId}` : '/coordinator/jobs';
return this.makeRequest('GET', path);
}
async getJob(jobId) {
return this.makeRequest('GET', `/coordinator/job/${jobId}`);
}
async addJobs(jobs, clusterId) {
const path = clusterId ? `/coordinator/jobs?clusterId=${clusterId}` : '/coordinator/jobs';
return this.makeRequest('POST', path, jobs);
}
async addJob(job) {
return this.makeRequest('POST', '/coordinator/job', job);
}
async updateJob(jobId, job) {
return this.makeRequest('PUT', `/coordinator/job/${jobId}`, job);
}
async jobAction(jobId, action, clusterId, scaleBy) {
const params = new URLSearchParams();
params.append('action', action);
if (clusterId)
params.append('clusterId', clusterId.toString());
if (scaleBy !== undefined)
params.append('by', scaleBy.toString());
return this.makeRequest('PUT', `/coordinator/job/${jobId}?${params.toString()}`);
}
async deleteJob(jobId) {
return this.makeRequest('DELETE', `/coordinator/jobs/${jobId}`);
}
async getJobTasks(jobId) {
return this.makeRequest('GET', `/coordinator/jobs/${jobId}/tasks`);
}
async getJobByOwner(owner, jobId) {
const path = jobId ? `/coordinator/jobs/owner/${owner}?jobId=${jobId}` : `/coordinator/jobs/owner/${owner}`;
return this.makeRequest('GET', path);
}
/**
* Cluster management endpoints
*/
async getClusters() {
return this.makeRequest('GET', '/admin/clusters');
}
async getCluster(clusterId) {
return this.makeRequest('GET', `/coordinator/cluster/${clusterId}`);
}
async createCluster(cluster) {
return this.makeRequest('POST', '/coordinator/cluster', cluster);
}
async addOrUpdateClusters(clusters) {
return this.makeRequest('POST', '/coordinator/cluster', clusters);
}
async updateCluster(clusterId, cluster) {
return this.makeRequest('PUT', `/coordinator/clusters/${clusterId}`, cluster);
}
async deleteCluster(clusterId) {
return this.makeRequest('DELETE', `/coordinator/clusters/${clusterId}`);
}
async getClusterJobs(clusterId) {
return this.makeRequest('GET', `/coordinator/jobs?clusterId=${clusterId}`);
}
async getClusterServers(clusterId) {
return this.makeRequest('GET', `/admin/servers?clusterId=${clusterId}`);
}
async getClusterLocations(clusterId) {
return this.makeRequest('GET', `/admin/cluster/${clusterId}/locations`);
}
/**
* Server management endpoints
*/
async getServers(clusterId) {
const path = clusterId ? `/admin/servers?clusterId=${clusterId}` : '/admin/servers';
return this.makeRequest('GET', path);
}
async getServer(clusterId, serverId) {
return this.makeRequest('GET', `/admin/cluster/${clusterId}/server/${serverId}`);
}
async updateServer(serverId, server) {
return this.makeRequest('PUT', `/coordinator/servers/${serverId}`, server);
}
async deleteServer(serverId) {
return this.makeRequest('DELETE', `/coordinator/servers/${serverId}`);
}
// Note: Backend does not support getting tasks by serverId directly
// Use getTasks() with jobId and clusterId parameters instead
async getServerTasks(serverId) {
// This endpoint doesn't exist in the backend - would need to be implemented
throw new Error('getServerTasks not supported by backend - use getTasks() with jobId/clusterId instead');
}
/**
* Server resource offer endpoint (used by agents)
*/
async offerResources(server) {
return this.makeRequest('POST', '/coordinator/offer', server);
}
/**
* Task management endpoints
*/
async getTasks(clusterId, jobId) {
let path = '/coordinator/tasks';
const params = new URLSearchParams();
if (clusterId)
params.append('clusterId', clusterId.toString());
if (jobId)
params.append('jobId', jobId.toString());
if (params.toString())
path += `?${params.toString()}`;
return this.makeRequest('GET', path);
}
async getTask(taskId) {
return this.makeRequest('GET', `/coordinator/tasks/${taskId}`);
}
async updateTask(task) {
return this.makeRequest('POST', '/coordinator/task', task);
}
async deleteTask(taskId) {
return this.makeRequest('DELETE', `/coordinator/tasks/${taskId}`);
}
async getTasksByOwner(owner) {
return this.makeRequest('GET', `/coordinator/tasks/owner/${owner}`);
}
async restartJobTasks(jobId, clusterId) {
const params = new URLSearchParams();
params.append('jobId', jobId.toString());
if (clusterId)
params.append('clusterId', clusterId.toString());
return this.makeRequest('POST', `/coordinator/cli/job/restart?${params.toString()}`);
}
async restartTask(taskIds) {
const params = new URLSearchParams();
taskIds.forEach(id => params.append('taskId', id.toString()));
return this.makeRequest('POST', `/coordinator/cli/task/restart?${params.toString()}`);
}
/**
* IP Lease management endpoints
*/
async getIpLeases(subnetName, serviceName) {
let path = '/coordinator/ip-leases';
const params = new URLSearchParams();
if (subnetName)
params.append('subnetName', subnetName);
if (serviceName)
params.append('serviceName', serviceName);
if (params.toString())
path += `?${params.toString()}`;
return this.makeRequest('GET', path);
}
async getIpLease(subnetName, serviceName) {
return this.makeRequest('GET', `/coordinator/ip-leases/${subnetName}/${serviceName}`);
}
async createIpLease(ipLease) {
return this.makeRequest('POST', '/coordinator/ip-leases', ipLease);
}
async updateIpLease(subnetName, serviceName, ipLease) {
return this.makeRequest('PUT', `/coordinator/ip-leases/${subnetName}/${serviceName}`, ipLease);
}
async deleteIpLease(subnetName, serviceName) {
return this.makeRequest('DELETE', `/coordinator/ip-leases/${subnetName}/${serviceName}`);
}
/**
* Location management endpoints
*/
async getLocations() {
return this.makeRequest('GET', '/coordinator/locations');
}
async getLocation(locationId) {
return this.makeRequest('GET', `/coordinator/locations/${locationId}`);
}
/**
* Cloud provider management endpoints
*/
async getCloudProviders() {
return this.makeRequest('GET', '/coordinator/cloud-providers');
}
async getCloudProvider(providerId) {
return this.makeRequest('GET', `/coordinator/cloud-providers/${providerId}`);
}
/**
* Key pair management endpoints
*/
async getKeyPairs() {
return this.makeRequest('GET', '/coordinator/key-pairs');
}
async getKeyPair(keyPairId) {
return this.makeRequest('GET', `/coordinator/key-pairs/${keyPairId}`);
}
/**
* Service management endpoints
*/
async getServices() {
return this.makeRequest('GET', '/coordinator/services');
}
async getService(serviceId) {
return this.makeRequest('GET', `/coordinator/services/${serviceId}`);
}
/**
* Volume management endpoints
*/
async getVolumes() {
return this.makeRequest('GET', '/coordinator/volumes');
}
async getVolume(volumeId) {
return this.makeRequest('GET', `/coordinator/volumes/${volumeId}`);
}
/**
* Property management endpoints
*/
async getProperties() {
return this.makeRequest('GET', '/coordinator/properties');
}
async getProperty(propertyId) {
return this.makeRequest('GET', `/coordinator/properties/${propertyId}`);
}
/**
* Unit management endpoints
*/
async getUnits() {
return this.makeRequest('GET', '/coordinator/units');
}
async getUnit(unitId) {
return this.makeRequest('GET', `/coordinator/units/${unitId}`);
}
/**
* Route53 management endpoints
*/
async getRoute53Records() {
return this.makeRequest('GET', '/coordinator/route53');
}
async getRoute53Record(recordId) {
return this.makeRequest('GET', `/coordinator/route53/${recordId}`);
}
/**
* Admin endpoints
*/
async getAdminStats() {
return this.makeRequest('GET', '/admin/stats');
}
async getAdminHealth() {
return this.makeRequest('GET', '/admin/health');
}
async getAdminMetrics() {
return this.makeRequest('GET', '/admin/metrics');
}
/**
* Catalog endpoints
*/
async getCatalogServerTypes() {
return this.makeRequest('GET', '/catalog/server-types');
}
async getCatalogServerType(serverTypeId) {
return this.makeRequest('GET', `/catalog/server-types/${serverTypeId}`);
}
async getCatalogProcessors() {
return this.makeRequest('GET', '/catalog/processors');
}
async getCatalogAccelerators() {
return this.makeRequest('GET', '/catalog/accelerators');
}
}
exports.MulticloudRestClient = MulticloudRestClient;
//# sourceMappingURL=client.js.map