Class: Pvectl::Repositories::Vm
- Defined in:
- lib/pvectl/repositories/vm.rb
Overview
Repository for QEMU virtual machines.
Uses the ‘/cluster/resources` API endpoint to list VMs across the cluster. Filters to only include QEMU VMs (excludes LXC containers).
Instance Method Summary collapse
-
#clone(vmid, node, new_vmid, options = {}) ⇒ String
Clones a VM to create a new VM.
-
#cloudinit_dump(node, vmid, type) ⇒ String
Dumps the generated cloud-init configuration for a VM.
-
#cloudinit_pending(node, vmid) ⇒ Array<Hash{Symbol => untyped}>
Fetches pending cloud-init configuration changes for a VM.
-
#cloudinit_regenerate(node, vmid) ⇒ nil
Regenerates the cloud-init configuration ISO for a VM.
-
#convert_to_template(vmid, node, disk: nil) ⇒ void
Converts a VM to a template.
-
#create(node, vmid, params = {}) ⇒ String
Creates a new VM on the specified node.
-
#delete(vmid, node, destroy_disks: true, purge: false, force: false) ⇒ String
Deletes a VM from the cluster.
-
#describe(vmid) ⇒ Models::Vm?
Describes a VM with comprehensive details from multiple API endpoints.
-
#feature_available?(vmid, node, feature, snapname: nil) ⇒ Hash
Checks whether a feature (clone, snapshot, copy) is available for a VM.
-
#fetch_config(node, vmid) ⇒ Hash
Fetches VM configuration.
-
#get(vmid) ⇒ Models::Vm?
Gets a single VM by VMID.
-
#list(node: nil) ⇒ Array<Models::Vm>
Lists all VMs in the cluster.
-
#migrate(vmid, node, params = {}) ⇒ String
Migrates a VM to another node.
-
#move_disk(vmid, node, disk, target_storage, format: nil, delete: false, bwlimit: nil) ⇒ String
Moves a VM disk to a different storage on the same node.
-
#next_available_vmid ⇒ Integer
Returns the next available VMID from the Proxmox cluster.
-
#reset(vmid, node) ⇒ String
Resets a VM (hard reset).
-
#resize(vmid, node, disk:, size:) ⇒ nil
Resizes a VM disk.
-
#restart(vmid, node) ⇒ String
Restarts a VM (reboot).
-
#resume(vmid, node) ⇒ String
Resumes a suspended VM.
-
#sendkey(vmid, node, key) ⇒ nil
Sends a QEMU monitor key event to a running VM.
-
#shutdown(vmid, node) ⇒ String
Shuts down a VM gracefully (ACPI).
-
#start(vmid, node) ⇒ String
Starts a VM.
-
#stop(vmid, node) ⇒ String
Stops a VM immediately (hard stop).
-
#suspend(vmid, node) ⇒ String
Suspends a VM (hibernate).
-
#termproxy(vmid, node) ⇒ Hash
Opens a terminal proxy session for a VM.
-
#unlink_disks(node, vmid, disk_ids, force: false) ⇒ nil
Unlinks (removes) one or more disks from a VM configuration.
-
#update(vmid, node, params = {}) ⇒ nil
Updates an existing VM configuration.
Methods inherited from Base
Constructor Details
This class inherits a constructor from Pvectl::Repositories::Base
Instance Method Details
#clone(vmid, node, new_vmid, options = {}) ⇒ String
Clones a VM to create a new VM.
Posts to ‘/nodes/node/qemu/vmid/clone` with the specified parameters.
187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/pvectl/repositories/vm.rb', line 187 def clone(vmid, node, new_vmid, = {}) params = { newid: new_vmid } params[:name] = [:name] if [:name] params[:target] = [:target] if [:target] params[:storage] = [:storage] if [:storage] params[:full] = [:full] ? 1 : 0 if .key?(:full) params[:description] = [:description] if [:description] params[:pool] = [:pool] if [:pool] connection.client["nodes/#{node}/qemu/#{vmid}/clone"].post(params) end |
#cloudinit_dump(node, vmid, type) ⇒ String
Dumps the generated cloud-init configuration for a VM.
GETs from /nodes/{node}/qemu/{vmid}/cloudinit/dump with the specified type query parameter. Returns the raw YAML/text body.
390 391 392 |
# File 'lib/pvectl/repositories/vm.rb', line 390 def cloudinit_dump(node, vmid, type) connection.client["nodes/#{node}/qemu/#{vmid}/cloudinit/dump"].get(params: { type: type }) end |
#cloudinit_pending(node, vmid) ⇒ Array<Hash{Symbol => untyped}>
Fetches pending cloud-init configuration changes for a VM.
GETs from /nodes/{node}/qemu/{vmid}/cloudinit. Returns an array of pending entries, each with :key, :value, :pending, and optional :delete keys.
376 377 378 379 |
# File 'lib/pvectl/repositories/vm.rb', line 376 def cloudinit_pending(node, vmid) response = connection.client["nodes/#{node}/qemu/#{vmid}/cloudinit"].get normalize_response(response) end |
#cloudinit_regenerate(node, vmid) ⇒ nil
Regenerates the cloud-init configuration ISO for a VM.
PUTs to /nodes/{node}/qemu/{vmid}/cloudinit. The Proxmox API endpoint returns null on success.
363 364 365 |
# File 'lib/pvectl/repositories/vm.rb', line 363 def cloudinit_regenerate(node, vmid) connection.client["nodes/#{node}/qemu/#{vmid}/cloudinit"].put end |
#convert_to_template(vmid, node, disk: nil) ⇒ void
This method returns an undefined value.
Converts a VM to a template.
This is an irreversible operation. The VM will become read-only and can only be used as a source for cloning.
208 209 210 211 212 |
# File 'lib/pvectl/repositories/vm.rb', line 208 def convert_to_template(vmid, node, disk: nil) params = {} params[:disk] = disk if disk connection.client["nodes/#{node}/qemu/#{vmid}/template"].post(params) end |
#create(node, vmid, params = {}) ⇒ String
Creates a new VM on the specified node.
Posts to ‘/nodes/node/qemu` with the VM configuration parameters. The vmid is merged into params automatically.
227 228 229 230 |
# File 'lib/pvectl/repositories/vm.rb', line 227 def create(node, vmid, params = {}) api_params = params.merge(vmid: vmid) connection.client["nodes/#{node}/qemu"].post(api_params) end |
#delete(vmid, node, destroy_disks: true, purge: false, force: false) ⇒ String
Deletes a VM from the cluster.
163 164 165 166 167 168 169 170 |
# File 'lib/pvectl/repositories/vm.rb', line 163 def delete(vmid, node, destroy_disks: true, purge: false, force: false) params = {} params["destroy-unreferenced-disks"] = 1 if destroy_disks params[:purge] = 1 if purge params[:skiplock] = 1 if force connection.client["nodes/#{node}/qemu/#{vmid}"].delete(params) end |
#describe(vmid) ⇒ Models::Vm?
Describes a VM with comprehensive details from multiple API endpoints.
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/pvectl/repositories/vm.rb', line 55 def describe(vmid) vmid = vmid.to_i # 1. Find VM in cluster to get node basic_data = find_vm_basic_data(vmid) return nil if basic_data.nil? node = basic_data[:node] # 2. Fetch detailed data from node-specific endpoints describe_data = { config: fetch_config(node, vmid), status: fetch_status(node, vmid), snapshots: fetch_snapshots(node, vmid), agent_ips: fetch_agent_ips(node, vmid), pending: fetch_pending(node, vmid), tasks: fetch_tasks(node, vmid), firewall: fetch_firewall(node, vmid) } build_describe_model(basic_data, describe_data) end |
#feature_available?(vmid, node, feature, snapname: nil) ⇒ Hash
Checks whether a feature (clone, snapshot, copy) is available for a VM.
Calls GET /nodes/{node}/qemu/{vmid}/feature with the feature and optional snapshot name. The Proxmox API returns hasFeature (0/1) and a nodes array listing cluster nodes that satisfy the feature.
409 410 411 412 413 414 415 416 417 418 419 420 |
# File 'lib/pvectl/repositories/vm.rb', line 409 def feature_available?(vmid, node, feature, snapname: nil) params = { feature: feature } params[:snapname] = snapname unless snapname.nil? response = connection.client["nodes/#{node}/qemu/#{vmid}/feature"].get(params: params) data = normalize_hash_response(response) { available: data[:hasFeature].to_i == 1, nodes: Array(data[:nodes]) } end |
#fetch_config(node, vmid) ⇒ Hash
Fetches VM configuration.
299 300 301 302 303 304 |
# File 'lib/pvectl/repositories/vm.rb', line 299 def fetch_config(node, vmid) resp = connection.client["nodes/#{node}/qemu/#{vmid}/config"].get normalize_hash_response(resp) rescue StandardError {} end |
#get(vmid) ⇒ Models::Vm?
Gets a single VM by VMID.
47 48 49 |
# File 'lib/pvectl/repositories/vm.rb', line 47 def get(vmid) list.find { |vm| vm.vmid == vmid.to_i } end |
#list(node: nil) ⇒ Array<Models::Vm>
Lists all VMs in the cluster.
Uses ‘/cluster/resources?type=vm` endpoint for efficient cluster-wide listing. Filters to only include QEMU VMs (type == “qemu”).
36 37 38 39 40 41 |
# File 'lib/pvectl/repositories/vm.rb', line 36 def list(node: nil) response = connection.client["cluster/resources"].get(params: { type: "vm" }) vms = response.select { |r| r[:type] == "qemu" } vms = vms.select { |r| r[:node] == node } if node vms.map { |data| build_model(data) } end |
#migrate(vmid, node, params = {}) ⇒ String
Migrates a VM to another node.
313 314 315 316 317 318 319 320 321 322 |
# File 'lib/pvectl/repositories/vm.rb', line 313 def migrate(vmid, node, params = {}) unless node.match?(/\A[a-z][a-z0-9-]*\z/) raise ArgumentError, "Invalid node name: #{node}" end unless vmid.is_a?(Integer) && vmid.positive? raise ArgumentError, "Invalid VMID: #{vmid}" end connection.client["nodes/#{node}/qemu/#{vmid}/migrate"].post(params) end |
#move_disk(vmid, node, disk, target_storage, format: nil, delete: false, bwlimit: nil) ⇒ String
Moves a VM disk to a different storage on the same node.
POSTs to /nodes/{node}/qemu/{vmid}/move_disk with the disk identifier and target storage. The operation is asynchronous — the returned UPID can be polled via Repositories::Task to track completion.
346 347 348 349 350 351 352 353 |
# File 'lib/pvectl/repositories/vm.rb', line 346 def move_disk(vmid, node, disk, target_storage, format: nil, delete: false, bwlimit: nil) params = { disk: disk, storage: target_storage } params[:format] = format if format params[:delete] = 1 if delete params[:bwlimit] = bwlimit if bwlimit connection.client["nodes/#{node}/qemu/#{vmid}/move_disk"].post(params) end |
#next_available_vmid ⇒ Integer
Returns the next available VMID from the Proxmox cluster.
Uses the /cluster/nextid API endpoint which performs server-side allocation. This is more reliable than client-side scanning because it detects stale config files that don’t appear in /cluster/resources.
429 430 431 |
# File 'lib/pvectl/repositories/vm.rb', line 429 def next_available_vmid connection.client["cluster/nextid"].get.to_i end |
#reset(vmid, node) ⇒ String
Resets a VM (hard reset).
123 124 125 |
# File 'lib/pvectl/repositories/vm.rb', line 123 def reset(vmid, node) post_status(vmid, node, "reset") end |
#resize(vmid, node, disk:, size:) ⇒ nil
Resizes a VM disk.
PUTs to /nodes/{node}/qemu/{vmid}/resize with disk and size parameters. Size can be absolute (e.g., “50G”) or relative (e.g., “+10G”).
255 256 257 |
# File 'lib/pvectl/repositories/vm.rb', line 255 def resize(vmid, node, disk:, size:) connection.client["nodes/#{node}/qemu/#{vmid}/resize"].put({ disk: disk, size: size }) end |
#restart(vmid, node) ⇒ String
Restarts a VM (reboot).
114 115 116 |
# File 'lib/pvectl/repositories/vm.rb', line 114 def restart(vmid, node) post_status(vmid, node, "reboot") end |
#resume(vmid, node) ⇒ String
Resumes a suspended VM.
141 142 143 |
# File 'lib/pvectl/repositories/vm.rb', line 141 def resume(vmid, node) post_status(vmid, node, "resume") end |
#sendkey(vmid, node, key) ⇒ nil
Sends a QEMU monitor key event to a running VM.
PUTs to /nodes/{node}/qemu/{vmid}/sendkey with the key parameter. The key uses QEMU qcode format (e.g., “ctrl-alt-delete”, “ret”, “f1”). This is a synchronous operation — Proxmox returns null on success.
269 270 271 |
# File 'lib/pvectl/repositories/vm.rb', line 269 def sendkey(vmid, node, key) connection.client["nodes/#{node}/qemu/#{vmid}/sendkey"].put({ key: key }) end |
#shutdown(vmid, node) ⇒ String
Shuts down a VM gracefully (ACPI).
105 106 107 |
# File 'lib/pvectl/repositories/vm.rb', line 105 def shutdown(vmid, node) post_status(vmid, node, "shutdown") end |
#start(vmid, node) ⇒ String
Starts a VM.
87 88 89 |
# File 'lib/pvectl/repositories/vm.rb', line 87 def start(vmid, node) post_status(vmid, node, "start") end |
#stop(vmid, node) ⇒ String
Stops a VM immediately (hard stop).
96 97 98 |
# File 'lib/pvectl/repositories/vm.rb', line 96 def stop(vmid, node) post_status(vmid, node, "stop") end |
#suspend(vmid, node) ⇒ String
Suspends a VM (hibernate).
132 133 134 |
# File 'lib/pvectl/repositories/vm.rb', line 132 def suspend(vmid, node) post_status(vmid, node, "suspend") end |
#termproxy(vmid, node) ⇒ Hash
Opens a terminal proxy session for a VM.
150 151 152 153 |
# File 'lib/pvectl/repositories/vm.rb', line 150 def termproxy(vmid, node) response = connection.client["nodes/#{node}/qemu/#{vmid}/termproxy"].post({}) normalize_hash_response(response) end |
#unlink_disks(node, vmid, disk_ids, force: false) ⇒ nil
Unlinks (removes) one or more disks from a VM configuration.
PUTs to /nodes/{node}/qemu/{vmid}/unlink with the comma-separated list of disk IDs. By default, Proxmox keeps removed volumes as unused[n] entries in the config; with force: true the underlying volume is physically removed.
287 288 289 290 291 292 |
# File 'lib/pvectl/repositories/vm.rb', line 287 def unlink_disks(node, vmid, disk_ids, force: false) idlist = Array(disk_ids).flat_map { |id| id.to_s.split(",") }.map(&:strip).reject(&:empty?).join(",") connection.client["nodes/#{node}/qemu/#{vmid}/unlink"].put( { idlist: idlist, force: force ? 1 : 0 } ) end |
#update(vmid, node, params = {}) ⇒ nil
Updates an existing VM configuration.
PUTs to /nodes/{node}/qemu/{vmid}/config with configuration parameters. This is a synchronous operation — changes are applied immediately.
241 242 243 |
# File 'lib/pvectl/repositories/vm.rb', line 241 def update(vmid, node, params = {}) connection.client["nodes/#{node}/qemu/#{vmid}/config"].put(params) end |