Class: Kitchen::Driver::Proxmox::ApiClient
- Inherits:
-
Object
- Object
- Kitchen::Driver::Proxmox::ApiClient
- Defined in:
- lib/kitchen/driver/proxmox/api_client.rb
Overview
HTTP client for the Proxmox VE REST API. Authenticates via API tokens. Provides convenience methods for VM lifecycle operations.
Supports multiple API URLs for failover. On connection errors the client tries the next URL. Once a URL works it becomes the sticky preference for subsequent calls.
Constant Summary collapse
- CONNECTION_ERRORS =
[ Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EHOSTUNREACH, Net::OpenTimeout, Net::ReadTimeout, SocketError, OpenSSL::SSL::SSLError ].freeze
Instance Attribute Summary collapse
-
#base_urls ⇒ Object
readonly
Returns the value of attribute base_urls.
-
#connect_timeout ⇒ Object
readonly
Returns the value of attribute connect_timeout.
-
#ssl_verify ⇒ Object
readonly
Returns the value of attribute ssl_verify.
-
#token_id ⇒ Object
readonly
Returns the value of attribute token_id.
-
#token_secret ⇒ Object
readonly
Returns the value of attribute token_secret.
Instance Method Summary collapse
- #agent_network_interfaces(node:, vm_id:) ⇒ Object
-
#base_url ⇒ Object
Backward-compat reader: returns the first (or preferred) URL.
- #clone_vm(node:, template_id:, new_id:, **options) ⇒ Object
- #configure_vm(node:, vm_id:, cpus: nil, memory: nil, network_bridge: nil) ⇒ Object
- #destroy_vm(node:, vm_id:, purge: true) ⇒ Object
-
#initialize(token_id:, token_secret:, base_url: nil, base_urls: nil, ssl_verify: true, connect_timeout: 10) ⇒ ApiClient
constructor
Accepts either base_url (String) or base_urls (Array).
- #list_nodes ⇒ Object
- #list_storage(node:) ⇒ Object
- #list_templates ⇒ Object
- #next_vm_id ⇒ Object
- #start_vm(node:, vm_id:) ⇒ Object
- #stop_vm(node:, vm_id:) ⇒ Object
- #task_status(node:, upid:) ⇒ Object
- #validate_vmid(vm_id) ⇒ Object
- #vm_config(node:, vm_id:) ⇒ Object
- #vm_status(node:, vm_id:) ⇒ Object
- #wait_for_task(node:, upid:, timeout: 300, interval: 2) ⇒ Object
Constructor Details
#initialize(token_id:, token_secret:, base_url: nil, base_urls: nil, ssl_verify: true, connect_timeout: 10) ⇒ ApiClient
Accepts either base_url (String) or base_urls (Array). The String form is normalized to a one-element array.
36 37 38 39 40 41 42 43 44 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 36 def initialize(token_id:, token_secret:, base_url: nil, base_urls: nil, ssl_verify: true, connect_timeout: 10) urls = base_urls || Array(base_url) @base_urls = urls.map { |u| u.chomp('/') } @token_id = token_id @token_secret = token_secret @ssl_verify = ssl_verify @connect_timeout = connect_timeout @preferred_url_index = nil end |
Instance Attribute Details
#base_urls ⇒ Object (readonly)
Returns the value of attribute base_urls.
32 33 34 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 32 def base_urls @base_urls end |
#connect_timeout ⇒ Object (readonly)
Returns the value of attribute connect_timeout.
32 33 34 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 32 def connect_timeout @connect_timeout end |
#ssl_verify ⇒ Object (readonly)
Returns the value of attribute ssl_verify.
32 33 34 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 32 def ssl_verify @ssl_verify end |
#token_id ⇒ Object (readonly)
Returns the value of attribute token_id.
32 33 34 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 32 def token_id @token_id end |
#token_secret ⇒ Object (readonly)
Returns the value of attribute token_secret.
32 33 34 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 32 def token_secret @token_secret end |
Instance Method Details
#agent_network_interfaces(node:, vm_id:) ⇒ Object
121 122 123 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 121 def agent_network_interfaces(node:, vm_id:) get("/api2/json/nodes/#{node}/qemu/#{vm_id}/agent/network-get-interfaces") end |
#base_url ⇒ Object
Backward-compat reader: returns the first (or preferred) URL.
47 48 49 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 47 def base_url @base_urls[@preferred_url_index || 0] end |
#clone_vm(node:, template_id:, new_id:, **options) ⇒ Object
59 60 61 62 63 64 65 66 67 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 59 def clone_vm(node:, template_id:, new_id:, **) full = .fetch(:full, true) target = .fetch(:target, node) body = { newid: new_id, full: full ? 1 : 0, target: } body[:name] = [:name] if [:name] body[:pool] = [:pool] if [:pool] body[:storage] = [:storage] if [:storage] post("/api2/json/nodes/#{node}/qemu/#{template_id}/clone", body) end |
#configure_vm(node:, vm_id:, cpus: nil, memory: nil, network_bridge: nil) ⇒ Object
69 70 71 72 73 74 75 76 77 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 69 def configure_vm(node:, vm_id:, cpus: nil, memory: nil, network_bridge: nil) body = {} body[:cores] = cpus if cpus body[:memory] = memory if memory body[:net0] = "virtio,bridge=#{network_bridge}" if network_bridge return nil if body.empty? put("/api2/json/nodes/#{node}/qemu/#{vm_id}/config", body) end |
#destroy_vm(node:, vm_id:, purge: true) ⇒ Object
87 88 89 90 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 87 def destroy_vm(node:, vm_id:, purge: true) params = purge ? { purge: 1 } : {} delete("/api2/json/nodes/#{node}/qemu/#{vm_id}", params) end |
#list_nodes ⇒ Object
125 126 127 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 125 def list_nodes get('/api2/json/nodes') end |
#list_storage(node:) ⇒ Object
134 135 136 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 134 def list_storage(node:) get("/api2/json/nodes/#{node}/storage") end |
#list_templates ⇒ Object
129 130 131 132 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 129 def list_templates resources = get('/api2/json/cluster/resources?type=vm') resources.select { |r| r['template'] == 1 } end |
#next_vm_id ⇒ Object
51 52 53 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 51 def next_vm_id get('/api2/json/cluster/nextid') end |
#start_vm(node:, vm_id:) ⇒ Object
79 80 81 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 79 def start_vm(node:, vm_id:) post("/api2/json/nodes/#{node}/qemu/#{vm_id}/status/start") end |
#stop_vm(node:, vm_id:) ⇒ Object
83 84 85 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 83 def stop_vm(node:, vm_id:) post("/api2/json/nodes/#{node}/qemu/#{vm_id}/status/stop") end |
#task_status(node:, upid:) ⇒ Object
100 101 102 103 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 100 def task_status(node:, upid:) encoded = URI.encode_www_form_component(upid) get("/api2/json/nodes/#{node}/tasks/#{encoded}/status") end |
#validate_vmid(vm_id) ⇒ Object
55 56 57 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 55 def validate_vmid(vm_id) get("/api2/json/cluster/nextid?vmid=#{vm_id}") end |
#vm_config(node:, vm_id:) ⇒ Object
96 97 98 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 96 def vm_config(node:, vm_id:) get("/api2/json/nodes/#{node}/qemu/#{vm_id}/config") end |
#vm_status(node:, vm_id:) ⇒ Object
92 93 94 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 92 def vm_status(node:, vm_id:) get("/api2/json/nodes/#{node}/qemu/#{vm_id}/status/current") end |
#wait_for_task(node:, upid:, timeout: 300, interval: 2) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/kitchen/driver/proxmox/api_client.rb', line 105 def wait_for_task(node:, upid:, timeout: 300, interval: 2) deadline = Time.now + timeout loop do status = task_status(node:, upid:) if status['status'] == 'stopped' exitstatus = status['exitstatus'].to_s raise ProxmoxErrors::ApiError.new(500, exitstatus) unless exitstatus == 'OK' return status end raise "Task timeout after #{timeout}s: #{upid}" if Time.now > deadline sleep interval end end |