kitchen-proxmox 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9431e030d0300d57c9fac8a20047375865cedf9f4a48b34b3039370f2d62a98a
4
- data.tar.gz: 62e91255a7b9b2586eeef54bcd76bb7110b782ae8c948853ef0691a13e11df5e
3
+ metadata.gz: 8592a8c21a5245c5517893fb3de6c2c2a9cae921cdb8c499fd3a7bcfcc8dc35a
4
+ data.tar.gz: eb18680f687a41ef9a5a5c2f4b290e586e867de4795cdc5733998189fb3b4e85
5
5
  SHA512:
6
- metadata.gz: e974ac8b7626ed1232e608073c259f5bb90c65aa47bdaf9327195a255dfbcbb7eb969a6cd88c5781c929835daa84f52a63e83aa6e291199de3d32889c244300b
7
- data.tar.gz: 4b36857b3cfb877ff3bcf292049389cbe26cd43ab2393fb235d3236e8ad5d50ba74ed1ae55076961f97294f2df14e9a8d98d683a50afe4f37af5253ca3066f63
6
+ metadata.gz: 8da473dbe9ddf5891bff39a77fe3a55db3fd263a4413592e0c55d826387dbde2e60f77287516f31dd5083200d8d5c962ceaf811f43ad0b89e1a794311ece678b
7
+ data.tar.gz: c93d6729fa61fbc286cdd6b64e03febad2ea3995c1a29e346e5c35037f51339f84aef79370c90443ce96f4ec94fb494225fbf05a3ad27942378c97b54e2d9e36
@@ -27,6 +27,10 @@ module Kitchen
27
27
  get('/api2/json/cluster/nextid')
28
28
  end
29
29
 
30
+ def validate_vmid(vm_id)
31
+ get("/api2/json/cluster/nextid?vmid=#{vm_id}")
32
+ end
33
+
30
34
  def clone_vm(node:, template_id:, new_id:, **options)
31
35
  full = options.fetch(:full, true)
32
36
  body = { newid: new_id, full: full ? 1 : 0, target: node }
@@ -76,7 +80,14 @@ module Kitchen
76
80
  deadline = Time.now + timeout
77
81
  loop do
78
82
  status = task_status(node:, upid:)
79
- return status if status['status'] == 'stopped'
83
+ if status['status'] == 'stopped'
84
+ exitstatus = status['exitstatus'].to_s
85
+ unless exitstatus == 'OK'
86
+ raise ProxmoxErrors::ApiError.new(500, exitstatus)
87
+ end
88
+
89
+ return status
90
+ end
80
91
  raise "Task timeout after #{timeout}s: #{upid}" if Time.now > deadline
81
92
 
82
93
  sleep interval
@@ -13,12 +13,25 @@ module Kitchen
13
13
  super("Proxmox API error #{status_code}: #{response_body}")
14
14
  end
15
15
 
16
- # Returns true when the error indicates a VMID is already in use.
16
+ # Returns true when the error indicates a VMID is already in use
17
+ # or cannot be locked (concurrent clone race).
17
18
  def vmid_conflict?
18
19
  return false unless status_code == 400 || status_code == 500
19
20
 
20
21
  response_body.match?(/already exists/i) ||
21
- response_body.match?(/unable to create VM \d+/i)
22
+ response_body.match?(/unable to create VM \d+/i) ||
23
+ response_body.match?(/can't lock file.*lock-\d+/i)
24
+ end
25
+
26
+ # Returns true when the error indicates another process owns the VM
27
+ # (lost a VMID race — VM was started or configured by another clone).
28
+ def vmid_race_lost?
29
+ return false unless status_code == 400 || status_code == 500
30
+
31
+ response_body.match?(/already running/i) ||
32
+ response_body.match?(/hotplug problem/i) ||
33
+ response_body.match?(/does not exist/i) ||
34
+ response_body.match?(/can't lock file.*lock-\d+/i)
22
35
  end
23
36
  end
24
37
  end
@@ -36,6 +36,8 @@ module Kitchen
36
36
  default_config :start_timeout, 300
37
37
  default_config :ip_wait_timeout, 120
38
38
  default_config :clone_retries, 5
39
+ default_config :vmid_range_min, 900_000
40
+ default_config :vmid_range_max, 999_999
39
41
 
40
42
  def create(state)
41
43
  return if state[:vm_id]
@@ -67,16 +69,33 @@ module Kitchen
67
69
  end
68
70
 
69
71
  def clone_and_start(state)
70
- info("Creating Proxmox VM from template #{config[:template_id]}...")
72
+ retries = config[:clone_retries]
73
+ last_error = nil
74
+
75
+ retries.times do |attempt|
76
+ info("Creating Proxmox VM from template #{config[:template_id]}...")
77
+
78
+ vm_id, vm_name = allocate_and_clone
79
+ state[:vm_id] = vm_id
80
+ state[:vm_name] = vm_name
71
81
 
72
- vm_id, vm_name = allocate_and_clone
73
- state[:vm_id] = vm_id
74
- state[:vm_name] = vm_name
82
+ begin
83
+ configure_hardware(vm_id)
84
+ start_and_wait_for_ip(state, vm_id)
85
+ info("Proxmox VM #{vm_name} (#{vm_id}) created.")
86
+ return
87
+ rescue ApiError => e
88
+ raise unless e.vmid_race_lost?
75
89
 
76
- configure_hardware(vm_id)
77
- start_and_wait_for_ip(state, vm_id)
90
+ last_error = e
91
+ warn("VMID #{vm_id} race lost (attempt #{attempt + 1}/#{retries}): #{e.message}")
92
+ warn("Another process owns VM #{vm_id} — abandoning and retrying...")
93
+ clear_state(state)
94
+ sleep backoff_delay(attempt)
95
+ end
96
+ end
78
97
 
79
- info("Proxmox VM #{vm_name} (#{vm_id}) created.")
98
+ raise last_error
80
99
  end
81
100
 
82
101
  def allocate_and_clone
@@ -107,7 +126,9 @@ module Kitchen
107
126
  end
108
127
 
109
128
  def allocate_vm_id
110
- Integer(api_client.next_vm_id)
129
+ vm_id = rand(config[:vmid_range_min]..config[:vmid_range_max])
130
+ api_client.validate_vmid(vm_id)
131
+ vm_id
111
132
  end
112
133
 
113
134
  def generate_vm_name(suite_name)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-proxmox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Nixon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-05-03 00:00:00.000000000 Z
11
+ date: 2026-05-04 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A Test Kitchen driver for Proxmox VE. Manages VM lifecycle (create, destroy)
14
14
  via the Proxmox REST API. Supports cloning from templates.