feat: add configurable VPS provider API URLs for emulator testing
- Add LINODE_API_URL and VULTR_API_URL environment variables - Update LinodeProvider and VultrProvider to accept optional baseUrl - Update ProvisioningService to pass API URLs to providers - Add source_provider and source_region_code to PricingWithProvider type - Use source_provider (linode/vultr) instead of provider_name (Anvil) - Improve error handling for non-JSON responses in LinodeProvider Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -114,7 +114,9 @@ export async function handleProvision(
|
||||
env.DB, // cloud-instances-db
|
||||
env.USER_DB, // telegram-conversations
|
||||
env.LINODE_API_KEY,
|
||||
env.VULTR_API_KEY
|
||||
env.VULTR_API_KEY,
|
||||
env.LINODE_API_URL,
|
||||
env.VULTR_API_URL
|
||||
);
|
||||
|
||||
// Provision server
|
||||
|
||||
@@ -19,7 +19,9 @@ export async function handleProvisionQueue(
|
||||
env.DB,
|
||||
env.USER_DB,
|
||||
env.LINODE_API_KEY,
|
||||
env.VULTR_API_KEY
|
||||
env.VULTR_API_KEY,
|
||||
env.LINODE_API_URL,
|
||||
env.VULTR_API_URL
|
||||
);
|
||||
|
||||
for (const message of batch.messages) {
|
||||
|
||||
@@ -26,10 +26,12 @@ interface LinodeError {
|
||||
}
|
||||
|
||||
export class LinodeProvider extends VPSProviderBase {
|
||||
constructor(apiKey: string, timeout: number = 30000) {
|
||||
static readonly DEFAULT_BASE_URL = 'https://api.linode.com/v4';
|
||||
|
||||
constructor(apiKey: string, baseUrl?: string, timeout: number = 30000) {
|
||||
super({
|
||||
apiKey,
|
||||
baseUrl: 'https://api.linode.com/v4',
|
||||
baseUrl: baseUrl || LinodeProvider.DEFAULT_BASE_URL,
|
||||
timeout,
|
||||
});
|
||||
}
|
||||
@@ -58,18 +60,32 @@ export class LinodeProvider extends VPSProviderBase {
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
// Read response text first to handle both JSON and HTML errors
|
||||
const responseText = await response.text();
|
||||
|
||||
if (!response.ok) {
|
||||
const error = (await response.json()) as LinodeError;
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: `LINODE_${response.status}`,
|
||||
message: error.errors?.[0]?.reason || 'Unknown error',
|
||||
},
|
||||
};
|
||||
// Try to parse as JSON, but handle HTML responses gracefully
|
||||
try {
|
||||
const error = JSON.parse(responseText) as LinodeError;
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: `LINODE_${response.status}`,
|
||||
message: error.errors?.[0]?.reason || 'Unknown error',
|
||||
},
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: `LINODE_${response.status}`,
|
||||
message: `Non-JSON response: ${responseText.substring(0, 200)}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const data = (await response.json()) as LinodeInstance;
|
||||
const data = JSON.parse(responseText) as LinodeInstance;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
|
||||
@@ -20,12 +20,14 @@ export class ProvisioningService {
|
||||
db: D1Database, // cloud-instances-db: pricing, providers
|
||||
userDb: D1Database, // telegram-conversations: users, deposits, orders
|
||||
linodeApiKey?: string,
|
||||
vultrApiKey?: string
|
||||
vultrApiKey?: string,
|
||||
linodeApiUrl?: string, // Optional: for testing with emulator
|
||||
vultrApiUrl?: string // Optional: for testing with emulator
|
||||
) {
|
||||
this.env = env;
|
||||
this.repo = new ProvisioningRepository(db, userDb);
|
||||
this.linodeProvider = linodeApiKey ? new LinodeProvider(linodeApiKey) : null;
|
||||
this.vultrProvider = vultrApiKey ? new VultrProvider(vultrApiKey) : null;
|
||||
this.linodeProvider = linodeApiKey ? new LinodeProvider(linodeApiKey, linodeApiUrl) : null;
|
||||
this.vultrProvider = vultrApiKey ? new VultrProvider(vultrApiKey, vultrApiUrl) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,10 +36,12 @@ interface VultrError {
|
||||
}
|
||||
|
||||
export class VultrProvider extends VPSProviderBase {
|
||||
constructor(apiKey: string, timeout: number = 30000) {
|
||||
static readonly DEFAULT_BASE_URL = 'https://api.vultr.com/v2';
|
||||
|
||||
constructor(apiKey: string, baseUrl?: string, timeout: number = 30000) {
|
||||
super({
|
||||
apiKey,
|
||||
baseUrl: 'https://api.vultr.com/v2',
|
||||
baseUrl: baseUrl || VultrProvider.DEFAULT_BASE_URL,
|
||||
timeout,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ export interface Env {
|
||||
// VPS Provider API Keys
|
||||
LINODE_API_KEY?: string;
|
||||
VULTR_API_KEY?: string;
|
||||
// VPS Provider API URLs (for testing with emulators)
|
||||
LINODE_API_URL?: string; // Default: https://api.linode.com/v4
|
||||
VULTR_API_URL?: string; // Default: https://api.vultr.com/v2
|
||||
// Provision API security
|
||||
PROVISION_API_KEY?: string; // Required for /api/provision/* endpoints
|
||||
// Queue for async provisioning
|
||||
|
||||
@@ -39,3 +39,9 @@ queue = "provision-queue"
|
||||
max_batch_size = 1
|
||||
max_retries = 3
|
||||
dead_letter_queue = "provision-queue-dlq"
|
||||
|
||||
# VPS Provider API URLs (for testing with emulators)
|
||||
# Comment out or remove for production to use default URLs
|
||||
[vars]
|
||||
LINODE_API_URL = "https://linode.actions.it.com/v4"
|
||||
VULTR_API_URL = "https://vultr.actions.it.com/v2"
|
||||
|
||||
Reference in New Issue
Block a user