Class: Kamal::Providers::Upcloud
- Defined in:
- lib/kamal/providers/upcloud.rb
Overview
UpCloud API v1.3 provider implementation
Implements VM provisioning, status querying, and cleanup via UpCloud's REST API. Uses Faraday with retry middleware for robust HTTP communication.
Constant Summary collapse
- API_BASE_URL =
"https://api.upcloud.com"- API_VERSION =
"1.3"- POLLING_INTERVAL =
seconds
5- POLLING_TIMEOUT =
seconds
120- DEFAULT_UBUNTU_TEMPLATE =
UpCloud storage template for Ubuntu 24.04 LTS (latest LTS) Using template UUID (universal across all UpCloud zones) Template type: cloud-init See: https://developers.upcloud.com/1.3/7-templates/
Available Ubuntu templates:
- Ubuntu 24.04 LTS (Noble Numbat) - UUID: 01000000-0000-4000-8000-000030240200 - Ubuntu 22.04 LTS (Jammy Jellyfish) - UUID: 01000000-0000-4000-8000-000030220200Note: UUIDs verified from UpCloud API (2025-11-18)
"01000000-0000-4000-8000-000030240200"
Instance Method Summary collapse
-
#destroy_vm(vm_id) ⇒ Boolean
Destroy VM and cleanup all associated resources.
-
#estimate_cost(config) ⇒ Hash
Estimate monthly cost for VM configuration.
-
#initialize(username:, password:) ⇒ Upcloud
constructor
Initialize UpCloud provider with credentials.
-
#provision_vm(config) ⇒ Hash
Provision a new VM on UpCloud.
-
#query_status(vm_id) ⇒ Symbol
Query VM status.
Constructor Details
#initialize(username:, password:) ⇒ Upcloud
Initialize UpCloud provider with credentials
51 52 53 |
# File 'lib/kamal/providers/upcloud.rb', line 51 def initialize(username:, password:) @conn = build_connection(username, password) end |
Instance Method Details
#destroy_vm(vm_id) ⇒ Boolean
Destroy VM and cleanup all associated resources
126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/kamal/providers/upcloud.rb', line 126 def destroy_vm(vm_id) @conn.delete("/#{API_VERSION}/server/#{vm_id}") do |req| req.params["storages"] = "1" # Delete attached storages end true rescue Faraday::ResourceNotFound # Already deleted - idempotent true rescue Faraday:: raise AuthenticationError, "Invalid UpCloud credentials" end |
#estimate_cost(config) ⇒ Hash
Estimate monthly cost for VM configuration
Provides generic cost guidance and pricing page link. Real-time pricing queries not implemented in Phase 1.
153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/kamal/providers/upcloud.rb', line 153 def estimate_cost(config) plan = config["plan"] || config[:plan] zone = config["zone"] || config[:zone] { warning: "Deploying VMs with plan #{plan} in zone #{zone}. " \ "Check pricing for accurate costs.", plan: plan, zone: zone, pricing_url: "https://upcloud.com/pricing" } end |
#provision_vm(config) ⇒ Hash
Provision a new VM on UpCloud
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/kamal/providers/upcloud.rb', line 72 def provision_vm(config) response = @conn.post("/#{API_VERSION}/server") do |req| req.headers["Content-Type"] = "application/json" req.body = build_server_spec(config).to_json end server_data = parse_response(response) vm_id = server_data["uuid"] vm_ip = extract_ip_address(server_data) # If already started, return immediately return {id: vm_id, ip: vm_ip, status: :running} if server_data["state"] == "started" # Otherwise poll until running poll_until_running(vm_id) {id: vm_id, ip: vm_ip, status: :running} rescue Faraday:: raise AuthenticationError, "Invalid UpCloud credentials" rescue Faraday::ForbiddenError => e handle_forbidden_error(e) rescue Faraday::ClientError => e raise ProvisioningError, "UpCloud API error: #{e.response[:body]}" rescue Faraday::ServerError raise ProvisioningError, "UpCloud service unavailable" end |
#query_status(vm_id) ⇒ Symbol
Query VM status
110 111 112 113 114 115 116 117 |
# File 'lib/kamal/providers/upcloud.rb', line 110 def query_status(vm_id) response = @conn.get("/#{API_VERSION}/server/#{vm_id}") server_data = response.body["server"] map_state_to_status(server_data["state"]) rescue Faraday:: raise AuthenticationError, "Invalid UpCloud credentials" end |