Class: Knife::Proxmox::Provisioner

Inherits:
Object
  • Object
show all
Defined in:
lib/knife-proxmox-ve/provisioner.rb

Overview

The single place the clone -> configure -> start -> wait-for-IP sequence lives, and the one place cloud-init param encoding policy is defined. Everything that requires ordering between Api round-trips belongs here; Api itself stays stateless.

Dependencies are injected so the whole sequence is testable without sockets or sleeps:

* +api+        — Knife::Proxmox::Api
* +ui+         — duck-typed #info/#warn sink (optional; progress is best-effort)
* +port_check+ — ->(host, port) { bool }; defaults to a real, short TCP connect
* +sleeper+    — ->(seconds) {}; defaults to Kernel#sleep

Defined Under Namespace

Classes: Result

Constant Summary collapse

POLL_INTERVAL =

Backoff between TCP/agent polls while waiting for the guest to come up.

2
PORT_CHECK_TIMEOUT =

Time budget for a single TCP connect probe.

2
CLOUDINIT_DRIVE_KEY =

A cloud-init drive lives on one of these controllers with a value naming "cloudinit".

/\A(?:ide|scsi|sata)\d+\z/
CLOUDINIT_DRIVE_VALUE =
/cloudinit/
DISK_KEY =

Config keys that can carry a resizable virtual disk.

/\A(?:scsi|virtio|sata|ide)\d+\z/
NON_DISK_VALUE =

Drives that are not resizable storage: the cloud-init drive and any CD-ROM.

/cloudinit|media=cdrom/
BOOT_ORDER =

Modern boot config: "boot: order=scsi0;ide2;net0".

/\border=([^,]+)/
UPID_PREFIX =

A Proxmox worker id, as returned by endpoints that offload their work to a task.

"UPID:"
DUPLICATE_ID =

Proxmox reports a VMID collision as a non-2xx body mentioning the existing id.

/already exists|config file already exists|VM \d+ already/i

Instance Method Summary collapse

Constructor Details

#initialize(api, ui: nil, port_check: nil, sleeper: nil) ⇒ Provisioner

Returns a new instance of Provisioner.



49
50
51
52
53
54
# File 'lib/knife-proxmox-ve/provisioner.rb', line 49

def initialize(api, ui: nil, port_check: nil, sleeper: nil)
  @api = api
  @ui = ui
  @port_check = port_check || method(:tcp_open?)
  @sleeper = sleeper || ->(seconds) { sleep(seconds) }
end

Instance Method Details

#provision(spec) ⇒ Object

Run the full provisioning sequence for spec (see the class header / WU contract for its shape). Returns a Result; raises Knife::Proxmox::* loudly on any failure.



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/knife-proxmox-ve/provisioner.rb', line 58

def provision(spec)
  template = spec.fetch(:template)
  newid = clone_with_retry(spec, template)
  node = spec[:target_node] || template[:node]

  params = build_config(spec.fetch(:config, {}) || {})
  # One read serves both the cloud-init drive guard and disk discovery; a hardware-only
  # provision needs neither and never reads the config back.
  vm_config = read_vm_config(node, newid, params, spec)
  guard_cloud_init_drive!(vm_config, spec[:name]) if cloud_init?(params)
  @api.update_config(node:, vmid: newid, **params) unless params.empty?
  resize_disk!(node, newid, vm_config, spec) if spec[:disk_size]

  boot(node, newid)
  ip = wait_for_ip(spec, node, newid)

  Result.new(vmid: newid, node:, ip:)
end