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 +4 -4
- data/lib/kitchen/driver/proxmox/api_client.rb +12 -1
- data/lib/kitchen/driver/proxmox/errors.rb +15 -2
- data/lib/kitchen/driver/proxmox.rb +29 -8
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8592a8c21a5245c5517893fb3de6c2c2a9cae921cdb8c499fd3a7bcfcc8dc35a
|
|
4
|
+
data.tar.gz: eb18680f687a41ef9a5a5c2f4b290e586e867de4795cdc5733998189fb3b4e85
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
77
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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-
|
|
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.
|