hybrid_platforms_conductor 32.3.6
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 +7 -0
- data/bin/check-node +24 -0
- data/bin/deploy +12 -0
- data/bin/dump_nodes_json +12 -0
- data/bin/free_ips +23 -0
- data/bin/free_veids +17 -0
- data/bin/get_impacted_nodes +43 -0
- data/bin/last_deploys +56 -0
- data/bin/nodes_to_deploy +104 -0
- data/bin/report +10 -0
- data/bin/run +39 -0
- data/bin/setup +11 -0
- data/bin/ssh_config +14 -0
- data/bin/test +13 -0
- data/bin/topograph +54 -0
- data/lib/hybrid_platforms_conductor/action.rb +82 -0
- data/lib/hybrid_platforms_conductor/actions_executor.rb +307 -0
- data/lib/hybrid_platforms_conductor/bitbucket.rb +123 -0
- data/lib/hybrid_platforms_conductor/cmd_runner.rb +188 -0
- data/lib/hybrid_platforms_conductor/cmdb.rb +34 -0
- data/lib/hybrid_platforms_conductor/common_config_dsl/bitbucket.rb +78 -0
- data/lib/hybrid_platforms_conductor/common_config_dsl/confluence.rb +43 -0
- data/lib/hybrid_platforms_conductor/common_config_dsl/file_system_tests.rb +110 -0
- data/lib/hybrid_platforms_conductor/common_config_dsl/idempotence_tests.rb +38 -0
- data/lib/hybrid_platforms_conductor/config.rb +263 -0
- data/lib/hybrid_platforms_conductor/confluence.rb +119 -0
- data/lib/hybrid_platforms_conductor/connector.rb +84 -0
- data/lib/hybrid_platforms_conductor/credentials.rb +127 -0
- data/lib/hybrid_platforms_conductor/current_dir_monitor.rb +42 -0
- data/lib/hybrid_platforms_conductor/deployer.rb +598 -0
- data/lib/hybrid_platforms_conductor/executable.rb +145 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/bash.rb +44 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/interactive.rb +44 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/my_action.rb.sample +79 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/remote_bash.rb +63 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/ruby.rb +69 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/scp.rb +61 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/config.rb +78 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/host_ip.rb +104 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/host_keys.rb +114 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/my_cmdb.rb.sample +129 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/platform_handlers.rb +66 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/my_connector.rb.sample +156 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +702 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/platform_handler_plugin.rb.sample +292 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/docker.rb +148 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/my_provisioner.rb.sample +103 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/podman.rb +125 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox.rb +522 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox/proxmox_waiter.rb +707 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox/reserve_proxmox_container +122 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/confluence.rb +69 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/mediawiki.rb +164 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/my_report_plugin.rb.sample +88 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/stdout.rb +61 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/templates/confluence_inventory.html.erb +33 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/bitbucket_conf.rb +137 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/can_be_checked.rb +21 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/check_deploy_and_idempotence.rb +112 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/check_from_scratch.rb +35 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/connection.rb +28 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_freshness.rb +44 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_from_scratch.rb +36 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_removes_root_access.rb +49 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/divergence.rb +25 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/executables.rb +46 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/file_system.rb +45 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/file_system_hdfs.rb +45 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/hostname.rb +25 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/idempotence.rb +77 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/ip.rb +38 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_conf.rb +56 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_masters_ok.rb +54 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/linear_strategy.rb +47 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/local_users.rb +82 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/mounts.rb +120 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/my_test_plugin.rb.sample +143 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/orphan_files.rb +74 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/ports.rb +85 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/private_ips.rb +38 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/public_ips.rb +38 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre-meltdown-checker.sh +1930 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre.rb +56 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/veids.rb +31 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/vulnerabilities.rb +159 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/confluence.rb +122 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/my_test_report.rb.sample +48 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/stdout.rb +120 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/templates/_confluence_errors_status.html.erb +46 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/templates/_confluence_gauge.html.erb +49 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/templates/confluence.html.erb +242 -0
- data/lib/hybrid_platforms_conductor/io_router.rb +70 -0
- data/lib/hybrid_platforms_conductor/json_dumper.rb +88 -0
- data/lib/hybrid_platforms_conductor/logger_helpers.rb +319 -0
- data/lib/hybrid_platforms_conductor/mutex_dir +76 -0
- data/lib/hybrid_platforms_conductor/nodes_handler.rb +597 -0
- data/lib/hybrid_platforms_conductor/parallel_threads.rb +97 -0
- data/lib/hybrid_platforms_conductor/platform_handler.rb +188 -0
- data/lib/hybrid_platforms_conductor/platforms_handler.rb +118 -0
- data/lib/hybrid_platforms_conductor/plugin.rb +53 -0
- data/lib/hybrid_platforms_conductor/plugins.rb +101 -0
- data/lib/hybrid_platforms_conductor/provisioner.rb +181 -0
- data/lib/hybrid_platforms_conductor/report.rb +31 -0
- data/lib/hybrid_platforms_conductor/reports_handler.rb +84 -0
- data/lib/hybrid_platforms_conductor/services_handler.rb +274 -0
- data/lib/hybrid_platforms_conductor/test.rb +141 -0
- data/lib/hybrid_platforms_conductor/test_by_service.rb +22 -0
- data/lib/hybrid_platforms_conductor/test_report.rb +282 -0
- data/lib/hybrid_platforms_conductor/tests_runner.rb +590 -0
- data/lib/hybrid_platforms_conductor/thycotic.rb +92 -0
- data/lib/hybrid_platforms_conductor/topographer.rb +859 -0
- data/lib/hybrid_platforms_conductor/topographer/plugin.rb +20 -0
- data/lib/hybrid_platforms_conductor/topographer/plugins/graphviz.rb +127 -0
- data/lib/hybrid_platforms_conductor/topographer/plugins/json.rb +72 -0
- data/lib/hybrid_platforms_conductor/topographer/plugins/my_topographer_output_plugin.rb.sample +37 -0
- data/lib/hybrid_platforms_conductor/topographer/plugins/svg.rb +30 -0
- data/lib/hybrid_platforms_conductor/version.rb +5 -0
- data/spec/hybrid_platforms_conductor_test.rb +159 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/bash_spec.rb +43 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/interactive_spec.rb +18 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/remote_bash_spec.rb +102 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/ruby_spec.rb +108 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/scp_spec.rb +79 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions_spec.rb +199 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connection_spec.rb +212 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/cli_options_spec.rb +125 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/config_dsl_spec.rb +50 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connectable_nodes_spec.rb +28 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connections_spec.rb +448 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/global_helpers_spec.rb +313 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/node_helpers_spec.rb +32 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/remote_actions_spec.rb +134 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/logging_spec.rb +256 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/parallel_spec.rb +338 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/timeout_spec.rb +101 -0
- data/spec/hybrid_platforms_conductor_test/api/cmd_runner_spec.rb +165 -0
- data/spec/hybrid_platforms_conductor_test/api/config_spec.rb +238 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/check_spec.rb +9 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/deploy_spec.rb +243 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/parse_deploy_output_spec.rb +104 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioner_spec.rb +131 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/docker/Dockerfile +10 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/docker_spec.rb +123 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/podman_spec.rb +211 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/config_dsl_spec.rb +126 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/create_spec.rb +290 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/destroy_spec.rb +43 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/ip_spec.rb +60 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/proxmox.json +3 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/destroy_vm_spec.rb +82 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/expired_containers_spec.rb +786 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/ips_assignment_spec.rb +112 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/other_lxc_containers_resources_spec.rb +190 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/pve_node_resources_spec.rb +200 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/retries_spec.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/vm_ids_assignment_spec.rb +67 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/start_spec.rb +79 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/state_spec.rb +28 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/stop_spec.rb +41 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/config_spec.rb +33 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/host_ip_spec.rb +64 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/host_keys_spec.rb +133 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/platform_handlers_spec.rb +19 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs_plugins_api_spec.rb +446 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/common_spec.rb +127 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/git_diff_impacts_spec.rb +318 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/nodes_selectors_spec.rb +132 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/platform_handlers_plugins_api_spec.rb +60 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/several_platforms_spec.rb +58 -0
- data/spec/hybrid_platforms_conductor_test/api/platform_handler_spec.rb +97 -0
- data/spec/hybrid_platforms_conductor_test/api/platforms_handler_spec.rb +104 -0
- data/spec/hybrid_platforms_conductor_test/api/plugins_spec.rb +243 -0
- data/spec/hybrid_platforms_conductor_test/api/reports_handler_spec.rb +44 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/actions_to_deploy_spec.rb +121 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/deploy_allowed_spec.rb +142 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/log_info_spec.rb +101 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/package_spec.rb +388 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/parse_deploy_output_spec.rb +274 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/prepare_for_deploy_spec.rb +264 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/common_spec.rb +194 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/global_spec.rb +37 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/node_check_spec.rb +194 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/node_spec.rb +137 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/node_ssh_spec.rb +257 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/platform_spec.rb +110 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/reports_spec.rb +367 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_plugins/bitbucket_conf_spec.rb +111 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_reports_plugins/confluence_spec.rb +29 -0
- data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb.rb +166 -0
- data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb2.rb +93 -0
- data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb_others.rb +60 -0
- data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb_others2.rb +58 -0
- data/spec/hybrid_platforms_conductor_test/executables/check-node_spec.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/executables/deploy_spec.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/executables/get_impacted_nodes_spec.rb +158 -0
- data/spec/hybrid_platforms_conductor_test/executables/last_deploys_spec.rb +173 -0
- data/spec/hybrid_platforms_conductor_test/executables/nodes_to_deploy_spec.rb +283 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/actions_executor_spec.rb +28 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/cmd_runner_spec.rb +28 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/common_spec.rb +67 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/deployer_spec.rb +251 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/nodes_handler_spec.rb +111 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/nodes_selectors_spec.rb +71 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/reports_handler_spec.rb +54 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/tests_runner_spec.rb +139 -0
- data/spec/hybrid_platforms_conductor_test/executables/report_spec.rb +60 -0
- data/spec/hybrid_platforms_conductor_test/executables/run_spec.rb +173 -0
- data/spec/hybrid_platforms_conductor_test/executables/ssh_config_spec.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/executables/test_spec.rb +41 -0
- data/spec/hybrid_platforms_conductor_test/helpers/actions_executor_helpers.rb +98 -0
- data/spec/hybrid_platforms_conductor_test/helpers/cmd_runner_helpers.rb +92 -0
- data/spec/hybrid_platforms_conductor_test/helpers/cmdb_helpers.rb +37 -0
- data/spec/hybrid_platforms_conductor_test/helpers/config_helpers.rb +20 -0
- data/spec/hybrid_platforms_conductor_test/helpers/connector_ssh_helpers.rb +130 -0
- data/spec/hybrid_platforms_conductor_test/helpers/deployer_helpers.rb +149 -0
- data/spec/hybrid_platforms_conductor_test/helpers/deployer_test_helpers.rb +812 -0
- data/spec/hybrid_platforms_conductor_test/helpers/executables_helpers.rb +96 -0
- data/spec/hybrid_platforms_conductor_test/helpers/nodes_handler_helpers.rb +20 -0
- data/spec/hybrid_platforms_conductor_test/helpers/platform_handler_helpers.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/helpers/platforms_handler_helpers.rb +127 -0
- data/spec/hybrid_platforms_conductor_test/helpers/plugins_helpers.rb +48 -0
- data/spec/hybrid_platforms_conductor_test/helpers/provisioner_proxmox_helpers.rb +789 -0
- data/spec/hybrid_platforms_conductor_test/helpers/reports_handler_helpers.rb +29 -0
- data/spec/hybrid_platforms_conductor_test/helpers/services_handler_helpers.rb +20 -0
- data/spec/hybrid_platforms_conductor_test/helpers/tests_runner_helpers.rb +38 -0
- data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem/hpc_plugins/test_plugin_type/test_plugin_id1.rb +22 -0
- data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem/hpc_plugins/test_plugin_type/test_plugin_id2.rb +22 -0
- data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem2/sub_dir/hpc_plugins/test_plugin_type/test_plugin_id3.rb +26 -0
- data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem2/sub_dir/hpc_plugins/test_plugin_type2/test_plugin_id4.rb +26 -0
- data/spec/hybrid_platforms_conductor_test/platform_handler_plugins/test.rb +225 -0
- data/spec/hybrid_platforms_conductor_test/platform_handler_plugins/test2.rb +11 -0
- data/spec/hybrid_platforms_conductor_test/report_plugin.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/test_action.rb +66 -0
- data/spec/hybrid_platforms_conductor_test/test_connector.rb +151 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/global.rb +30 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/node.rb +53 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/node_check.rb +47 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/node_ssh.rb +42 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/platform.rb +50 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/several_checks.rb +50 -0
- data/spec/hybrid_platforms_conductor_test/test_provisioner.rb +95 -0
- data/spec/hybrid_platforms_conductor_test/tests_report_plugin.rb +49 -0
- data/spec/spec_helper.rb +111 -0
- metadata +566 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'hybrid_platforms_conductor/provisioner'
|
|
3
|
+
|
|
4
|
+
module HybridPlatformsConductor
|
|
5
|
+
|
|
6
|
+
module HpcPlugins
|
|
7
|
+
|
|
8
|
+
module Provisioner
|
|
9
|
+
|
|
10
|
+
# Provision Podman containers
|
|
11
|
+
class Podman < HybridPlatformsConductor::Provisioner
|
|
12
|
+
|
|
13
|
+
# Create an instance.
|
|
14
|
+
# Reuse an existing one if it already exists.
|
|
15
|
+
# [API] - This method is mandatory
|
|
16
|
+
def create
|
|
17
|
+
# Get the image name for this node
|
|
18
|
+
image = @nodes_handler.get_image_of(@node).to_sym
|
|
19
|
+
# Find if we have such an image registered
|
|
20
|
+
if @config.known_os_images.include?(image)
|
|
21
|
+
# Build the image if it does not exist
|
|
22
|
+
image_tag = "hpc_image_#{image}"
|
|
23
|
+
image_futex_file = "#{Dir.tmpdir}/hpc_podman_image_futexes/#{image_tag}"
|
|
24
|
+
FileUtils.mkdir_p File.dirname(image_futex_file)
|
|
25
|
+
Futex.new(image_futex_file).open do
|
|
26
|
+
@cmd_runner.run_cmd "cd #{@config.os_image_dir(image)} && #{podman_cmd} build --tag #{image_tag} --security-opt seccomp=/usr/share/containers/seccomp.json --cgroup-manager=cgroupfs ."
|
|
27
|
+
end
|
|
28
|
+
container_name = "hpc_container_#{@node}_#{@environment}"
|
|
29
|
+
container_futex_file = "#{Dir.tmpdir}/hpc_podman_container_futexes/#{image_tag}"
|
|
30
|
+
FileUtils.mkdir_p File.dirname(container_futex_file)
|
|
31
|
+
Futex.new(container_futex_file).open do
|
|
32
|
+
_exit_status, stdout, _stderr = @cmd_runner.run_cmd "#{podman_cmd} container list --all | grep #{container_name}", expected_code: [0, 1]
|
|
33
|
+
existing_container = !stdout.strip.empty?
|
|
34
|
+
@cmd_runner.run_cmd "#{podman_cmd} container create --name #{container_name} #{image_tag}" unless existing_container
|
|
35
|
+
@container = container_name
|
|
36
|
+
end
|
|
37
|
+
else
|
|
38
|
+
raise "[ #{@node}/#{@environment} ] - Unknown OS image #{image} defined for node #{@node}"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Start an instance
|
|
43
|
+
# Prerequisite: create has been called before
|
|
44
|
+
# [API] - This method is mandatory
|
|
45
|
+
def start
|
|
46
|
+
log_debug "[ #{@node}/#{@environment} ] - Start Podman Container #{@container} ..."
|
|
47
|
+
@cmd_runner.run_cmd "#{podman_cmd} container start --cgroup-manager=cgroupfs #{@container}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Stop an instance
|
|
51
|
+
# Prerequisite: create has been called before
|
|
52
|
+
# [API] - This method is mandatory
|
|
53
|
+
def stop
|
|
54
|
+
log_debug "[ #{@node}/#{@environment} ] - Stop Podman Container #{@container} ..."
|
|
55
|
+
@cmd_runner.run_cmd "#{podman_cmd} container stop #{@container}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Destroy an instance
|
|
59
|
+
# Prerequisite: create has been called before
|
|
60
|
+
# [API] - This method is mandatory
|
|
61
|
+
def destroy
|
|
62
|
+
log_debug "[ #{@node}/#{@environment} ] - Destroy Podman Container #{@container} ..."
|
|
63
|
+
@cmd_runner.run_cmd "#{podman_cmd} container rm #{@container}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Returns the state of an instance
|
|
67
|
+
# [API] - This method is mandatory
|
|
68
|
+
#
|
|
69
|
+
# Result::
|
|
70
|
+
# * Symbol: The state the instance is in. Possible values are:
|
|
71
|
+
# * *:missing*: The instance does not exist
|
|
72
|
+
# * *:created*: The instance has been created but is not running
|
|
73
|
+
# * *:running*: The instance is running
|
|
74
|
+
# * *:exited*: The instance has run and is now stopped
|
|
75
|
+
# * *:error*: The instance is in error
|
|
76
|
+
def state
|
|
77
|
+
if !defined?(@container) || @container.nil?
|
|
78
|
+
:missing
|
|
79
|
+
else
|
|
80
|
+
begin
|
|
81
|
+
_exit_status, stdout, _stderr = @cmd_runner.run_cmd "#{podman_cmd} container inspect #{@container}"
|
|
82
|
+
status = JSON.parse(stdout).first['State']['Status'].to_sym
|
|
83
|
+
status = :created if status == :configured
|
|
84
|
+
status
|
|
85
|
+
rescue
|
|
86
|
+
log_warn "Error while reading state of Podman container #{@container}: #{$!}"
|
|
87
|
+
:error
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Return the IP address of an instance.
|
|
93
|
+
# Prerequisite: create has been called before.
|
|
94
|
+
# [API] - This method is optional
|
|
95
|
+
#
|
|
96
|
+
# Result::
|
|
97
|
+
# * String or nil: The instance IP address, or nil if this information is not relevant
|
|
98
|
+
def ip
|
|
99
|
+
# Get its IP that could have changed upon restart
|
|
100
|
+
# cf https://github.com/moby/moby/issues/2801
|
|
101
|
+
# Make sure we refresh its info before querying it, as we could hit a cache of a previous IP.
|
|
102
|
+
_exit_status, stdout, _stderr = @cmd_runner.run_cmd "#{podman_cmd} container inspect #{@container} | grep IPAddress"
|
|
103
|
+
stdout.strip.match(/\d+\.\d+\.\d+\.\d+/)[0]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
# Get the Podman command.
|
|
109
|
+
# Handle sudo rights if needed.
|
|
110
|
+
# Keep a cache of it for performance.
|
|
111
|
+
#
|
|
112
|
+
# Result::
|
|
113
|
+
# * String: The Podman command
|
|
114
|
+
def podman_cmd
|
|
115
|
+
@podman_cmd = @cmd_runner.root? ? 'podman' : 'sudo podman' unless defined?(@podman_cmd)
|
|
116
|
+
@podman_cmd
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
end
|
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'proxmox'
|
|
3
|
+
require 'digest'
|
|
4
|
+
require 'hybrid_platforms_conductor/actions_executor'
|
|
5
|
+
require 'hybrid_platforms_conductor/provisioner'
|
|
6
|
+
|
|
7
|
+
module HybridPlatformsConductor
|
|
8
|
+
|
|
9
|
+
module HpcPlugins
|
|
10
|
+
|
|
11
|
+
module Provisioner
|
|
12
|
+
|
|
13
|
+
# Monkey patch some Proxmox methods
|
|
14
|
+
module ProxmoxPatches
|
|
15
|
+
|
|
16
|
+
include LoggerHelpers
|
|
17
|
+
|
|
18
|
+
attr_accessor *%i[logger logger_stderr]
|
|
19
|
+
|
|
20
|
+
def check_response(response)
|
|
21
|
+
log_debug "Response from Proxmox API: #{response}"
|
|
22
|
+
log_warn "Response from Proxmox API: #{response}" if response.code >= 400 && !log_debug?
|
|
23
|
+
super
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
::Proxmox::Proxmox.prepend ProxmoxPatches
|
|
28
|
+
|
|
29
|
+
# Decorate the DSL of platforms definitions
|
|
30
|
+
module PlatformsDSLProxmox
|
|
31
|
+
|
|
32
|
+
# Mixin initializer
|
|
33
|
+
def init_proxmox
|
|
34
|
+
# List of Proxmox servers info
|
|
35
|
+
# Array< Hash<Symbol,Object> >
|
|
36
|
+
@proxmox_servers = []
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Register a Proxmox server
|
|
40
|
+
#
|
|
41
|
+
# Parameters::
|
|
42
|
+
# * *proxmox_info* (Hash<Symbol,Object>): Proxmox server configuration. See Provisioner::Proxmox#proxmox_test_info to know about the returned structure.
|
|
43
|
+
def proxmox(proxmox_info)
|
|
44
|
+
@proxmox_servers << proxmox_info
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Return the list of Proxmox servers
|
|
48
|
+
#
|
|
49
|
+
# Result::
|
|
50
|
+
# * Array<Hash<Symbol,Object>>: The list of Proxmox servers. See Provisioner::Proxmox#proxmox_test_info to know about the returned structure.
|
|
51
|
+
def proxmox_servers
|
|
52
|
+
@proxmox_servers
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Provision Proxmox containers
|
|
58
|
+
class Proxmox < HybridPlatformsConductor::Provisioner
|
|
59
|
+
|
|
60
|
+
extend_config_dsl_with PlatformsDSLProxmox, :init_proxmox
|
|
61
|
+
|
|
62
|
+
class << self
|
|
63
|
+
attr_accessor :proxmox_waiter_files_mutex
|
|
64
|
+
end
|
|
65
|
+
@proxmox_waiter_files_mutex = Mutex.new
|
|
66
|
+
|
|
67
|
+
# Maximum size in chars of hostnames set in Proxmox
|
|
68
|
+
MAX_PROXMOX_HOSTNAME_SIZE = 64
|
|
69
|
+
|
|
70
|
+
# Create an instance.
|
|
71
|
+
# Reuse an existing one if it already exists.
|
|
72
|
+
# [API] - This method is mandatory
|
|
73
|
+
def create
|
|
74
|
+
# First check if we already have a test container that corresponds to this node and environment
|
|
75
|
+
@lxc_details = nil
|
|
76
|
+
with_proxmox do |proxmox|
|
|
77
|
+
proxmox.get('nodes').each do |node_info|
|
|
78
|
+
if proxmox_test_info[:test_config][:pve_nodes].include?(node_info['node']) && node_info['status'] == 'online'
|
|
79
|
+
proxmox.get("nodes/#{node_info['node']}/lxc").each do |lxc_info|
|
|
80
|
+
vm_id = Integer(lxc_info['vmid'])
|
|
81
|
+
if vm_id.between?(*proxmox_test_info[:test_config][:vm_ids_range])
|
|
82
|
+
# Check if the description contains our ID
|
|
83
|
+
lxc_config = proxmox.get("nodes/#{node_info['node']}/lxc/#{vm_id}/config")
|
|
84
|
+
vm_description_lines = (lxc_config['description'] || '').split("\n")
|
|
85
|
+
hpc_marker_idx = vm_description_lines.index('===== HPC info =====')
|
|
86
|
+
unless hpc_marker_idx.nil?
|
|
87
|
+
# Get the HPC info associated to this VM
|
|
88
|
+
# Hash<Symbol,String>
|
|
89
|
+
vm_hpc_info = Hash[vm_description_lines[hpc_marker_idx + 1..-1].map do |line|
|
|
90
|
+
property, value = line.split(': ')
|
|
91
|
+
[property.to_sym, value]
|
|
92
|
+
end]
|
|
93
|
+
if vm_hpc_info[:node] == @node && vm_hpc_info[:environment] == @environment
|
|
94
|
+
# Found it
|
|
95
|
+
# Get back the IP
|
|
96
|
+
ip_found = nil
|
|
97
|
+
lxc_config['net0'].split(',').each do |net_info|
|
|
98
|
+
property, value = net_info.split('=')
|
|
99
|
+
if property == 'ip'
|
|
100
|
+
ip_found = value.split('/').first
|
|
101
|
+
break
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
raise "[ #{@node}/#{@environment} ] - Unable to get IP back from LXC container nodes/#{node_info['node']}/lxc/#{vm_id}/config" if ip_found.nil?
|
|
105
|
+
@lxc_details = {
|
|
106
|
+
pve_node: node_info['node'],
|
|
107
|
+
vm_id: vm_id,
|
|
108
|
+
vm_ip: ip_found
|
|
109
|
+
}
|
|
110
|
+
break
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
break if @lxc_details
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
unless @lxc_details
|
|
120
|
+
# We couldn't find an existing LXC container for this node/environment.
|
|
121
|
+
# We have to create one.
|
|
122
|
+
# Get the image name for this node
|
|
123
|
+
image = @nodes_handler.get_image_of(@node).to_sym
|
|
124
|
+
# Find if we have such an image registered
|
|
125
|
+
if @config.known_os_images.include?(image)
|
|
126
|
+
proxmox_conf = "#{@config.os_image_dir(image)}/proxmox.json"
|
|
127
|
+
if File.exist?(proxmox_conf)
|
|
128
|
+
pve_template = JSON.parse(File.read(proxmox_conf)).dig 'template'
|
|
129
|
+
if pve_template
|
|
130
|
+
# Query the inventory to know about minimum resources needed to deploy the node.
|
|
131
|
+
# Provide default values if they are not part of the metadata.
|
|
132
|
+
min_resources_to_deploy = {
|
|
133
|
+
cpus: 2,
|
|
134
|
+
ram_mb: 1024,
|
|
135
|
+
disk_gb: 10
|
|
136
|
+
}.merge(@nodes_handler.get_deploy_resources_min_of(@node) || {})
|
|
137
|
+
# Create the Proxmox container from the sync node.
|
|
138
|
+
vm_config = proxmox_test_info[:vm_config]
|
|
139
|
+
# Hostname in Proxmox is capped at 65 chars.
|
|
140
|
+
# Make sure we don't get over it, but still use a unique one.
|
|
141
|
+
hostname = "#{@node}.#{@environment}.hpc-test.com"
|
|
142
|
+
if hostname.size > MAX_PROXMOX_HOSTNAME_SIZE
|
|
143
|
+
# Truncate it, but add a unique ID in it.
|
|
144
|
+
# In the end the hostname looks like:
|
|
145
|
+
# <truncated_node_environment>.<unique_id>.hpc-test.com
|
|
146
|
+
hostname = "-#{Digest::MD5.hexdigest(hostname)[0..7]}.hpc-test.com"
|
|
147
|
+
hostname = "#{@node}.#{@environment}"[0..MAX_PROXMOX_HOSTNAME_SIZE - hostname.size - 1] + hostname
|
|
148
|
+
end
|
|
149
|
+
@lxc_details = request_lxc_creation_for( {
|
|
150
|
+
ostemplate: pve_template,
|
|
151
|
+
hostname: hostname.gsub('_', '-'),
|
|
152
|
+
cores: min_resources_to_deploy[:cpus],
|
|
153
|
+
cpulimit: min_resources_to_deploy[:cpus],
|
|
154
|
+
memory: min_resources_to_deploy[:ram_mb],
|
|
155
|
+
rootfs: "local-lvm:#{min_resources_to_deploy[:disk_gb]}",
|
|
156
|
+
nameserver: vm_config[:vm_dns_servers].join(' '),
|
|
157
|
+
searchdomain: vm_config[:vm_search_domain],
|
|
158
|
+
net0: "name=eth0,bridge=vmbr0,gw=#{vm_config[:vm_gateway]}",
|
|
159
|
+
password: 'root_pwd',
|
|
160
|
+
description: <<~EOS
|
|
161
|
+
===== HPC info =====
|
|
162
|
+
node: #{@node}
|
|
163
|
+
environment: #{@environment}
|
|
164
|
+
debug: #{log_debug? ? 'true' : 'false'}
|
|
165
|
+
EOS
|
|
166
|
+
})
|
|
167
|
+
else
|
|
168
|
+
raise "[ #{@node}/#{@environment} ] - No template found in #{proxmox_conf}"
|
|
169
|
+
end
|
|
170
|
+
else
|
|
171
|
+
raise "[ #{@node}/#{@environment} ] - No Proxmox configuration found at #{proxmox_conf}"
|
|
172
|
+
end
|
|
173
|
+
else
|
|
174
|
+
raise "[ #{@node}/#{@environment} ] - Unknown OS image #{image} defined for node #{@node}"
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Start an instance
|
|
180
|
+
# Prerequisite: create has been called before
|
|
181
|
+
# [API] - This method is mandatory
|
|
182
|
+
def start
|
|
183
|
+
log_debug "[ #{@node}/#{@environment} ] - Start Proxmox LXC Container ..."
|
|
184
|
+
with_proxmox do |proxmox|
|
|
185
|
+
run_proxmox_task(proxmox, :post, @lxc_details[:pve_node], "lxc/#{@lxc_details[:vm_id]}/status/start")
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Stop an instance
|
|
190
|
+
# Prerequisite: create has been called before
|
|
191
|
+
# [API] - This method is mandatory
|
|
192
|
+
def stop
|
|
193
|
+
log_debug "[ #{@node}/#{@environment} ] - Stop Proxmox LXC Container ..."
|
|
194
|
+
with_proxmox do |proxmox|
|
|
195
|
+
run_proxmox_task(proxmox, :post, @lxc_details[:pve_node], "lxc/#{@lxc_details[:vm_id]}/status/stop")
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Destroy an instance
|
|
200
|
+
# Prerequisite: create has been called before
|
|
201
|
+
# [API] - This method is mandatory
|
|
202
|
+
def destroy
|
|
203
|
+
log_debug "[ #{@node}/#{@environment} ] - Delete Proxmox LXC Container ..."
|
|
204
|
+
release_lxc_container(@lxc_details[:vm_id])
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Return the state of an instance
|
|
208
|
+
# [API] - This method is mandatory
|
|
209
|
+
#
|
|
210
|
+
# Result::
|
|
211
|
+
# * Symbol: The state the instance is in. Possible values are:
|
|
212
|
+
# * *:missing*: The instance does not exist
|
|
213
|
+
# * *:created*: The instance has been created but is not running
|
|
214
|
+
# * *:running*: The instance is running
|
|
215
|
+
# * *:exited*: The instance has run and is now stopped
|
|
216
|
+
# * *:error*: The instance is in error
|
|
217
|
+
def state
|
|
218
|
+
if @lxc_details.nil?
|
|
219
|
+
:missing
|
|
220
|
+
else
|
|
221
|
+
status = nil
|
|
222
|
+
with_proxmox do |proxmox|
|
|
223
|
+
vm_id_str = @lxc_details[:vm_id].to_s
|
|
224
|
+
status =
|
|
225
|
+
if proxmox.get("nodes/#{@lxc_details[:pve_node]}/lxc").any? { |data_info| data_info['vmid'] == vm_id_str }
|
|
226
|
+
status_info = proxmox.get("nodes/#{@lxc_details[:pve_node]}/lxc/#{@lxc_details[:vm_id]}/status/current")
|
|
227
|
+
# Careful that it is possible that somebody destroyed the VM and so its status is missing
|
|
228
|
+
status = status_info.key?('status') ? status_info['status'].to_sym : :missing
|
|
229
|
+
status = :exited if status == :stopped
|
|
230
|
+
status
|
|
231
|
+
else
|
|
232
|
+
:missing
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
status
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Return the IP address of an instance.
|
|
240
|
+
# Prerequisite: create has been called before.
|
|
241
|
+
# [API] - This method is optional
|
|
242
|
+
#
|
|
243
|
+
# Result::
|
|
244
|
+
# * String or nil: The instance IP address, or nil if this information is not relevant
|
|
245
|
+
def ip
|
|
246
|
+
@lxc_details[:vm_ip]
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Return the default timeout to apply when waiting for an instance to be started/stopped...
|
|
250
|
+
# [API] - This method is optional
|
|
251
|
+
#
|
|
252
|
+
# Result::
|
|
253
|
+
# * Integer: The timeout in seconds
|
|
254
|
+
def default_timeout
|
|
255
|
+
proxmox_test_info[:default_timeout] || 3600
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
private
|
|
259
|
+
|
|
260
|
+
# Connect to the Proxmox API
|
|
261
|
+
#
|
|
262
|
+
# Parameters::
|
|
263
|
+
# * Proc: Client code to be called when connected
|
|
264
|
+
# * Parameters::
|
|
265
|
+
# * *proxmox* (Proxmox): The Proxmox instance
|
|
266
|
+
def with_proxmox
|
|
267
|
+
url = proxmox_test_info[:api_url]
|
|
268
|
+
raise 'No Proxmox server defined' if url.nil?
|
|
269
|
+
Credentials.with_credentials_for(:proxmox, @logger, @logger_stderr, url: url) do |user, password|
|
|
270
|
+
log_debug "[ #{@node}/#{@environment} ] - Connect to Proxmox #{url}"
|
|
271
|
+
proxmox_logs = StringIO.new
|
|
272
|
+
proxmox = ::Proxmox::Proxmox.new(
|
|
273
|
+
"#{url}/api2/json/",
|
|
274
|
+
# Proxmox uses the hostname as the node name so make the default API node derived from the URL.
|
|
275
|
+
# cf https://pve.proxmox.com/wiki/Renaming_a_PVE_node
|
|
276
|
+
URI.parse(url).host.downcase.split('.').first,
|
|
277
|
+
user,
|
|
278
|
+
password,
|
|
279
|
+
ENV['hpc_realm_for_proxmox'] || 'pam',
|
|
280
|
+
{
|
|
281
|
+
verify_ssl: false,
|
|
282
|
+
log: Logger.new(proxmox_logs)
|
|
283
|
+
}
|
|
284
|
+
)
|
|
285
|
+
proxmox.logger = @logger
|
|
286
|
+
proxmox.logger_stderr = @logger_stderr
|
|
287
|
+
begin
|
|
288
|
+
yield proxmox
|
|
289
|
+
ensure
|
|
290
|
+
log_debug "[ #{@node}/#{@environment} ] - Proxmox API logs:\n#{proxmox_logs.string}"
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# Maximum number of retries to perform on the Proxmox API.
|
|
296
|
+
NBR_RETRIES_MAX = 5
|
|
297
|
+
|
|
298
|
+
# Minimum seconds to wait between retries
|
|
299
|
+
RETRY_WAIT_TIME_SECS = 5
|
|
300
|
+
|
|
301
|
+
# Run a Proxmox task.
|
|
302
|
+
# Handle a retry mechanism in case of 5xx errors.
|
|
303
|
+
#
|
|
304
|
+
# Parameters::
|
|
305
|
+
# * *proxmox* (Proxmox): The Proxmox instance
|
|
306
|
+
# * *http_method* (Symbol): The HTTP method to call on the Proxmox instance
|
|
307
|
+
# * *pve_node* (String): Node on which the task is to be performed
|
|
308
|
+
# * *sub_path* (String): API sub-path to use (in the node API path)
|
|
309
|
+
# * *args* (Array): The list of additionnal arguments to give to the call
|
|
310
|
+
def run_proxmox_task(proxmox, http_method, pve_node, sub_path, *args)
|
|
311
|
+
task = nil
|
|
312
|
+
idx_try = 0
|
|
313
|
+
while task.nil? do
|
|
314
|
+
task = proxmox.send(http_method, "nodes/#{pve_node}/#{sub_path}", *args)
|
|
315
|
+
if task =~ /^NOK: error code = 5\d\d$/
|
|
316
|
+
log_warn "[ #{@node}/#{@environment} ] - Proxmox API call #{http_method} nodes/#{pve_node}/#{sub_path} #{args} returned error #{task} (attempt ##{idx_try}/#{NBR_RETRIES_MAX})"
|
|
317
|
+
task = nil
|
|
318
|
+
idx_try += 1
|
|
319
|
+
break if idx_try == NBR_RETRIES_MAX
|
|
320
|
+
sleep RETRY_WAIT_TIME_SECS + rand(5)
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
if task.nil?
|
|
324
|
+
raise "[ #{@node}/#{@environment} ] - Proxmox API call #{http_method} nodes/#{pve_node}/#{sub_path} #{args} is constantly failing. Giving up."
|
|
325
|
+
else
|
|
326
|
+
wait_for_proxmox_task(proxmox, pve_node, task)
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# Wait for a given Proxmox task completion
|
|
331
|
+
#
|
|
332
|
+
# Parameters::
|
|
333
|
+
# * *proxmox* (Proxmox): The Proxmox instance
|
|
334
|
+
# * *pve_node* (String): Node on which the task is to be performed
|
|
335
|
+
# * *task* (String): The task ID
|
|
336
|
+
def wait_for_proxmox_task(proxmox, pve_node, task)
|
|
337
|
+
raise "Invalid task: #{task}" if task[0..3] == 'NOK:'
|
|
338
|
+
status = nil
|
|
339
|
+
loop do
|
|
340
|
+
status = task_status(proxmox, pve_node, task)
|
|
341
|
+
break unless status == 'running'
|
|
342
|
+
log_debug "[ #{@node}/#{@environment} ] - Wait for Proxmox task #{task} to complete..."
|
|
343
|
+
sleep 1
|
|
344
|
+
end
|
|
345
|
+
if status.split(':').last == 'OK'
|
|
346
|
+
log_debug "[ #{@node}/#{@environment} ] - Proxmox task #{task} completed."
|
|
347
|
+
else
|
|
348
|
+
raise "[ #{@node}/#{@environment} ] - Proxmox task #{task} completed with status #{status}"
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
# Get task status
|
|
353
|
+
#
|
|
354
|
+
# Parameters::
|
|
355
|
+
# * *proxmox* (Proxmox): The Proxmox instance
|
|
356
|
+
# * *pve_node* (String): Node on which the task status is to be queried
|
|
357
|
+
# * *task* (String): Task ID to query
|
|
358
|
+
# Result::
|
|
359
|
+
# * String: The task status
|
|
360
|
+
def task_status(proxmox, pve_node, task)
|
|
361
|
+
status_info = proxmox.get("nodes/#{pve_node}/tasks/#{task}/status")
|
|
362
|
+
"#{status_info['status']}#{status_info['exitstatus'] ? ":#{status_info['exitstatus']}" : ''}"
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
# Execute a command on the sync node and get back its JSON result
|
|
366
|
+
#
|
|
367
|
+
# Parameters::
|
|
368
|
+
# * *cmd* (String): The command to execute
|
|
369
|
+
# * *extra_files* (Hash<String,String>): Extra files (source file, destination directory) to include on the sync node [default: {}]
|
|
370
|
+
# Result::
|
|
371
|
+
# * Hash<Symbol,Object>: The result
|
|
372
|
+
def run_cmd_on_sync_node(cmd, extra_files: {})
|
|
373
|
+
# Create the ProxmoxWaiter config in a file to be uploaded
|
|
374
|
+
config_file = "#{Dir.tmpdir}/config_#{file_id}.json"
|
|
375
|
+
File.write(
|
|
376
|
+
config_file,
|
|
377
|
+
(proxmox_test_info[:test_config].merge(
|
|
378
|
+
proxmox_api_url: proxmox_test_info[:api_url],
|
|
379
|
+
futex_file: '/tmp/hpc_proxmox_allocations.futex',
|
|
380
|
+
logs_dir: '/tmp/hpc_proxmox_waiter_logs'
|
|
381
|
+
)).to_json
|
|
382
|
+
)
|
|
383
|
+
result = nil
|
|
384
|
+
begin
|
|
385
|
+
extra_files[config_file] = './proxmox/config'
|
|
386
|
+
cmd << " --config ./proxmox/config/#{File.basename(config_file)}"
|
|
387
|
+
stdout = nil
|
|
388
|
+
Credentials.with_credentials_for(:proxmox, @logger, @logger_stderr, url: proxmox_test_info[:api_url]) do |user, password|
|
|
389
|
+
# To avoid too fine concurrent accesses on the sync node file system, make sure all threads of our process wait for their turn to upload their files.
|
|
390
|
+
# Otherwise there is a small probability that a directory scp makes previously copied files inaccessible for a short period of time.
|
|
391
|
+
self.class.proxmox_waiter_files_mutex.synchronize do
|
|
392
|
+
@actions_executor.execute_actions(
|
|
393
|
+
{
|
|
394
|
+
proxmox_test_info[:sync_node] => [
|
|
395
|
+
{ scp: { "#{__dir__}/proxmox/" => '.' } },
|
|
396
|
+
{ remote_bash: extra_files.values.sort.uniq.map { |dir| "mkdir -p #{dir}" }.join("\n") }
|
|
397
|
+
] +
|
|
398
|
+
extra_files.map { |src_file, dst_dir| { scp: { src_file => dst_dir } } }
|
|
399
|
+
},
|
|
400
|
+
log_to_stdout: log_debug?
|
|
401
|
+
)
|
|
402
|
+
end
|
|
403
|
+
_exit_code, stdout, _stderr = @actions_executor.execute_actions(
|
|
404
|
+
{
|
|
405
|
+
proxmox_test_info[:sync_node] => {
|
|
406
|
+
remote_bash: {
|
|
407
|
+
commands: "#{@actions_executor.connector(:ssh).ssh_user == 'root' ? '' : 'sudo -E '}./proxmox/#{cmd}",
|
|
408
|
+
env: {
|
|
409
|
+
'hpc_user_for_proxmox' => user,
|
|
410
|
+
'hpc_password_for_proxmox' => password,
|
|
411
|
+
'hpc_realm_for_proxmox' => ENV['hpc_realm_for_proxmox'] || 'pam'
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
log_to_stdout: log_debug?
|
|
417
|
+
)[proxmox_test_info[:sync_node]]
|
|
418
|
+
end
|
|
419
|
+
stdout_lines = stdout.split("\n")
|
|
420
|
+
result = JSON.parse(stdout_lines[stdout_lines.index('===== JSON =====') + 1..-1].join("\n")).transform_keys(&:to_sym)
|
|
421
|
+
raise "[ #{@node}/#{@environment} ] - Error returned by #{cmd}: #{result[:error]}" if result.key?(:error)
|
|
422
|
+
ensure
|
|
423
|
+
File.unlink(config_file)
|
|
424
|
+
end
|
|
425
|
+
result
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# Query the Proxmox cluster to get authorization to create an LXC container that will use some resources.
|
|
429
|
+
# The returned VM ID/IP does not exist in the Proxmox cluster, and their usage is reserved for our node/environment.
|
|
430
|
+
#
|
|
431
|
+
# Parameters::
|
|
432
|
+
# * *vm_info* (Hash<symbol,Object>): The VM info we want to create
|
|
433
|
+
# Result::
|
|
434
|
+
# * Hash<Symbol, Object>: The details of the authorized container to be created:
|
|
435
|
+
# * *pve_node* (String): Name of the node on which the container is to be created
|
|
436
|
+
# * *vm_id* (Integer): Container ID to be used
|
|
437
|
+
# * *vm_ip* (String): IP address allocated for the LXC container to be created
|
|
438
|
+
def request_lxc_creation_for(vm_info)
|
|
439
|
+
log_debug "[ #{@node}/#{@environment} ] - Request LXC creation for #{vm_info}..."
|
|
440
|
+
# Create a unique file name
|
|
441
|
+
create_config_file = "#{Dir.tmpdir}/create_#{file_id}.json"
|
|
442
|
+
File.write(create_config_file, vm_info.to_json)
|
|
443
|
+
created_vm_info = nil
|
|
444
|
+
begin
|
|
445
|
+
created_vm_info = run_cmd_on_sync_node(
|
|
446
|
+
"reserve_proxmox_container --create ./proxmox/create/#{File.basename(create_config_file)}",
|
|
447
|
+
extra_files: { create_config_file => './proxmox/create' }
|
|
448
|
+
)
|
|
449
|
+
ensure
|
|
450
|
+
File.unlink(create_config_file)
|
|
451
|
+
end
|
|
452
|
+
created_vm_info
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
# Contact the sync node to notify a container release
|
|
456
|
+
#
|
|
457
|
+
# Parameters::
|
|
458
|
+
# * *vm_id* (Integer): The VM ID to be released
|
|
459
|
+
# Result::
|
|
460
|
+
# * Hash<Symbol, Object>: The details of the released container:
|
|
461
|
+
# * *pve_node* (String): Name of the node on which the container was reserved (if found)
|
|
462
|
+
def release_lxc_container(vm_id)
|
|
463
|
+
log_debug "[ #{@node}/#{@environment} ] - Release LXC VM #{vm_id}..."
|
|
464
|
+
# Create a unique file name
|
|
465
|
+
destroy_config_file = "#{Dir.tmpdir}/destroy_#{file_id}.json"
|
|
466
|
+
File.write(destroy_config_file, {
|
|
467
|
+
vm_id: vm_id,
|
|
468
|
+
node: @node,
|
|
469
|
+
environment: @environment
|
|
470
|
+
}.to_json)
|
|
471
|
+
destroyed_vm_info = nil
|
|
472
|
+
begin
|
|
473
|
+
destroyed_vm_info = run_cmd_on_sync_node(
|
|
474
|
+
"reserve_proxmox_container --destroy ./proxmox/destroy/#{File.basename(destroy_config_file)}",
|
|
475
|
+
extra_files: { destroy_config_file => './proxmox/destroy' }
|
|
476
|
+
)
|
|
477
|
+
ensure
|
|
478
|
+
File.unlink(destroy_config_file)
|
|
479
|
+
end
|
|
480
|
+
destroyed_vm_info
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
# Maximum size a file ID can have (file IDs are used differentiate create/destroy/config files for a given node/environment).
|
|
484
|
+
# File names are 255 chars max.
|
|
485
|
+
# Consider that it is to be used on the following patterns: (config|create|destroy)_<ID>.json
|
|
486
|
+
# So remaining length is 255 - 13 = 242 characters.
|
|
487
|
+
MAX_FILE_ID_SIZE = 242
|
|
488
|
+
|
|
489
|
+
# Get an ID unique for theis node/environment and that can be used in file names.
|
|
490
|
+
#
|
|
491
|
+
# Result::
|
|
492
|
+
# * String: ID
|
|
493
|
+
def file_id
|
|
494
|
+
# If the file name exceeds the maximum length, then generate an MD5 to truncate the end of the file name.
|
|
495
|
+
result = "#{@node}_#{@environment}"
|
|
496
|
+
if result.size > MAX_FILE_ID_SIZE
|
|
497
|
+
# Truncate it, but add a unique ID in it.
|
|
498
|
+
result = "-#{Digest::MD5.hexdigest(result)[0..7]}"
|
|
499
|
+
result = "#{@node}_#{@environment}"[0..MAX_FILE_ID_SIZE - result.size - 1] + result
|
|
500
|
+
end
|
|
501
|
+
result
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
# Get details about the proxmox instance to be used
|
|
505
|
+
#
|
|
506
|
+
# Result::
|
|
507
|
+
# * Hash<Symbol,Object>: Configuration of the Proxmox instance to be used:
|
|
508
|
+
# * *api_url* (String): The Proxmox API URL
|
|
509
|
+
# * *sync_node* (String): Node to be used to synchronize Proxmox resources acquisition
|
|
510
|
+
# * *test_config* (Hash<Symbol,Object>): The test configuration. Check ProxmoxWaiter#initialize (config_file structure) method to get details.
|
|
511
|
+
# * *vm_config* (Hash<Symbol,Object>): Extra configuration of a created container. Check #request_lxc_creation_for results to get details.
|
|
512
|
+
# * *default_timeout* (Integer): The default timeout tobe applied when starting/stopping containers [default: 3600].
|
|
513
|
+
def proxmox_test_info
|
|
514
|
+
@config.proxmox_servers.first
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
end
|