hybrid_platforms_conductor 32.9.0 → 32.11.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/hybrid_platforms_conductor/common_config_dsl/idempotence_tests.rb +23 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox.rb +14 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox/proxmox_waiter.rb +29 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/templates/confluence_inventory.html.erb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/check_deploy_and_idempotence.rb +4 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/divergence.rb +16 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/executables.rb +27 -13
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/idempotence.rb +4 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/templates/confluence.html.erb +1 -1
- data/lib/hybrid_platforms_conductor/version.rb +1 -1
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/retries_spec.rb +44 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/vm_ids_assignment_spec.rb +92 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/state_spec.rb +0 -14
- data/spec/hybrid_platforms_conductor_test/helpers/provisioner_proxmox_helpers.rb +39 -2
- metadata +12 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2162d052fbbe0833d8a26d94d9fc8a490e9c57b0fd35ecd5656be8d3a52a2893
|
4
|
+
data.tar.gz: 40d6251c2dac02c7588ea158174ecb6da4f2381712e8696b5395fdfcb05555ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 572f8136afc8153bcb645c2612b128b7c6aeb2b44fc795fa1785f0dc6bad06298171466b37aef5d03ad38d6f49cb39cab3c268ce6edc0807cb125328e24c6cba
|
7
|
+
data.tar.gz: 993478c8a81af0e5bfce3a74cfe5ce9c8bb4259d0f6063e41912ea905d493a2e6cca801525d45ffd080ba1570d80e2c0097e56aac33ee694526e53e6ee9685ee
|
@@ -11,13 +11,24 @@ module HybridPlatformsConductor
|
|
11
11
|
# Array< Hash<Symbol, Object> >
|
12
12
|
attr_reader :ignored_idempotence_tasks
|
13
13
|
|
14
|
-
#
|
14
|
+
# List of ignored tasks info. Each info has the following properties:
|
15
|
+
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by this rule
|
16
|
+
# * *ignored_tasks* (Hash<String, String>): List of task names for which we ignore divergence errors, with the corresponding descriptive reason for ignore.
|
17
|
+
# Array< Hash<Symbol, Object> >
|
18
|
+
attr_reader :ignored_divergent_tasks
|
19
|
+
|
20
|
+
# Initialize the DSL
|
15
21
|
def init_idempotence_tests
|
16
22
|
# List of ignored tasks info. Each info has the following properties:
|
17
23
|
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by this rule
|
18
24
|
# * *ignored_tasks* (Hash<String, String>): List of task names for which we ignore idempotence errors, with the corresponding descriptive reason for ignore.
|
19
25
|
# Array< Hash<Symbol, Object> >
|
20
26
|
@ignored_idempotence_tasks = []
|
27
|
+
# List of ignored tasks info. Each info has the following properties:
|
28
|
+
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by this rule
|
29
|
+
# * *ignored_tasks* (Hash<String, String>): List of task names for which we ignore divergence errors, with the corresponding descriptive reason for ignore.
|
30
|
+
# Array< Hash<Symbol, Object> >
|
31
|
+
@ignored_divergent_tasks = []
|
21
32
|
end
|
22
33
|
|
23
34
|
# Ignore idempotence errors on a set of tasks
|
@@ -31,6 +42,17 @@ module HybridPlatformsConductor
|
|
31
42
|
}
|
32
43
|
end
|
33
44
|
|
45
|
+
# Ignore idempotence errors on a set of tasks
|
46
|
+
#
|
47
|
+
# Parameters::
|
48
|
+
# * *tasks_to_ignore* (Hash<String, String>): Set of tasks to ignore, along with the reason
|
49
|
+
def ignore_divergent_tasks(tasks_to_ignore)
|
50
|
+
@ignored_divergent_tasks << {
|
51
|
+
ignored_tasks: tasks_to_ignore,
|
52
|
+
nodes_selectors_stack: current_nodes_selectors_stack,
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
34
56
|
end
|
35
57
|
|
36
58
|
end
|
@@ -18,11 +18,19 @@ module HybridPlatformsConductor
|
|
18
18
|
attr_accessor *%i[logger logger_stderr]
|
19
19
|
|
20
20
|
def check_response(response)
|
21
|
-
|
22
|
-
|
21
|
+
msg = "Response from Proxmox API: #{response} - #{response.net_http_res.message}"
|
22
|
+
log_debug msg
|
23
|
+
log_warn msg if response.code >= 400 && !log_debug?
|
23
24
|
super
|
24
25
|
end
|
25
26
|
|
27
|
+
# Re-authenticate the Proxmox instance
|
28
|
+
# This can be useful when the API returns errors due to invalidated tokens
|
29
|
+
def reauthenticate
|
30
|
+
log_debug 'Force re-authentication to Proxmox'
|
31
|
+
@auth_params = create_ticket
|
32
|
+
end
|
33
|
+
|
26
34
|
end
|
27
35
|
::Proxmox::Proxmox.prepend ProxmoxPatches
|
28
36
|
|
@@ -309,6 +317,8 @@ module HybridPlatformsConductor
|
|
309
317
|
log_warn "[ #{@node}/#{@environment} ] - Proxmox API call get #{path} returned error #{response} (attempt ##{idx_try}/#{proxmox_test_info[:api_max_retries]})"
|
310
318
|
raise "[ #{@node}/#{@environment} ] - Proxmox API call get #{path} returns #{response} continuously (tried #{idx_try + 1} times)" if idx_try >= proxmox_test_info[:api_max_retries]
|
311
319
|
idx_try += 1
|
320
|
+
# We have to reauthenticate: error 500 raised by Proxmox are often due to token being invalidated wrongly
|
321
|
+
proxmox.reauthenticate
|
312
322
|
sleep proxmox_test_info[:api_wait_between_retries_secs] + rand(5)
|
313
323
|
end
|
314
324
|
response
|
@@ -333,6 +343,8 @@ module HybridPlatformsConductor
|
|
333
343
|
task = nil
|
334
344
|
break if idx_try >= proxmox_test_info[:api_max_retries]
|
335
345
|
idx_try += 1
|
346
|
+
# We have to reauthenticate: error 500 raised by Proxmox are often due to token being invalidated wrongly
|
347
|
+
proxmox.reauthenticate
|
336
348
|
sleep proxmox_test_info[:api_wait_between_retries_secs] + rand(5)
|
337
349
|
end
|
338
350
|
end
|
@@ -605,10 +605,35 @@ class ProxmoxWaiter
|
|
605
605
|
# Result::
|
606
606
|
# * Array<Integer>: List of available VM IDs
|
607
607
|
def free_vm_ids
|
608
|
-
Range.new(*@config['vm_ids_range']).to_a -
|
608
|
+
vm_ids = Range.new(*@config['vm_ids_range']).to_a -
|
609
609
|
api_get('nodes').map do |pve_node_info|
|
610
610
|
api_get("nodes/#{pve_node_info['node']}/lxc").map { |lxc_info| Integer(lxc_info['vmid']) }
|
611
611
|
end.flatten
|
612
|
+
# Make sure the vm_ids that are available don't have any leftovers in the cgroups.
|
613
|
+
# This can happen with some Proxmox bugs, and make the API returns 500 errors.
|
614
|
+
# cf. https://forum.proxmox.com/threads/lxc-console-cleanup-error.38293/
|
615
|
+
# TODO: Remove this when Proxmox will have solved the issue with leftovers of destroyed vms.
|
616
|
+
(vm_ids.map(&:to_s) & vm_ids_in_cgroups).each do |vm_id_str|
|
617
|
+
# We are having a vm_id that is available but still has some leftovers in cgroups.
|
618
|
+
# Clean those to avoid 500 errors in API.
|
619
|
+
log "Found VMID #{vm_id_str} with leftovers in cgroups. Cleaning those."
|
620
|
+
Dir.glob("/sys/fs/cgroup/*/lxc/#{vm_id_str}") do |cgroup_dir|
|
621
|
+
log "Removing #{cgroup_dir}"
|
622
|
+
FileUtils.rm_rf cgroup_dir
|
623
|
+
end
|
624
|
+
end
|
625
|
+
vm_ids
|
626
|
+
end
|
627
|
+
|
628
|
+
# Return the list of VM IDs present in cgroups
|
629
|
+
#
|
630
|
+
# Result::
|
631
|
+
# * Array<String>: List of VM IDs as strings (as some are not Integers like '1010-1')
|
632
|
+
def vm_ids_in_cgroups
|
633
|
+
Dir.glob('/sys/fs/cgroup/*/lxc/*').map do |file|
|
634
|
+
basename = File.basename(file)
|
635
|
+
basename =~ /^\d.+$/ ? basename : nil
|
636
|
+
end.compact.sort.uniq
|
612
637
|
end
|
613
638
|
|
614
639
|
# Wait for a given Proxmox task completion
|
@@ -653,6 +678,9 @@ class ProxmoxWaiter
|
|
653
678
|
break unless @gets_cache[path].is_a?(String) && @gets_cache[path] =~ /^NOK: error code = 5\d\d$/
|
654
679
|
raise "Proxmox API get #{path} returns #{@gets_cache[path]} continuously (tried #{idx_try + 1} times)" if idx_try >= @config['api_max_retries']
|
655
680
|
idx_try += 1
|
681
|
+
# We have to reauthenticate: error 500 raised by Proxmox are often due to token being invalidated wrongly
|
682
|
+
# TODO: Provide a way to do it properly in the official gem
|
683
|
+
@proxmox.instance_variable_set(:@auth_params, @proxmox.send(:create_ticket))
|
656
684
|
sleep @config['api_wait_between_retries_secs']
|
657
685
|
end
|
658
686
|
end
|
data/lib/hybrid_platforms_conductor/hpc_plugins/report/templates/confluence_inventory.html.erb
CHANGED
@@ -28,6 +28,6 @@
|
|
28
28
|
</table>
|
29
29
|
<p>
|
30
30
|
<br/>
|
31
|
-
Generated at <%= Time.now.utc.strftime('%F %T') %> UTC by <a href="https://
|
31
|
+
Generated at <%= Time.now.utc.strftime('%F %T') %> UTC by <a href="https://github.com/sweet-delights/hybrid-platforms-conductor">Hybrid Platforms Conductor</a>.
|
32
32
|
<br/>
|
33
33
|
</p>
|
@@ -81,7 +81,10 @@ module HybridPlatformsConductor
|
|
81
81
|
exit_status, stdout, stderr = deployer.deploy_on(@node)[@node]
|
82
82
|
assert_equal exit_status, 0, "Check-node after deployment returned error code #{exit_status}", log_debug? ? nil : deployer.stdouts_to_s
|
83
83
|
# Check that the output of the check-node returns no changes.
|
84
|
-
ignored_tasks =
|
84
|
+
ignored_tasks = (
|
85
|
+
@nodes_handler.select_confs_for_node(@node, @config.ignored_idempotence_tasks) +
|
86
|
+
@nodes_handler.select_confs_for_node(@node, @config.ignored_divergent_tasks)
|
87
|
+
).inject({}) do |merged_ignored_tasks, conf|
|
85
88
|
merged_ignored_tasks.merge(conf[:ignored_tasks])
|
86
89
|
end
|
87
90
|
@deployer.parse_deploy_output(@node, stdout, stderr).each do |task_info|
|
@@ -11,8 +11,23 @@ module HybridPlatformsConductor
|
|
11
11
|
|
12
12
|
# Check my_test_plugin.rb.sample documentation for signature details.
|
13
13
|
def test_on_check_node(stdout, stderr, exit_status)
|
14
|
+
# Check that the output of the check-node returns no changes.
|
15
|
+
ignored_tasks = @nodes_handler.select_confs_for_node(@node, @config.ignored_divergent_tasks).inject({}) do |merged_ignored_tasks, conf|
|
16
|
+
merged_ignored_tasks.merge(conf[:ignored_tasks])
|
17
|
+
end
|
14
18
|
@deployer.parse_deploy_output(@node, stdout, stderr).each do |task_info|
|
15
|
-
|
19
|
+
if task_info[:status] == :changed
|
20
|
+
if ignored_tasks.key?(task_info[:name])
|
21
|
+
# It was expected that this task is not idempotent
|
22
|
+
log_debug "Task #{task_info[:name]} was expected to be divergent. Reason: #{ignored_tasks[task_info[:name]]}"
|
23
|
+
else
|
24
|
+
extra_details = task_info.slice(*(task_info.keys - %i[name status diffs]))
|
25
|
+
error_details = []
|
26
|
+
error_details << "----- Changes:\n#{task_info[:diffs].strip}\n-----" if task_info[:diffs]
|
27
|
+
error_details << "----- Additional details:\n#{JSON.pretty_generate(extra_details)}\n-----" unless extra_details.empty?
|
28
|
+
error "Task #{task_info[:name]} has diverged", error_details.empty? ? nil : error_details.join("\n")
|
29
|
+
end
|
30
|
+
end
|
16
31
|
end
|
17
32
|
end
|
18
33
|
|
@@ -11,24 +11,38 @@ module HybridPlatformsConductor
|
|
11
11
|
|
12
12
|
# Check my_test_plugin.rb.sample documentation for signature details.
|
13
13
|
def test
|
14
|
-
|
15
|
-
example_node = example_platform.known_nodes.first
|
16
|
-
[
|
17
|
-
"#{CmdRunner.executables_prefix}check-node --node #{example_node} --show-commands",
|
18
|
-
"#{CmdRunner.executables_prefix}deploy --node #{example_node} --show-commands --why-run",
|
14
|
+
tests = [
|
19
15
|
"#{CmdRunner.executables_prefix}dump_nodes_json --help",
|
20
16
|
"#{CmdRunner.executables_prefix}free_ips",
|
21
17
|
"#{CmdRunner.executables_prefix}free_veids",
|
22
|
-
"#{CmdRunner.executables_prefix}get_impacted_nodes --platform #{example_platform.name} --show-commands",
|
23
|
-
"#{CmdRunner.executables_prefix}last_deploys --node #{example_node} --show-commands",
|
24
|
-
"#{CmdRunner.executables_prefix}nodes_to_deploy --node #{example_node} --show-commands",
|
25
|
-
"#{CmdRunner.executables_prefix}report --node #{example_node} --format stdout",
|
26
|
-
"#{CmdRunner.executables_prefix}run --node #{example_node} --show-commands --interactive",
|
27
18
|
"#{CmdRunner.executables_prefix}setup --help",
|
28
19
|
"#{CmdRunner.executables_prefix}ssh_config",
|
29
|
-
"#{CmdRunner.executables_prefix}test --help"
|
30
|
-
|
31
|
-
|
20
|
+
"#{CmdRunner.executables_prefix}test --help"
|
21
|
+
]
|
22
|
+
example_platform = PlatformsHandler.new(
|
23
|
+
logger: @logger,
|
24
|
+
logger_stderr: @logger_stderr,
|
25
|
+
config: @config,
|
26
|
+
cmd_runner: @cmd_runner
|
27
|
+
).known_platforms.first
|
28
|
+
unless example_platform.nil?
|
29
|
+
tests.concat [
|
30
|
+
"#{CmdRunner.executables_prefix}get_impacted_nodes --platform #{example_platform.name} --show-commands",
|
31
|
+
]
|
32
|
+
example_node = example_platform.known_nodes.first
|
33
|
+
unless example_node.nil?
|
34
|
+
tests.concat [
|
35
|
+
"#{CmdRunner.executables_prefix}check-node --node #{example_node} --show-commands",
|
36
|
+
"#{CmdRunner.executables_prefix}deploy --node #{example_node} --show-commands --why-run",
|
37
|
+
"#{CmdRunner.executables_prefix}last_deploys --node #{example_node} --show-commands",
|
38
|
+
"#{CmdRunner.executables_prefix}nodes_to_deploy --node #{example_node} --show-commands",
|
39
|
+
"#{CmdRunner.executables_prefix}report --node #{example_node} --format stdout",
|
40
|
+
"#{CmdRunner.executables_prefix}run --node #{example_node} --show-commands --interactive",
|
41
|
+
"#{CmdRunner.executables_prefix}topograph --from \"--node #{example_node}\" --to \"--node #{example_node}\" --skip-run --output graphviz:graph.gv"
|
42
|
+
]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
tests.sort.each do |cmd|
|
32
46
|
log_debug "Testing #{cmd}"
|
33
47
|
exit_status, stdout, _stderr = @cmd_runner.run_cmd "#{cmd} 2>&1", no_exception: true, log_to_stdout: log_debug?
|
34
48
|
assert_equal(exit_status, 0, "Command #{cmd} returned code #{exit_status}:\n#{stdout}")
|
@@ -43,7 +43,10 @@ module HybridPlatformsConductor
|
|
43
43
|
assert_equal tested_node, @node, "Wrong node being tested: #{tested_node} should be #{@node}"
|
44
44
|
assert_equal exit_status, 0, "Check-node returned error code #{exit_status}"
|
45
45
|
# Check that the output of the check-node returns no changes.
|
46
|
-
ignored_tasks =
|
46
|
+
ignored_tasks = (
|
47
|
+
@nodes_handler.select_confs_for_node(@node, @config.ignored_idempotence_tasks) +
|
48
|
+
@nodes_handler.select_confs_for_node(@node, @config.ignored_divergent_tasks)
|
49
|
+
).inject({}) do |merged_ignored_tasks, conf|
|
47
50
|
merged_ignored_tasks.merge(conf[:ignored_tasks])
|
48
51
|
end
|
49
52
|
@deployer.parse_deploy_output(@node, stdout, stderr).each do |task_info|
|
@@ -237,6 +237,6 @@
|
|
237
237
|
</table>
|
238
238
|
<p>
|
239
239
|
<br/>
|
240
|
-
Generated at <%= Time.now.utc.strftime('%F %T') %> UTC by <a href="https://
|
240
|
+
Generated at <%= Time.now.utc.strftime('%F %T') %> UTC by <a href="https://github.com/sweet-delights/hybrid-platforms-conductor">Hybrid Platforms Conductor</a>.
|
241
241
|
<br/>
|
242
242
|
</p>
|
@@ -10,6 +10,7 @@ describe HybridPlatformsConductor::HpcPlugins::Provisioner::Proxmox do
|
|
10
10
|
with_sync_node do
|
11
11
|
mock_proxmox(mocked_pve_nodes: [{ 'pve_node_name' => {} }] * 5)
|
12
12
|
expect(call_reserve_proxmox_container(2, 128 * 1024, 4, max_retries: 5)).to eq(error: 'not_enough_resources')
|
13
|
+
expect_proxmox_actions_to_be []
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
@@ -25,6 +26,23 @@ describe HybridPlatformsConductor::HpcPlugins::Provisioner::Proxmox do
|
|
25
26
|
vm_id: 1000,
|
26
27
|
vm_ip: '192.168.0.100'
|
27
28
|
)
|
29
|
+
expect_proxmox_actions_to_be [
|
30
|
+
[
|
31
|
+
:post,
|
32
|
+
'nodes/pve_node_name/lxc',
|
33
|
+
{
|
34
|
+
'ostemplate' => 'test_template.iso',
|
35
|
+
'hostname' => 'test.hostname.my-domain.com',
|
36
|
+
'description' => /node: test_node\nenvironment: test_env/,
|
37
|
+
'cores' => 2,
|
38
|
+
'cpulimit' => 2,
|
39
|
+
'memory' => 1024,
|
40
|
+
'rootfs' => 'local-lvm:4',
|
41
|
+
'net0' => 'name=eth0,bridge=vmbr0,gw=172.16.16.16,ip=192.168.0.100/32',
|
42
|
+
'vmid' => 1000
|
43
|
+
}
|
44
|
+
]
|
45
|
+
]
|
28
46
|
end
|
29
47
|
end
|
30
48
|
|
@@ -34,6 +52,12 @@ describe HybridPlatformsConductor::HpcPlugins::Provisioner::Proxmox do
|
|
34
52
|
result = call_reserve_proxmox_container(2, 1024, 4, config: { api_max_retries: 4 })
|
35
53
|
expect(result[:error]).not_to eq nil
|
36
54
|
expect(result[:error]).to match /Unhandled exception from reserve_proxmox_container: Proxmox API get nodes\/pve_node_name\/lxc returns NOK: error code = 500 continuously \(tried 5 times\)/
|
55
|
+
expect_proxmox_actions_to_be [
|
56
|
+
[:create_ticket],
|
57
|
+
[:create_ticket],
|
58
|
+
[:create_ticket],
|
59
|
+
[:create_ticket]
|
60
|
+
]
|
37
61
|
end
|
38
62
|
end
|
39
63
|
|
@@ -45,6 +69,26 @@ describe HybridPlatformsConductor::HpcPlugins::Provisioner::Proxmox do
|
|
45
69
|
vm_id: 1000,
|
46
70
|
vm_ip: '192.168.0.100'
|
47
71
|
)
|
72
|
+
expect_proxmox_actions_to_be [
|
73
|
+
[:create_ticket],
|
74
|
+
[:create_ticket],
|
75
|
+
[:create_ticket],
|
76
|
+
[
|
77
|
+
:post,
|
78
|
+
'nodes/pve_node_name/lxc',
|
79
|
+
{
|
80
|
+
'ostemplate' => 'test_template.iso',
|
81
|
+
'hostname' => 'test.hostname.my-domain.com',
|
82
|
+
'description' => /node: test_node\nenvironment: test_env/,
|
83
|
+
'cores' => 2,
|
84
|
+
'cpulimit' => 2,
|
85
|
+
'memory' => 1024,
|
86
|
+
'rootfs' => 'local-lvm:4',
|
87
|
+
'net0' => 'name=eth0,bridge=vmbr0,gw=172.16.16.16,ip=192.168.0.100/32',
|
88
|
+
'vmid' => 1000
|
89
|
+
}
|
90
|
+
]
|
91
|
+
]
|
48
92
|
end
|
49
93
|
end
|
50
94
|
|
@@ -60,6 +60,98 @@ describe HybridPlatformsConductor::HpcPlugins::Provisioner::Proxmox do
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
+
it 'makes sure to remove cgroup files that are leftovers of removed containers' do
|
64
|
+
with_sync_node(leftovers: [
|
65
|
+
'/sys/fs/cgroup/memory/lxc/1003'
|
66
|
+
]) do
|
67
|
+
mock_proxmox(mocked_pve_nodes: {
|
68
|
+
'pve_node_name' => {
|
69
|
+
lxc_containers: {
|
70
|
+
1000 => { ip: '192.168.1.100' },
|
71
|
+
1001 => { ip: '192.168.1.101' }
|
72
|
+
}
|
73
|
+
}
|
74
|
+
})
|
75
|
+
expect(call_reserve_proxmox_container(2, 1024, 1, config: { vm_ids_range: [1000, 1100] })).to eq(
|
76
|
+
pve_node: 'pve_node_name',
|
77
|
+
vm_id: 1002,
|
78
|
+
vm_ip: '192.168.0.100'
|
79
|
+
)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'makes sure to remove cgroup files that are leftovers of removed containers even when they are reusing the VM ID' do
|
84
|
+
with_sync_node(leftovers: [
|
85
|
+
'/sys/fs/cgroup/memory/lxc/1002'
|
86
|
+
]) do
|
87
|
+
mock_proxmox(mocked_pve_nodes: {
|
88
|
+
'pve_node_name' => {
|
89
|
+
lxc_containers: {
|
90
|
+
1000 => { ip: '192.168.1.100' },
|
91
|
+
1001 => { ip: '192.168.1.101' }
|
92
|
+
}
|
93
|
+
}
|
94
|
+
})
|
95
|
+
expect(call_reserve_proxmox_container(2, 1024, 1, config: { vm_ids_range: [1000, 1100] })).to eq(
|
96
|
+
pve_node: 'pve_node_name',
|
97
|
+
vm_id: 1002,
|
98
|
+
vm_ip: '192.168.0.100'
|
99
|
+
)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'makes sure to remove cgroup files that are leftovers of removed containers when several cgroups contain files' do
|
104
|
+
with_sync_node(leftovers: [
|
105
|
+
'/sys/fs/cgroup/memory/lxc/1003',
|
106
|
+
'/sys/fs/cgroup/network/lxc/1003',
|
107
|
+
'/sys/fs/cgroup/cpu/lxc/1003'
|
108
|
+
]) do
|
109
|
+
mock_proxmox(mocked_pve_nodes: {
|
110
|
+
'pve_node_name' => {
|
111
|
+
lxc_containers: {
|
112
|
+
1000 => { ip: '192.168.1.100' },
|
113
|
+
1001 => { ip: '192.168.1.101' }
|
114
|
+
}
|
115
|
+
}
|
116
|
+
})
|
117
|
+
expect(call_reserve_proxmox_container(2, 1024, 1, config: { vm_ids_range: [1000, 1100] })).to eq(
|
118
|
+
pve_node: 'pve_node_name',
|
119
|
+
vm_id: 1002,
|
120
|
+
vm_ip: '192.168.0.100'
|
121
|
+
)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'makes sure to remove only cgroup files that are leftovers of removed containers inside our VM ID range' do
|
126
|
+
with_sync_node(
|
127
|
+
leftovers: [
|
128
|
+
'/sys/fs/cgroup/memory/lxc/100',
|
129
|
+
'/sys/fs/cgroup/memory/lxc/1001',
|
130
|
+
'/sys/fs/cgroup/memory/lxc/1002',
|
131
|
+
'/sys/fs/cgroup/memory/lxc/1003'
|
132
|
+
],
|
133
|
+
expect_remaining_leftovers: [
|
134
|
+
'/sys/fs/cgroup/memory/lxc/100',
|
135
|
+
'/sys/fs/cgroup/memory/lxc/1001'
|
136
|
+
]
|
137
|
+
) do
|
138
|
+
mock_proxmox(mocked_pve_nodes: {
|
139
|
+
'pve_node_name' => {
|
140
|
+
lxc_containers: {
|
141
|
+
100 => { ip: '192.168.1.10' },
|
142
|
+
1000 => { ip: '192.168.1.100' },
|
143
|
+
1001 => { ip: '192.168.1.101' }
|
144
|
+
}
|
145
|
+
}
|
146
|
+
})
|
147
|
+
expect(call_reserve_proxmox_container(2, 1024, 1, config: { vm_ids_range: [1000, 1100] })).to eq(
|
148
|
+
pve_node: 'pve_node_name',
|
149
|
+
vm_id: 1002,
|
150
|
+
vm_ip: '192.168.0.100'
|
151
|
+
)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
63
155
|
end
|
64
156
|
|
65
157
|
end
|
@@ -23,20 +23,6 @@ describe HybridPlatformsConductor::HpcPlugins::Provisioner::Proxmox do
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
it '' do
|
28
|
-
with_test_proxmox_platform do |instance|
|
29
|
-
mock_proxmox_calls_with [
|
30
|
-
# 1 - The info on existing containers
|
31
|
-
mock_proxmox_to_get_nodes_info,
|
32
|
-
# 2 - The start of the container - fail a few times
|
33
|
-
mock_proxmox_to_start_node(nbr_api_errors: 2)
|
34
|
-
]
|
35
|
-
instance.create
|
36
|
-
instance.start
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
26
|
it 'retries calls to the API when getting back errors 5xx' do
|
41
27
|
with_test_proxmox_platform do |instance|
|
42
28
|
mock_proxmox_calls_with [
|
@@ -156,6 +156,7 @@ module HybridPlatformsConductorTest
|
|
156
156
|
idx_try += 1
|
157
157
|
idx_try <= nbr_api_errors ? 'NOK: error code = 500' : task_name
|
158
158
|
end
|
159
|
+
expect(proxmox).to receive(:reauthenticate).exactly(nbr_api_errors - (task_status.nil? ? 1 : 0)).times
|
159
160
|
# Mock checking task status
|
160
161
|
unless task_status.nil?
|
161
162
|
# Mock checking task status
|
@@ -294,6 +295,7 @@ module HybridPlatformsConductorTest
|
|
294
295
|
]
|
295
296
|
end
|
296
297
|
end
|
298
|
+
expect(proxmox).to receive(:reauthenticate).exactly(nbr_api_errors - (status.nil? ? 1 : 0)).times
|
297
299
|
unless status.nil?
|
298
300
|
expect(proxmox).to receive(:get).with('nodes/pve_node_name/lxc/1024/status/current') do
|
299
301
|
{
|
@@ -641,6 +643,10 @@ module HybridPlatformsConductorTest
|
|
641
643
|
raise "Unknown Proxmox API post call: #{path}. Please adapt the test framework."
|
642
644
|
end
|
643
645
|
end
|
646
|
+
# Mock create_ticket
|
647
|
+
allow(proxmox).to receive(:create_ticket) do
|
648
|
+
@proxmox_actions << [:create_ticket]
|
649
|
+
end
|
644
650
|
proxmox
|
645
651
|
end
|
646
652
|
end,
|
@@ -651,11 +657,36 @@ module HybridPlatformsConductorTest
|
|
651
657
|
# Prepare a repository to test reserve_proxmox_container
|
652
658
|
#
|
653
659
|
# Parameters::
|
660
|
+
# * *leftovers* (Array<String>): List of leftover files among cgroups [default: []]
|
661
|
+
# * *expect_remaining_leftovers* (Array<String>): List of leftover files among cgroups that should remain after run [default: []]
|
654
662
|
# * Proc: Code to be called with repository setup
|
655
|
-
def with_sync_node
|
663
|
+
def with_sync_node(leftovers: [], expect_remaining_leftovers: [])
|
656
664
|
with_repository('sync_node') do |repository|
|
665
|
+
# Mock the cgroup file system of the sync node
|
666
|
+
remaining_leftovers = leftovers.clone
|
667
|
+
allow(Dir).to receive(:glob).and_wrap_original do |original_glob, dir, &block|
|
668
|
+
case dir
|
669
|
+
when '/sys/fs/cgroup/*/lxc/*'
|
670
|
+
block.nil? ? remaining_leftovers : remaining_leftovers.each(&block)
|
671
|
+
when /^\/sys\/fs\/cgroup\/\*\/lxc\/(.+)$/
|
672
|
+
vm_id_str = $1
|
673
|
+
file_pattern = /^\/sys\/fs\/cgroup\/.+\/lxc\/#{Regexp.escape(vm_id_str)}$/
|
674
|
+
matched_files = remaining_leftovers.select { |file| file =~ file_pattern }
|
675
|
+
block.nil? ? matched_files : matched_files.each(&block)
|
676
|
+
else
|
677
|
+
original_glob.call(dir, &block)
|
678
|
+
end
|
679
|
+
end
|
680
|
+
allow(FileUtils).to receive(:rm_rf).and_wrap_original do |original_rm_rf, path|
|
681
|
+
if path.start_with?('/sys/fs/cgroup')
|
682
|
+
remaining_leftovers.delete_if { |file| file.start_with?(path) }
|
683
|
+
else
|
684
|
+
original_rm_rf.call(path)
|
685
|
+
end
|
686
|
+
end
|
657
687
|
@repository = repository
|
658
688
|
yield
|
689
|
+
expect(remaining_leftovers.sort).to eq expect_remaining_leftovers.sort
|
659
690
|
end
|
660
691
|
end
|
661
692
|
|
@@ -808,7 +839,13 @@ module HybridPlatformsConductorTest
|
|
808
839
|
# Parameters::
|
809
840
|
# * *expected_proxmox_actions* (Array<Array>): Expected Proxmox actions
|
810
841
|
def expect_proxmox_actions_to_be(expected_proxmox_actions)
|
811
|
-
expect(@proxmox_actions.size).to eq
|
842
|
+
expect(@proxmox_actions.size).to eq(expected_proxmox_actions.size), <<~EOS
|
843
|
+
Expected #{expected_proxmox_actions.size} Proxmox actions, but got #{@proxmox_actions.size} instead:
|
844
|
+
----- Received:
|
845
|
+
#{@proxmox_actions.map(&:inspect).join("\n")}
|
846
|
+
----- Expected:
|
847
|
+
#{expected_proxmox_actions.map(&:inspect).join("\n")}
|
848
|
+
EOS
|
812
849
|
@proxmox_actions.zip(expected_proxmox_actions).each do |proxmox_action, expected_proxmox_action|
|
813
850
|
expect(proxmox_action.size).to eq expected_proxmox_action.size
|
814
851
|
expect(proxmox_action[0..1]).to eq expected_proxmox_action[0..1]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hybrid_platforms_conductor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 32.
|
4
|
+
version: 32.11.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Muriel Salvan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: range_operators
|
@@ -281,20 +281,20 @@ description: Provides a complete toolset to help DevOps maintain, deploy, monito
|
|
281
281
|
email:
|
282
282
|
- muriel@x-aeon.com
|
283
283
|
executables:
|
284
|
-
- topograph
|
285
|
-
- test
|
286
|
-
- free_veids
|
287
|
-
- free_ips
|
288
|
-
- nodes_to_deploy
|
289
|
-
- last_deploys
|
290
|
-
- check-node
|
291
284
|
- run
|
292
|
-
- report
|
293
285
|
- get_impacted_nodes
|
294
|
-
-
|
286
|
+
- dump_nodes_json
|
287
|
+
- check-node
|
288
|
+
- nodes_to_deploy
|
289
|
+
- free_veids
|
290
|
+
- free_ips
|
291
|
+
- test
|
295
292
|
- deploy
|
293
|
+
- report
|
294
|
+
- topograph
|
296
295
|
- setup
|
297
|
-
-
|
296
|
+
- last_deploys
|
297
|
+
- ssh_config
|
298
298
|
extensions: []
|
299
299
|
extra_rdoc_files: []
|
300
300
|
files:
|