feat: Update error handling to use getErrorMessage utility and improve logging across multiple services
This commit is contained in:
@@ -17,7 +17,7 @@
|
|||||||
"@std/encoding": "jsr:@std/encoding@^1.0.10",
|
"@std/encoding": "jsr:@std/encoding@^1.0.10",
|
||||||
"@db/sqlite": "jsr:@db/sqlite@0.12.0",
|
"@db/sqlite": "jsr:@db/sqlite@0.12.0",
|
||||||
"@push.rocks/smartdaemon": "npm:@push.rocks/smartdaemon@^2.1.0",
|
"@push.rocks/smartdaemon": "npm:@push.rocks/smartdaemon@^2.1.0",
|
||||||
"@apiclient.xyz/docker": "npm:@apiclient.xyz/docker@^5.0.2",
|
"@apiclient.xyz/docker": "npm:@apiclient.xyz/docker@^5.1.0",
|
||||||
"@apiclient.xyz/cloudflare": "npm:@apiclient.xyz/cloudflare@6.4.3",
|
"@apiclient.xyz/cloudflare": "npm:@apiclient.xyz/cloudflare@6.4.3",
|
||||||
"@push.rocks/smartacme": "npm:@push.rocks/smartacme@^8.0.0",
|
"@push.rocks/smartacme": "npm:@push.rocks/smartacme@^8.0.0",
|
||||||
"@push.rocks/smartregistry": "npm:@push.rocks/smartregistry@^1.8.0",
|
"@push.rocks/smartregistry": "npm:@push.rocks/smartregistry@^1.8.0",
|
||||||
|
|||||||
5
mod.ts
5
mod.ts
@@ -7,13 +7,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { runCli } from './ts/index.ts';
|
import { runCli } from './ts/index.ts';
|
||||||
|
import { getErrorMessage } from './ts/utils/error.ts';
|
||||||
|
|
||||||
if (import.meta.main) {
|
if (import.meta.main) {
|
||||||
try {
|
try {
|
||||||
await runCli();
|
await runCli();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error: ${error.message}`);
|
console.error(`Error: ${getErrorMessage(error)}`);
|
||||||
if (Deno.args.includes('--debug')) {
|
if (Deno.args.includes('--debug') && error instanceof Error) {
|
||||||
console.error(error.stack);
|
console.error(error.stack);
|
||||||
}
|
}
|
||||||
Deno.exit(1);
|
Deno.exit(1);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import type {
|
|||||||
ISslCertificate,
|
ISslCertificate,
|
||||||
IServiceDeployOptions,
|
IServiceDeployOptions,
|
||||||
} from '../types.ts';
|
} from '../types.ts';
|
||||||
|
import { getErrorMessage } from '../utils/error.ts';
|
||||||
|
|
||||||
export class OneboxApiClient {
|
export class OneboxApiClient {
|
||||||
private baseUrl: string;
|
private baseUrl: string;
|
||||||
@@ -193,7 +194,7 @@ export class OneboxApiClient {
|
|||||||
|
|
||||||
return await response.json();
|
return await response.json();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.name === 'TimeoutError') {
|
if (error instanceof Error && error.name === 'TimeoutError') {
|
||||||
throw new Error('Request timed out. Daemon might be unresponsive.');
|
throw new Error('Request timed out. Daemon might be unresponsive.');
|
||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
@@ -836,7 +836,7 @@ export class OneboxDatabase {
|
|||||||
if (!this.db) throw new Error('Database not initialized');
|
if (!this.db) throw new Error('Database not initialized');
|
||||||
|
|
||||||
const fields: string[] = [];
|
const fields: string[] = [];
|
||||||
const values: unknown[] = [];
|
const values: BindValue[] = [];
|
||||||
|
|
||||||
if (updates.image !== undefined) {
|
if (updates.image !== undefined) {
|
||||||
fields.push('image = ?');
|
fields.push('image = ?');
|
||||||
@@ -1202,7 +1202,7 @@ export class OneboxDatabase {
|
|||||||
if (!this.db) throw new Error('Database not initialized');
|
if (!this.db) throw new Error('Database not initialized');
|
||||||
|
|
||||||
const fields: string[] = [];
|
const fields: string[] = [];
|
||||||
const values: unknown[] = [];
|
const values: BindValue[] = [];
|
||||||
|
|
||||||
if (updates.certPath) {
|
if (updates.certPath) {
|
||||||
fields.push('cert_path = ?');
|
fields.push('cert_path = ?');
|
||||||
@@ -1303,7 +1303,7 @@ export class OneboxDatabase {
|
|||||||
if (!this.db) throw new Error('Database not initialized');
|
if (!this.db) throw new Error('Database not initialized');
|
||||||
|
|
||||||
const fields: string[] = [];
|
const fields: string[] = [];
|
||||||
const values: unknown[] = [];
|
const values: BindValue[] = [];
|
||||||
|
|
||||||
if (updates.domain !== undefined) {
|
if (updates.domain !== undefined) {
|
||||||
fields.push('domain = ?');
|
fields.push('domain = ?');
|
||||||
@@ -1405,7 +1405,7 @@ export class OneboxDatabase {
|
|||||||
if (!this.db) throw new Error('Database not initialized');
|
if (!this.db) throw new Error('Database not initialized');
|
||||||
|
|
||||||
const fields: string[] = [];
|
const fields: string[] = [];
|
||||||
const values: unknown[] = [];
|
const values: BindValue[] = [];
|
||||||
|
|
||||||
if (updates.certDomain !== undefined) {
|
if (updates.certDomain !== undefined) {
|
||||||
fields.push('cert_domain = ?');
|
fields.push('cert_domain = ?');
|
||||||
@@ -1524,7 +1524,7 @@ export class OneboxDatabase {
|
|||||||
if (!this.db) throw new Error('Database not initialized');
|
if (!this.db) throw new Error('Database not initialized');
|
||||||
|
|
||||||
const fields: string[] = [];
|
const fields: string[] = [];
|
||||||
const values: unknown[] = [];
|
const values: BindValue[] = [];
|
||||||
|
|
||||||
if (updates.subdomain !== undefined) {
|
if (updates.subdomain !== undefined) {
|
||||||
fields.push('subdomain = ?');
|
fields.push('subdomain = ?');
|
||||||
@@ -1711,7 +1711,7 @@ export class OneboxDatabase {
|
|||||||
if (!this.db) throw new Error('Database not initialized');
|
if (!this.db) throw new Error('Database not initialized');
|
||||||
|
|
||||||
const fields: string[] = [];
|
const fields: string[] = [];
|
||||||
const values: unknown[] = [];
|
const values: BindValue[] = [];
|
||||||
|
|
||||||
if (updates.status !== undefined) {
|
if (updates.status !== undefined) {
|
||||||
fields.push('status = ?');
|
fields.push('status = ?');
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { logger } from '../logging.ts';
|
|||||||
import { getErrorMessage } from '../utils/error.ts';
|
import { getErrorMessage } from '../utils/error.ts';
|
||||||
|
|
||||||
export class OneboxDockerManager {
|
export class OneboxDockerManager {
|
||||||
private dockerClient: plugins.docker.Docker | null = null;
|
private dockerClient: InstanceType<typeof plugins.docker.Docker> | null = null;
|
||||||
private networkName = 'onebox-network';
|
private networkName = 'onebox-network';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -695,14 +695,6 @@ export class OneboxDockerManager {
|
|||||||
timestamps: true,
|
timestamps: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// v5 should return a string, but let's handle edge cases
|
|
||||||
if (typeof logs !== 'string') {
|
|
||||||
logger.error(`Unexpected logs type: ${typeof logs}, constructor: ${logs?.constructor?.name}`);
|
|
||||||
logger.error(`Logs content: ${JSON.stringify(logs).slice(0, 500)}`);
|
|
||||||
// If it's not a string, something went wrong
|
|
||||||
throw new Error(`Unexpected log format: expected string, got ${typeof logs}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// v5 returns already-parsed logs as a string
|
// v5 returns already-parsed logs as a string
|
||||||
return {
|
return {
|
||||||
stdout: logs,
|
stdout: logs,
|
||||||
@@ -809,20 +801,17 @@ export class OneboxDockerManager {
|
|||||||
throw new Error(`Container not found: ${containerID}`);
|
throw new Error(`Container not found: ${containerID}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const exec = await container.exec({
|
const { stream, inspect } = await container.exec(cmd, {
|
||||||
Cmd: cmd,
|
attachStdout: true,
|
||||||
AttachStdout: true,
|
attachStderr: true,
|
||||||
AttachStderr: true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const stream = await exec.start({ Detach: false });
|
|
||||||
|
|
||||||
let stdout = '';
|
let stdout = '';
|
||||||
let stderr = '';
|
let stderr = '';
|
||||||
|
|
||||||
stream.on('data', (chunk: Buffer) => {
|
stream.on('data', (chunk: Uint8Array) => {
|
||||||
const streamType = chunk[0];
|
const streamType = chunk[0];
|
||||||
const content = chunk.slice(8).toString();
|
const content = new TextDecoder().decode(chunk.slice(8));
|
||||||
|
|
||||||
if (streamType === 1) {
|
if (streamType === 1) {
|
||||||
stdout += content;
|
stdout += content;
|
||||||
@@ -834,8 +823,8 @@ export class OneboxDockerManager {
|
|||||||
// Wait for completion
|
// Wait for completion
|
||||||
await new Promise((resolve) => stream.on('end', resolve));
|
await new Promise((resolve) => stream.on('end', resolve));
|
||||||
|
|
||||||
const inspect = await exec.inspect();
|
const execInfo = await inspect();
|
||||||
const exitCode = inspect.ExitCode || 0;
|
const exitCode = execInfo.ExitCode || 0;
|
||||||
|
|
||||||
return { stdout, stderr, exitCode };
|
return { stdout, stderr, exitCode };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -928,4 +917,26 @@ export class OneboxDockerManager {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a container by ID
|
||||||
|
* Public wrapper for Docker client method
|
||||||
|
*/
|
||||||
|
async getContainerById(containerID: string): Promise<any> {
|
||||||
|
if (!this.dockerClient) {
|
||||||
|
throw new Error('Docker client not initialized');
|
||||||
|
}
|
||||||
|
return this.dockerClient.getContainerById(containerID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all containers
|
||||||
|
* Public wrapper for Docker client method
|
||||||
|
*/
|
||||||
|
async listAllContainers(): Promise<any[]> {
|
||||||
|
if (!this.dockerClient) {
|
||||||
|
throw new Error('Docker client not initialized');
|
||||||
|
}
|
||||||
|
return this.dockerClient.listContainers();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export class CredentialEncryption {
|
|||||||
}
|
}
|
||||||
this.key = await crypto.subtle.importKey(
|
this.key = await crypto.subtle.importKey(
|
||||||
'raw',
|
'raw',
|
||||||
keyBytes,
|
keyBytes.buffer as ArrayBuffer,
|
||||||
{ name: this.algorithm },
|
{ name: this.algorithm },
|
||||||
false,
|
false,
|
||||||
['encrypt', 'decrypt']
|
['encrypt', 'decrypt']
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import * as plugins from '../plugins.ts';
|
|||||||
import { logger } from '../logging.ts';
|
import { logger } from '../logging.ts';
|
||||||
import { getErrorMessage } from '../utils/error.ts';
|
import { getErrorMessage } from '../utils/error.ts';
|
||||||
import type { Onebox } from './onebox.ts';
|
import type { Onebox } from './onebox.ts';
|
||||||
import type { IApiResponse, ICreateRegistryTokenRequest, IRegistryTokenView } from '../types.ts';
|
import type { IApiResponse, ICreateRegistryTokenRequest, IRegistryTokenView, TPlatformServiceType } from '../types.ts';
|
||||||
|
|
||||||
export class OneboxHttpServer {
|
export class OneboxHttpServer {
|
||||||
private oneboxRef: Onebox;
|
private oneboxRef: Onebox;
|
||||||
@@ -482,8 +482,8 @@ export class OneboxHttpServer {
|
|||||||
private async handleGetLogsRequest(name: string): Promise<Response> {
|
private async handleGetLogsRequest(name: string): Promise<Response> {
|
||||||
try {
|
try {
|
||||||
const logs = await this.oneboxRef.services.getServiceLogs(name);
|
const logs = await this.oneboxRef.services.getServiceLogs(name);
|
||||||
logger.log(`handleGetLogsRequest: logs type = ${typeof logs}, constructor = ${logs?.constructor?.name}`);
|
logger.debug(`handleGetLogsRequest: logs type = ${typeof logs}, constructor = ${logs?.constructor?.name}`);
|
||||||
logger.log(`handleGetLogsRequest: logs value = ${String(logs).slice(0, 100)}`);
|
logger.debug(`handleGetLogsRequest: logs value = ${String(logs).slice(0, 100)}`);
|
||||||
return this.jsonResponse({ success: true, data: logs });
|
return this.jsonResponse({ success: true, data: logs });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to get logs for service ${name}: ${getErrorMessage(error)}`);
|
logger.error(`Failed to get logs for service ${name}: ${getErrorMessage(error)}`);
|
||||||
@@ -878,13 +878,13 @@ export class OneboxHttpServer {
|
|||||||
|
|
||||||
// Get the container (handle both direct container IDs and service IDs)
|
// Get the container (handle both direct container IDs and service IDs)
|
||||||
logger.info(`Looking up container for service ${serviceName}, containerID: ${service.containerID}`);
|
logger.info(`Looking up container for service ${serviceName}, containerID: ${service.containerID}`);
|
||||||
let container = await this.oneboxRef.docker.dockerClient!.getContainerById(service.containerID!);
|
let container = await this.oneboxRef.docker.getContainerById(service.containerID!);
|
||||||
logger.info(`Direct lookup result: ${container ? 'found' : 'null'}`);
|
logger.info(`Direct lookup result: ${container ? 'found' : 'null'}`);
|
||||||
|
|
||||||
// If not found, it might be a service ID - try to get the actual container ID
|
// If not found, it might be a service ID - try to get the actual container ID
|
||||||
if (!container) {
|
if (!container) {
|
||||||
logger.info('Listing all containers to find matching service...');
|
logger.info('Listing all containers to find matching service...');
|
||||||
const containers = await this.oneboxRef.docker.dockerClient!.listContainers();
|
const containers = await this.oneboxRef.docker.listAllContainers();
|
||||||
logger.info(`Found ${containers.length} containers`);
|
logger.info(`Found ${containers.length} containers`);
|
||||||
|
|
||||||
const serviceContainer = containers.find((c: any) => {
|
const serviceContainer = containers.find((c: any) => {
|
||||||
@@ -894,7 +894,7 @@ export class OneboxHttpServer {
|
|||||||
|
|
||||||
if (serviceContainer) {
|
if (serviceContainer) {
|
||||||
logger.info(`Found matching container: ${serviceContainer.Id}`);
|
logger.info(`Found matching container: ${serviceContainer.Id}`);
|
||||||
container = await this.oneboxRef.docker.dockerClient!.getContainerById(serviceContainer.Id);
|
container = await this.oneboxRef.docker.getContainerById(serviceContainer.Id);
|
||||||
logger.info(`Second lookup result: ${container ? 'found' : 'null'}`);
|
logger.info(`Second lookup result: ${container ? 'found' : 'null'}`);
|
||||||
} else {
|
} else {
|
||||||
logger.error(`No container found with service label matching ${service.containerID}`);
|
logger.error(`No container found with service label matching ${service.containerID}`);
|
||||||
@@ -924,18 +924,21 @@ export class OneboxHttpServer {
|
|||||||
|
|
||||||
// Demultiplex and pipe log data to WebSocket
|
// Demultiplex and pipe log data to WebSocket
|
||||||
// Docker streams use 8-byte headers: [STREAM_TYPE, 0, 0, 0, SIZE_BYTE1, SIZE_BYTE2, SIZE_BYTE3, SIZE_BYTE4]
|
// Docker streams use 8-byte headers: [STREAM_TYPE, 0, 0, 0, SIZE_BYTE1, SIZE_BYTE2, SIZE_BYTE3, SIZE_BYTE4]
|
||||||
let buffer = Buffer.alloc(0);
|
let buffer = new Uint8Array(0);
|
||||||
|
|
||||||
logStream.on('data', (chunk: Buffer) => {
|
logStream.on('data', (chunk: Uint8Array) => {
|
||||||
if (socket.readyState !== WebSocket.OPEN) return;
|
if (socket.readyState !== WebSocket.OPEN) return;
|
||||||
|
|
||||||
// Append new data to buffer
|
// Append new data to buffer
|
||||||
buffer = Buffer.concat([buffer, chunk]);
|
const newBuffer = new Uint8Array(buffer.length + chunk.length);
|
||||||
|
newBuffer.set(buffer);
|
||||||
|
newBuffer.set(chunk, buffer.length);
|
||||||
|
buffer = newBuffer;
|
||||||
|
|
||||||
// Process complete frames
|
// Process complete frames
|
||||||
while (buffer.length >= 8) {
|
while (buffer.length >= 8) {
|
||||||
// Read frame size from header (bytes 4-7, big-endian)
|
// Read frame size from header (bytes 4-7, big-endian)
|
||||||
const frameSize = buffer.readUInt32BE(4);
|
const frameSize = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
|
||||||
|
|
||||||
// Check if we have the complete frame
|
// Check if we have the complete frame
|
||||||
if (buffer.length < 8 + frameSize) {
|
if (buffer.length < 8 + frameSize) {
|
||||||
@@ -946,7 +949,7 @@ export class OneboxHttpServer {
|
|||||||
const frameData = buffer.slice(8, 8 + frameSize);
|
const frameData = buffer.slice(8, 8 + frameSize);
|
||||||
|
|
||||||
// Send the clean log line
|
// Send the clean log line
|
||||||
socket.send(frameData.toString('utf8'));
|
socket.send(new TextDecoder().decode(frameData));
|
||||||
|
|
||||||
// Remove processed frame from buffer
|
// Remove processed frame from buffer
|
||||||
buffer = buffer.slice(8 + frameSize);
|
buffer = buffer.slice(8 + frameSize);
|
||||||
@@ -1083,7 +1086,7 @@ export class OneboxHttpServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleGetPlatformServiceRequest(type: string): Promise<Response> {
|
private async handleGetPlatformServiceRequest(type: TPlatformServiceType): Promise<Response> {
|
||||||
try {
|
try {
|
||||||
const provider = this.oneboxRef.platformServices.getProvider(type);
|
const provider = this.oneboxRef.platformServices.getProvider(type);
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
@@ -1123,7 +1126,7 @@ export class OneboxHttpServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleStartPlatformServiceRequest(type: string): Promise<Response> {
|
private async handleStartPlatformServiceRequest(type: TPlatformServiceType): Promise<Response> {
|
||||||
try {
|
try {
|
||||||
const provider = this.oneboxRef.platformServices.getProvider(type);
|
const provider = this.oneboxRef.platformServices.getProvider(type);
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
@@ -1154,7 +1157,7 @@ export class OneboxHttpServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleStopPlatformServiceRequest(type: string): Promise<Response> {
|
private async handleStopPlatformServiceRequest(type: TPlatformServiceType): Promise<Response> {
|
||||||
try {
|
try {
|
||||||
const provider = this.oneboxRef.platformServices.getProvider(type);
|
const provider = this.oneboxRef.platformServices.getProvider(type);
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import type { IPlatformServiceProvider } from './providers/base.ts';
|
|||||||
import { MongoDBProvider } from './providers/mongodb.ts';
|
import { MongoDBProvider } from './providers/mongodb.ts';
|
||||||
import { MinioProvider } from './providers/minio.ts';
|
import { MinioProvider } from './providers/minio.ts';
|
||||||
import { logger } from '../../logging.ts';
|
import { logger } from '../../logging.ts';
|
||||||
|
import { getErrorMessage } from '../../utils/error.ts';
|
||||||
import { credentialEncryption } from '../encryption.ts';
|
import { credentialEncryption } from '../encryption.ts';
|
||||||
import type { Onebox } from '../onebox.ts';
|
import type { Onebox } from '../onebox.ts';
|
||||||
|
|
||||||
@@ -126,7 +127,7 @@ export class PlatformServicesManager {
|
|||||||
// Refresh platform service from database
|
// Refresh platform service from database
|
||||||
platformService = this.oneboxRef.database.getPlatformServiceByType(type)!;
|
platformService = this.oneboxRef.database.getPlatformServiceByType(type)!;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to start ${provider.displayName}: ${error.message}`);
|
logger.error(`Failed to start ${provider.displayName}: ${getErrorMessage(error)}`);
|
||||||
this.oneboxRef.database.updatePlatformService(platformService.id!, { status: 'failed' });
|
this.oneboxRef.database.updatePlatformService(platformService.id!, { status: 'failed' });
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@@ -187,7 +188,7 @@ export class PlatformServicesManager {
|
|||||||
});
|
});
|
||||||
logger.success(`${provider.displayName} platform service stopped`);
|
logger.success(`${provider.displayName} platform service stopped`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to stop ${provider.displayName}: ${error.message}`);
|
logger.error(`Failed to stop ${provider.displayName}: ${getErrorMessage(error)}`);
|
||||||
this.oneboxRef.database.updatePlatformService(platformService.id!, { status: 'failed' });
|
this.oneboxRef.database.updatePlatformService(platformService.id!, { status: 'failed' });
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@@ -292,7 +293,7 @@ export class PlatformServicesManager {
|
|||||||
this.oneboxRef.database.deletePlatformResource(resource.id!);
|
this.oneboxRef.database.deletePlatformResource(resource.id!);
|
||||||
logger.success(`Cleaned up ${resource.resourceType} '${resource.resourceName}'`);
|
logger.success(`Cleaned up ${resource.resourceType} '${resource.resourceName}'`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to cleanup resource ${resource.id}: ${error.message}`);
|
logger.error(`Failed to cleanup resource ${resource.id}: ${getErrorMessage(error)}`);
|
||||||
// Continue with other resources even if one fails
|
// Continue with other resources even if one fails
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import type {
|
|||||||
TPlatformResourceType,
|
TPlatformResourceType,
|
||||||
} from '../../../types.ts';
|
} from '../../../types.ts';
|
||||||
import { logger } from '../../../logging.ts';
|
import { logger } from '../../../logging.ts';
|
||||||
|
import { getErrorMessage } from '../../../utils/error.ts';
|
||||||
import { credentialEncryption } from '../../encryption.ts';
|
import { credentialEncryption } from '../../encryption.ts';
|
||||||
import type { Onebox } from '../../onebox.ts';
|
import type { Onebox } from '../../onebox.ts';
|
||||||
|
|
||||||
@@ -73,7 +74,7 @@ export class MinioProvider extends BasePlatformServiceProvider {
|
|||||||
await Deno.mkdir('/var/lib/onebox/minio', { recursive: true });
|
await Deno.mkdir('/var/lib/onebox/minio', { recursive: true });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!(e instanceof Deno.errors.AlreadyExists)) {
|
if (!(e instanceof Deno.errors.AlreadyExists)) {
|
||||||
logger.warn(`Could not create MinIO data directory: ${e.message}`);
|
logger.warn(`Could not create MinIO data directory: ${getErrorMessage(e)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +128,7 @@ export class MinioProvider extends BasePlatformServiceProvider {
|
|||||||
|
|
||||||
return response.ok;
|
return response.ok;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.debug(`MinIO health check failed: ${error.message}`);
|
logger.debug(`MinIO health check failed: ${getErrorMessage(error)}`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,7 +206,7 @@ export class MinioProvider extends BasePlatformServiceProvider {
|
|||||||
}));
|
}));
|
||||||
logger.info(`Set bucket policy for '${bucketName}'`);
|
logger.info(`Set bucket policy for '${bucketName}'`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.warn(`Could not set bucket policy: ${e.message}`);
|
logger.warn(`Could not set bucket policy: ${getErrorMessage(e)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: For proper per-service credentials, MinIO Admin API should be used
|
// Note: For proper per-service credentials, MinIO Admin API should be used
|
||||||
@@ -292,7 +293,7 @@ export class MinioProvider extends BasePlatformServiceProvider {
|
|||||||
|
|
||||||
logger.success(`MinIO bucket '${resource.resourceName}' deleted`);
|
logger.success(`MinIO bucket '${resource.resourceName}' deleted`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(`Failed to delete MinIO bucket: ${e.message}`);
|
logger.error(`Failed to delete MinIO bucket: ${getErrorMessage(e)}`);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import type {
|
|||||||
TPlatformResourceType,
|
TPlatformResourceType,
|
||||||
} from '../../../types.ts';
|
} from '../../../types.ts';
|
||||||
import { logger } from '../../../logging.ts';
|
import { logger } from '../../../logging.ts';
|
||||||
|
import { getErrorMessage } from '../../../utils/error.ts';
|
||||||
import { credentialEncryption } from '../../encryption.ts';
|
import { credentialEncryption } from '../../encryption.ts';
|
||||||
import type { Onebox } from '../../onebox.ts';
|
import type { Onebox } from '../../onebox.ts';
|
||||||
|
|
||||||
@@ -69,7 +70,7 @@ export class MongoDBProvider extends BasePlatformServiceProvider {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Directory might already exist
|
// Directory might already exist
|
||||||
if (!(e instanceof Deno.errors.AlreadyExists)) {
|
if (!(e instanceof Deno.errors.AlreadyExists)) {
|
||||||
logger.warn(`Could not create MongoDB data directory: ${e.message}`);
|
logger.warn(`Could not create MongoDB data directory: ${getErrorMessage(e)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +136,7 @@ export class MongoDBProvider extends BasePlatformServiceProvider {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.debug(`MongoDB health check failed: ${error.message}`);
|
logger.debug(`MongoDB health check failed: ${getErrorMessage(error)}`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,7 +234,7 @@ export class MongoDBProvider extends BasePlatformServiceProvider {
|
|||||||
await db.command({ dropUser: credentials.username });
|
await db.command({ dropUser: credentials.username });
|
||||||
logger.info(`Dropped MongoDB user '${credentials.username}'`);
|
logger.info(`Dropped MongoDB user '${credentials.username}'`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.warn(`Could not drop MongoDB user: ${e.message}`);
|
logger.warn(`Could not drop MongoDB user: ${getErrorMessage(e)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drop the database
|
// Drop the database
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import * as plugins from '../plugins.ts';
|
import * as plugins from '../plugins.ts';
|
||||||
import { logger } from '../logging.ts';
|
import { logger } from '../logging.ts';
|
||||||
|
import { getErrorMessage } from '../utils/error.ts';
|
||||||
|
|
||||||
export class RegistryManager {
|
export class RegistryManager {
|
||||||
private s3Server: any = null;
|
private s3Server: any = null;
|
||||||
@@ -86,7 +87,7 @@ export class RegistryManager {
|
|||||||
this.isInitialized = true;
|
this.isInitialized = true;
|
||||||
logger.success('Onebox Registry initialized successfully');
|
logger.success('Onebox Registry initialized successfully');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to initialize registry: ${error.message}`);
|
logger.error(`Failed to initialize registry: ${getErrorMessage(error)}`);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,7 +103,7 @@ export class RegistryManager {
|
|||||||
try {
|
try {
|
||||||
return await this.registry.handleRequest(req);
|
return await this.registry.handleRequest(req);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Registry request error: ${error.message}`);
|
logger.error(`Registry request error: ${getErrorMessage(error)}`);
|
||||||
return new Response('Internal registry error', { status: 500 });
|
return new Response('Internal registry error', { status: 500 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -119,7 +120,7 @@ export class RegistryManager {
|
|||||||
const tags = await this.registry.getTags(repository);
|
const tags = await this.registry.getTags(repository);
|
||||||
return tags || [];
|
return tags || [];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.warn(`Failed to get tags for ${repository}: ${error.message}`);
|
logger.warn(`Failed to get tags for ${repository}: ${getErrorMessage(error)}`);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,8 +147,9 @@ export class RegistryManager {
|
|||||||
return null;
|
return null;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Only log if it's not a "not a function" error
|
// Only log if it's not a "not a function" error
|
||||||
if (!error.message.includes('not a function')) {
|
const errMsg = getErrorMessage(error);
|
||||||
logger.warn(`Failed to get digest for ${repository}:${tag}: ${error.message}`);
|
if (!errMsg.includes('not a function')) {
|
||||||
|
logger.warn(`Failed to get digest for ${repository}:${tag}: ${errMsg}`);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -165,7 +167,7 @@ export class RegistryManager {
|
|||||||
await this.registry.deleteManifest(repository, tag);
|
await this.registry.deleteManifest(repository, tag);
|
||||||
logger.info(`Deleted image ${repository}:${tag}`);
|
logger.info(`Deleted image ${repository}:${tag}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to delete image ${repository}:${tag}: ${error.message}`);
|
logger.error(`Failed to delete image ${repository}:${tag}: ${getErrorMessage(error)}`);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,7 +214,7 @@ export class RegistryManager {
|
|||||||
await this.s3Server.stop();
|
await this.s3Server.stop();
|
||||||
logger.info('smarts3 server stopped');
|
logger.info('smarts3 server stopped');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Error stopping smarts3: ${error.message}`);
|
logger.error(`Error stopping smarts3: ${getErrorMessage(error)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { logger } from '../logging.ts';
|
import { logger } from '../logging.ts';
|
||||||
|
import { getErrorMessage } from '../utils/error.ts';
|
||||||
import { OneboxDatabase } from './database.ts';
|
import { OneboxDatabase } from './database.ts';
|
||||||
|
|
||||||
interface IProxyRoute {
|
interface IProxyRoute {
|
||||||
@@ -43,7 +44,7 @@ export class OneboxReverseProxy {
|
|||||||
try {
|
try {
|
||||||
logger.info('Reverse proxy initialized');
|
logger.info('Reverse proxy initialized');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to initialize reverse proxy: ${error.message}`);
|
logger.error(`Failed to initialize reverse proxy: ${getErrorMessage(error)}`);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,7 +78,7 @@ export class OneboxReverseProxy {
|
|||||||
|
|
||||||
logger.success(`HTTP reverse proxy started on port ${this.httpPort}`);
|
logger.success(`HTTP reverse proxy started on port ${this.httpPort}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to start HTTP reverse proxy: ${error.message}`);
|
logger.error(`Failed to start HTTP reverse proxy: ${getErrorMessage(error)}`);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,7 +123,7 @@ export class OneboxReverseProxy {
|
|||||||
|
|
||||||
logger.success(`HTTPS reverse proxy started on port ${this.httpsPort}`);
|
logger.success(`HTTPS reverse proxy started on port ${this.httpsPort}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to start HTTPS reverse proxy: ${error.message}`);
|
logger.error(`Failed to start HTTPS reverse proxy: ${getErrorMessage(error)}`);
|
||||||
// Don't throw - HTTPS is optional
|
// Don't throw - HTTPS is optional
|
||||||
logger.warn('Continuing without HTTPS support');
|
logger.warn('Continuing without HTTPS support');
|
||||||
}
|
}
|
||||||
@@ -197,7 +198,7 @@ export class OneboxReverseProxy {
|
|||||||
headers: this.filterResponseHeaders(response.headers),
|
headers: this.filterResponseHeaders(response.headers),
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Proxy error for ${host}: ${error.message}`);
|
logger.error(`Proxy error for ${host}: ${getErrorMessage(error)}`);
|
||||||
return new Response('Bad Gateway', {
|
return new Response('Bad Gateway', {
|
||||||
status: 502,
|
status: 502,
|
||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
@@ -264,7 +265,7 @@ export class OneboxReverseProxy {
|
|||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`WebSocket upgrade error: ${error.message}`);
|
logger.error(`WebSocket upgrade error: ${getErrorMessage(error)}`);
|
||||||
return new Response('WebSocket Upgrade Failed', {
|
return new Response('WebSocket Upgrade Failed', {
|
||||||
status: 500,
|
status: 500,
|
||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
@@ -353,7 +354,7 @@ export class OneboxReverseProxy {
|
|||||||
this.routes.set(domain, route);
|
this.routes.set(domain, route);
|
||||||
logger.success(`Added proxy route: ${domain} -> ${targetHost}:${targetPort}`);
|
logger.success(`Added proxy route: ${domain} -> ${targetHost}:${targetPort}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to add route for ${domain}: ${error.message}`);
|
logger.error(`Failed to add route for ${domain}: ${getErrorMessage(error)}`);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,7 +396,7 @@ export class OneboxReverseProxy {
|
|||||||
|
|
||||||
logger.success(`Loaded ${this.routes.size} proxy routes`);
|
logger.success(`Loaded ${this.routes.size} proxy routes`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to reload routes: ${error.message}`);
|
logger.error(`Failed to reload routes: ${getErrorMessage(error)}`);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -423,7 +424,7 @@ export class OneboxReverseProxy {
|
|||||||
logger.warn('HTTPS server restart required for new certificate to take effect');
|
logger.warn('HTTPS server restart required for new certificate to take effect');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to add certificate for ${domain}: ${error.message}`);
|
logger.error(`Failed to add certificate for ${domain}: ${getErrorMessage(error)}`);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -455,7 +456,7 @@ export class OneboxReverseProxy {
|
|||||||
try {
|
try {
|
||||||
await this.addCertificate(cert.domain, cert.fullChainPath, cert.keyPath);
|
await this.addCertificate(cert.domain, cert.fullChainPath, cert.keyPath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.warn(`Failed to load certificate for ${cert.domain}: ${error.message}`);
|
logger.warn(`Failed to load certificate for ${cert.domain}: ${getErrorMessage(error)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -470,7 +471,7 @@ export class OneboxReverseProxy {
|
|||||||
await this.startHttps();
|
await this.startHttps();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to reload certificates: ${error.message}`);
|
logger.error(`Failed to reload certificates: ${getErrorMessage(error)}`);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -382,9 +382,9 @@ export class OneboxServicesManager {
|
|||||||
const logs = await this.docker.getContainerLogs(service.containerID, tail);
|
const logs = await this.docker.getContainerLogs(service.containerID, tail);
|
||||||
|
|
||||||
// Debug: check what we got
|
// Debug: check what we got
|
||||||
logger.log(`getServiceLogs: logs type = ${typeof logs}, constructor = ${logs?.constructor?.name}`);
|
logger.debug(`getServiceLogs: logs type = ${typeof logs}, constructor = ${logs?.constructor?.name}`);
|
||||||
logger.log(`getServiceLogs: logs.stdout type = ${typeof logs.stdout}`);
|
logger.debug(`getServiceLogs: logs.stdout type = ${typeof logs.stdout}`);
|
||||||
logger.log(`getServiceLogs: logs.stdout value = ${String(logs.stdout).slice(0, 100)}`);
|
logger.debug(`getServiceLogs: logs.stdout value = ${String(logs.stdout).slice(0, 100)}`);
|
||||||
|
|
||||||
// v5 API returns combined stdout/stderr with proper formatting
|
// v5 API returns combined stdout/stderr with proper formatting
|
||||||
return logs.stdout;
|
return logs.stdout;
|
||||||
@@ -746,7 +746,7 @@ export class OneboxServicesManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to check updates for ${service.name}: ${error.message}`);
|
logger.error(`Failed to check updates for ${service.name}: ${getErrorMessage(error)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user