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,96 @@
|
|
|
1
|
+
module HybridPlatformsConductorTest
|
|
2
|
+
|
|
3
|
+
module Helpers
|
|
4
|
+
|
|
5
|
+
module ExecutablesHelpers
|
|
6
|
+
|
|
7
|
+
# Run an executable and get its output
|
|
8
|
+
#
|
|
9
|
+
# Parameters::
|
|
10
|
+
# * *executable* (String): Executable name
|
|
11
|
+
# * *args* (Array<String>): Arguments to give the executable
|
|
12
|
+
# Result::
|
|
13
|
+
# * Integer: Exit code
|
|
14
|
+
# * String: stdout
|
|
15
|
+
# * String: stderr
|
|
16
|
+
def run(executable, *args)
|
|
17
|
+
stdout_file = "#{Dir.tmpdir}/hpc_test/run.stdout"
|
|
18
|
+
stderr_file = "#{Dir.tmpdir}/hpc_test/run.stderr"
|
|
19
|
+
File.open(stdout_file, 'w') { |f| f.truncate(0) }
|
|
20
|
+
File.open(stderr_file, 'w') { |f| f.truncate(0) }
|
|
21
|
+
logger_stdout = Logger.new(stdout_file, level: :info)
|
|
22
|
+
logger_stderr = Logger.new(stderr_file, level: :info)
|
|
23
|
+
# Mock the Executable creation to redirect stdout and stderr correctly
|
|
24
|
+
expect(HybridPlatformsConductor::Executable).to receive(:new).once.and_wrap_original do |original_method,
|
|
25
|
+
check_options: true,
|
|
26
|
+
nodes_selection_options: true,
|
|
27
|
+
parallel_options: true,
|
|
28
|
+
timeout_options: true,
|
|
29
|
+
deploy_options: true,
|
|
30
|
+
original_logger: Logger.new(STDOUT, level: :info),
|
|
31
|
+
original_logger_stderr: Logger.new(STDERR, level: :info),
|
|
32
|
+
&opts_block|
|
|
33
|
+
original_method.call(
|
|
34
|
+
check_options: check_options,
|
|
35
|
+
nodes_selection_options: nodes_selection_options,
|
|
36
|
+
parallel_options: parallel_options,
|
|
37
|
+
timeout_options: timeout_options,
|
|
38
|
+
deploy_options: deploy_options,
|
|
39
|
+
logger: logger_stdout,
|
|
40
|
+
logger_stderr: logger_stderr,
|
|
41
|
+
&opts_block
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
# Get a simple list of all the components that should be mocked when being used by the executables, per class to be mocked.
|
|
45
|
+
components_to_mock = {
|
|
46
|
+
HybridPlatformsConductor::ActionsExecutor => test_actions_executor,
|
|
47
|
+
HybridPlatformsConductor::CmdRunner => test_cmd_runner,
|
|
48
|
+
HybridPlatformsConductor::Config => test_config,
|
|
49
|
+
HybridPlatformsConductor::Deployer => test_deployer,
|
|
50
|
+
HybridPlatformsConductor::NodesHandler => test_nodes_handler,
|
|
51
|
+
HybridPlatformsConductor::PlatformsHandler => test_platforms_handler,
|
|
52
|
+
HybridPlatformsConductor::ReportsHandler => test_reports_handler,
|
|
53
|
+
HybridPlatformsConductor::TestsRunner => test_tests_runner
|
|
54
|
+
}
|
|
55
|
+
# Make sure the tested components use the same loggers as the executable.
|
|
56
|
+
components_to_mock.values.each do |component|
|
|
57
|
+
component.stdout_device = stdout_file
|
|
58
|
+
component.stderr_device = stderr_file
|
|
59
|
+
end
|
|
60
|
+
# Make sure that when the executable creates components it uses ours
|
|
61
|
+
components_to_mock.each do |component_class, component|
|
|
62
|
+
allow(component_class).to receive(:new).once { component }
|
|
63
|
+
end
|
|
64
|
+
# Run the executable
|
|
65
|
+
args.concat(['--debug']) if ENV['TEST_DEBUG'] == '1'
|
|
66
|
+
ARGV.replace(args)
|
|
67
|
+
old_0 = $0
|
|
68
|
+
$0 = executable
|
|
69
|
+
begin
|
|
70
|
+
exit_code = nil
|
|
71
|
+
begin
|
|
72
|
+
load "#{__dir__}/../../../bin/#{executable}"
|
|
73
|
+
exit_code = 0
|
|
74
|
+
rescue SystemExit
|
|
75
|
+
exit_code = $!.status
|
|
76
|
+
end
|
|
77
|
+
ensure
|
|
78
|
+
$0 = old_0
|
|
79
|
+
end
|
|
80
|
+
stdout = File.read(stdout_file)
|
|
81
|
+
stderr = File.read(stderr_file)
|
|
82
|
+
if ENV['TEST_DEBUG'] == '1'
|
|
83
|
+
puts "> #{executable} #{args.join(' ')}"
|
|
84
|
+
puts '===== STDOUT ====='
|
|
85
|
+
puts stdout
|
|
86
|
+
puts '===== STDERR ====='
|
|
87
|
+
puts stderr
|
|
88
|
+
end
|
|
89
|
+
[exit_code, stdout, stderr]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module HybridPlatformsConductorTest
|
|
2
|
+
|
|
3
|
+
module Helpers
|
|
4
|
+
|
|
5
|
+
module NodesHandlerHelpers
|
|
6
|
+
|
|
7
|
+
# Get a test NodesHandler
|
|
8
|
+
#
|
|
9
|
+
# Result::
|
|
10
|
+
# * NodesHandler: NodesHandler on which we can do testing
|
|
11
|
+
def test_nodes_handler
|
|
12
|
+
@nodes_handler = HybridPlatformsConductor::NodesHandler.new logger: logger, logger_stderr: logger, config: test_config, cmd_runner: test_cmd_runner, platforms_handler: test_platforms_handler unless @nodes_handler
|
|
13
|
+
@nodes_handler
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module HybridPlatformsConductorTest
|
|
2
|
+
|
|
3
|
+
module Helpers
|
|
4
|
+
|
|
5
|
+
module PlatformHandlerHelpers
|
|
6
|
+
|
|
7
|
+
# Return the test platforms info, used by the test PlatformHandler
|
|
8
|
+
#
|
|
9
|
+
# Result::
|
|
10
|
+
# * *Hash<String, Hash>: Platforms info, per platform name (see TestPlatformHandler#platforms_info for details)
|
|
11
|
+
def test_platforms_info
|
|
12
|
+
HybridPlatformsConductorTest::PlatformHandlerPlugins::Test.platforms_info
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Set the test platforms info, used by the test PlatformHandler
|
|
16
|
+
#
|
|
17
|
+
# Parameters::
|
|
18
|
+
# * *platforms_info* (Hash<String, Hash>): Platforms info, per platform name (see TestPlatformHandler#platforms_info for details)
|
|
19
|
+
def test_platforms_info=(platforms_info)
|
|
20
|
+
HybridPlatformsConductorTest::PlatformHandlerPlugins::Test.platforms_info = platforms_info
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Register the given platform handler classes
|
|
24
|
+
#
|
|
25
|
+
# Parameters::
|
|
26
|
+
# * *platform_handlers* (Hash<Symbol,Class>): The platform handler classes, per platform type name
|
|
27
|
+
def register_platform_handlers(platform_handlers)
|
|
28
|
+
register_plugins(:platform_handler, platform_handlers)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
module HybridPlatformsConductorTest
|
|
2
|
+
|
|
3
|
+
module Helpers
|
|
4
|
+
|
|
5
|
+
module PlatformsHandlerHelpers
|
|
6
|
+
|
|
7
|
+
# Setup several test repositories.
|
|
8
|
+
# Clean-up at the end.
|
|
9
|
+
#
|
|
10
|
+
# Parameters::
|
|
11
|
+
# * *names* (Array<String>): Name of the directories to be used [default = []]
|
|
12
|
+
# * *as_git* (Boolean): Do we initialize those repositories as Git repositories? [default: false]
|
|
13
|
+
# * Proc: Code called with the repositories created.
|
|
14
|
+
# * Parameters::
|
|
15
|
+
# * *repositories* (Hash<String,String>): Path to the repositories, per repository name
|
|
16
|
+
def with_repositories(names = [], as_git: false)
|
|
17
|
+
repositories = Hash[names.map { |name| [name, "#{Dir.tmpdir}/hpc_test/#{name}"] }]
|
|
18
|
+
repositories.values.each do |dir|
|
|
19
|
+
FileUtils.rm_rf dir
|
|
20
|
+
FileUtils.mkdir_p dir
|
|
21
|
+
if as_git
|
|
22
|
+
git = Git.init(dir)
|
|
23
|
+
FileUtils.touch("#{dir}/test_file")
|
|
24
|
+
git.add('test_file')
|
|
25
|
+
git.config('user.name', 'Thats Me')
|
|
26
|
+
git.config('user.email', 'email@email.com')
|
|
27
|
+
git.commit('Test commit')
|
|
28
|
+
git.add_remote('origin', "https://my_remote.com/path/to/#{File.basename(dir)}.git")
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
begin
|
|
32
|
+
yield repositories
|
|
33
|
+
ensure
|
|
34
|
+
repositories.values.each do |dir|
|
|
35
|
+
FileUtils.rm_rf dir
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Setup a test repository.
|
|
41
|
+
# Clean-up at the end.
|
|
42
|
+
#
|
|
43
|
+
# Parameters::
|
|
44
|
+
# * *name* (String): Name of the directory to be used [default = 'platform_repo']
|
|
45
|
+
# * *as_git* (Boolean): Do we initialize those repositories as Git repositories? [default: false]
|
|
46
|
+
# * Proc: Code called with the repository created.
|
|
47
|
+
# * Parameters::
|
|
48
|
+
# * *repository* (String): Path to the repository
|
|
49
|
+
def with_repository(name = 'platform_repo', as_git: false)
|
|
50
|
+
with_repositories([name], as_git: as_git) do |repositories|
|
|
51
|
+
yield repositories[name]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Setup a hpc_config.rb with a given content and call code when it's ready.
|
|
56
|
+
# Automatically sets the hpc_platforms env variable so that processes can then use it.
|
|
57
|
+
# Clean-up at the end.
|
|
58
|
+
#
|
|
59
|
+
# Parameters::
|
|
60
|
+
# * *content* (String): hpc_config.rb's content
|
|
61
|
+
# * Proc: Code called with the platforms.rb file created.
|
|
62
|
+
# * Parameters::
|
|
63
|
+
# * *hybrid_platforms_dir* (String): The hybrid-platforms directory
|
|
64
|
+
def with_platforms(content)
|
|
65
|
+
with_repository('hybrid-platforms') do |hybrid_platforms_dir|
|
|
66
|
+
File.write("#{hybrid_platforms_dir}/hpc_config.rb", content)
|
|
67
|
+
ENV['hpc_platforms'] = hybrid_platforms_dir
|
|
68
|
+
yield hybrid_platforms_dir
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Instantiate a test environment with several test platforms, ready to run tests
|
|
73
|
+
# Clean-up at the end.
|
|
74
|
+
#
|
|
75
|
+
# Parameters::
|
|
76
|
+
# * *platforms_info* (Hash<String,Object>): Platforms info for the test platform [default = {}]
|
|
77
|
+
# * *as_git* (Boolean): Do we initialize those repositories as Git repositories? [default = false]
|
|
78
|
+
# * *additional_platforms_content* (String): Additional platforms content to be added [default = '']
|
|
79
|
+
# * Proc: Code called with the environment ready
|
|
80
|
+
# * Parameters::
|
|
81
|
+
# * *repositories* (Hash<String,String>): Path to the repositories, per repository name
|
|
82
|
+
def with_test_platforms(platforms_info = {}, as_git = false, additional_platforms_content = '')
|
|
83
|
+
with_repositories(platforms_info.keys, as_git: as_git) do |repositories|
|
|
84
|
+
platform_types = []
|
|
85
|
+
with_platforms(repositories.map do |platform, dir|
|
|
86
|
+
platform_type = platforms_info[platform].key?(:platform_type) ? platforms_info[platform][:platform_type] : :test
|
|
87
|
+
platform_types << platform_type unless platform_types.include?(platform_type)
|
|
88
|
+
"#{platform_type}_platform path: '#{dir}'"
|
|
89
|
+
end.join("\n") + "\n#{additional_platforms_content}") do
|
|
90
|
+
register_platform_handlers(Hash[platform_types.map { |platform_type| [platform_type, HybridPlatformsConductorTest::PlatformHandlerPlugins.const_get(platform_type.to_s.split('_').collect(&:capitalize).join.to_sym)] }])
|
|
91
|
+
self.test_platforms_info = platforms_info
|
|
92
|
+
yield repositories
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Instantiate a test environment with a test platform handler, ready to run tests
|
|
98
|
+
# Clean-up at the end.
|
|
99
|
+
#
|
|
100
|
+
# Parameters::
|
|
101
|
+
# * *platform_info* (Hash<Symbol,Object>): Platform info for the test platform [default = {}]
|
|
102
|
+
# * *as_git* (Boolean): Do we initialize those repositories as Git repositories? [default = false]
|
|
103
|
+
# * *additional_platforms_content* (String): Additional platforms content to be added [default = '']
|
|
104
|
+
# * Proc: Code called with the environment ready
|
|
105
|
+
# * Parameters::
|
|
106
|
+
# * *repository* (String): Path to the repository
|
|
107
|
+
def with_test_platform(platform_info = {}, as_git = false, additional_platforms_content = '')
|
|
108
|
+
platform_name = as_git ? 'my_remote_platform' : 'platform'
|
|
109
|
+
with_test_platforms({ platform_name => platform_info }, as_git, additional_platforms_content) do |repositories|
|
|
110
|
+
yield repositories[platform_name]
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Get a test PlatformsHandler
|
|
115
|
+
#
|
|
116
|
+
# Result::
|
|
117
|
+
# * PlatformsHandler: PlatformsHandler on which we can do testing
|
|
118
|
+
def test_platforms_handler
|
|
119
|
+
@platforms_handler = HybridPlatformsConductor::PlatformsHandler.new logger: logger, logger_stderr: logger, config: test_config, cmd_runner: test_cmd_runner unless @platforms_handler
|
|
120
|
+
@platforms_handler
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module HybridPlatformsConductorTest
|
|
2
|
+
|
|
3
|
+
module Helpers
|
|
4
|
+
|
|
5
|
+
module PluginsHelpers
|
|
6
|
+
|
|
7
|
+
# Register given plugins for a given plugin type
|
|
8
|
+
#
|
|
9
|
+
# Parameters::
|
|
10
|
+
# * *plugin_type* (Symbol): The plugin type
|
|
11
|
+
# * *plugins* (Hash<Symbol,Class>): The plugin classes, per plugin ID
|
|
12
|
+
# * *replace* (Boolean): Should we replace the plugins with the mocked ones, or only add them? [default: true]
|
|
13
|
+
def register_plugins(plugin_type, plugins, replace: true)
|
|
14
|
+
unless defined?(@plugins_to_mock)
|
|
15
|
+
# First time we invoke it: mock the call to Plugins
|
|
16
|
+
# List of plugins information to mock, per plugin type
|
|
17
|
+
# * *plugins* (Hash<Symbol,Class>): The mocked plugins
|
|
18
|
+
# * *replace* (Boolean): Should we replace the plugins or add them?
|
|
19
|
+
# Hash< Symbol, Hash<Symbol, Object> >
|
|
20
|
+
@plugins_to_mock = {}
|
|
21
|
+
allow(HybridPlatformsConductor::Plugins).to receive(:new).and_wrap_original do |original_new, plugins_type, init_plugin: nil, parse_gems: true, logger: Logger.new(STDOUT), logger_stderr: Logger.new(STDERR)|
|
|
22
|
+
# If this plugin type is to be mocked, then don't parse gems and provide the mocked plugins instead
|
|
23
|
+
mocked_plugins = original_new.call(
|
|
24
|
+
plugins_type,
|
|
25
|
+
init_plugin: init_plugin,
|
|
26
|
+
parse_gems: @plugins_to_mock.key?(plugins_type) && @plugins_to_mock[plugins_type][:replace] ? false : parse_gems,
|
|
27
|
+
logger: logger,
|
|
28
|
+
logger_stderr: logger_stderr
|
|
29
|
+
)
|
|
30
|
+
if @plugins_to_mock.key?(plugins_type)
|
|
31
|
+
@plugins_to_mock[plugins_type][:plugins].each do |plugin_id, plugin_class|
|
|
32
|
+
mocked_plugins[plugin_id] = plugin_class
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
mocked_plugins
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
@plugins_to_mock[plugin_type] = {
|
|
39
|
+
plugins: plugins,
|
|
40
|
+
replace: replace
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
@@ -0,0 +1,789 @@
|
|
|
1
|
+
module HybridPlatformsConductorTest
|
|
2
|
+
|
|
3
|
+
module Helpers
|
|
4
|
+
|
|
5
|
+
module ProvisionerProxmoxHelpers
|
|
6
|
+
|
|
7
|
+
# Setup a test platform for Proxmox tests
|
|
8
|
+
#
|
|
9
|
+
# Parameters::
|
|
10
|
+
# * *node_metadata* (Hash<Symbol,Object>): Extra node metadata [default: {}]
|
|
11
|
+
# * *environment* (String): Environment to be used [default: 'test']
|
|
12
|
+
# * Proc: Code called when everything is setup
|
|
13
|
+
# * Parameters::
|
|
14
|
+
# * *instance* (Provisioner): A new Provisioner instance targeting the Proxmox instance
|
|
15
|
+
# * *repository* (String): The platforms' repository
|
|
16
|
+
def with_test_proxmox_platform(node_metadata: {}, environment: 'test')
|
|
17
|
+
with_repository('platform') do |repository|
|
|
18
|
+
os_image_path = "#{repository}/os_image"
|
|
19
|
+
FileUtils.mkdir_p os_image_path
|
|
20
|
+
FileUtils.cp "#{__dir__}/../api/deployer/provisioners/proxmox/proxmox.json", "#{os_image_path}/proxmox.json"
|
|
21
|
+
with_platforms("
|
|
22
|
+
os_image :test_image, '#{os_image_path}'
|
|
23
|
+
test_platform path: '#{repository}'
|
|
24
|
+
proxmox(
|
|
25
|
+
api_url: 'https://my-proxmox.my-domain.com:8006',
|
|
26
|
+
sync_node: 'node',
|
|
27
|
+
test_config: {
|
|
28
|
+
pve_nodes: ['pve_node_name'],
|
|
29
|
+
vm_ips_list: %w[
|
|
30
|
+
192.168.0.100
|
|
31
|
+
192.168.0.101
|
|
32
|
+
],
|
|
33
|
+
vm_ids_range: [1000, 1100],
|
|
34
|
+
coeff_ram_consumption: 10,
|
|
35
|
+
coeff_disk_consumption: 1,
|
|
36
|
+
expiration_period_secs: 24 * 60 * 60,
|
|
37
|
+
limits: {
|
|
38
|
+
nbr_vms_max: 5,
|
|
39
|
+
cpu_loads_thresholds: [10, 10, 10],
|
|
40
|
+
ram_percent_used_max: 0.75,
|
|
41
|
+
disk_percent_used_max: 0.75
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
vm_config: {
|
|
45
|
+
vm_dns_servers: ['8.8.8.8'],
|
|
46
|
+
vm_search_domain: 'my-domain.com',
|
|
47
|
+
vm_gateway: '192.168.0.1'
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
") do
|
|
51
|
+
register_platform_handlers test: HybridPlatformsConductorTest::PlatformHandlerPlugins::Test
|
|
52
|
+
self.test_platforms_info = { 'platform' => {
|
|
53
|
+
nodes: { 'node' => { meta: { host_ip: '192.168.42.42', image: 'test_image' }.merge(node_metadata) } }
|
|
54
|
+
} }
|
|
55
|
+
instance = HybridPlatformsConductor::HpcPlugins::Provisioner::Proxmox.new(
|
|
56
|
+
'node',
|
|
57
|
+
environment: environment,
|
|
58
|
+
logger: logger,
|
|
59
|
+
logger_stderr: logger,
|
|
60
|
+
config: test_config,
|
|
61
|
+
cmd_runner: test_cmd_runner,
|
|
62
|
+
nodes_handler: test_nodes_handler,
|
|
63
|
+
actions_executor: test_actions_executor
|
|
64
|
+
)
|
|
65
|
+
yield instance, repository
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Get a mocking code corresponding to a call to Proxmox.new.
|
|
71
|
+
# This code should mock Proxmox getting info about the existing nodes
|
|
72
|
+
#
|
|
73
|
+
# Parameters::
|
|
74
|
+
# * *proxmox_user* (String or nil): Proxmox user used to connect to Proxmox API [default: nil]
|
|
75
|
+
# * *proxmox_password* (String or nil): Proxmox password used to connect to Proxmox API [default: nil]
|
|
76
|
+
# * *proxmox_realm* (String or nil): Proxmox realm used to connect to Proxmox API [default: 'pam']
|
|
77
|
+
# * *nodes_info* (Array<Hash>): Nodes info returned by the Proxmox API [default: []]
|
|
78
|
+
# * *extra_expects* (Proc or nil): Code called for additional expectations on the proxmox instance, or nil if none [default: nil]
|
|
79
|
+
# * Parameters::
|
|
80
|
+
# * *proxmox* (Double): The mocked Proxmox instance
|
|
81
|
+
# Result::
|
|
82
|
+
# * Proc: Code called in place of Proxmox.new. Signature is the same as Proxmox.new.
|
|
83
|
+
def mock_proxmox_to_get_nodes_info(proxmox_user: nil, proxmox_password: nil, proxmox_realm: 'pam', nodes_info: [], extra_expects: nil)
|
|
84
|
+
proc do |url, pve_node, user, password, realm, options|
|
|
85
|
+
expect(url).to eq 'https://my-proxmox.my-domain.com:8006/api2/json/'
|
|
86
|
+
expect(pve_node).to eq 'my-proxmox'
|
|
87
|
+
expect(user).to eq proxmox_user
|
|
88
|
+
expect(password).to eq proxmox_password
|
|
89
|
+
expect(realm).to eq proxmox_realm
|
|
90
|
+
expect(options[:verify_ssl]).to eq false
|
|
91
|
+
proxmox = double 'Proxmox info instance'
|
|
92
|
+
# Mock initialization
|
|
93
|
+
expect(proxmox).to receive(:logger=) do
|
|
94
|
+
# Nothing
|
|
95
|
+
end
|
|
96
|
+
expect(proxmox).to receive(:logger_stderr=) do
|
|
97
|
+
# Nothing
|
|
98
|
+
end
|
|
99
|
+
# Mock checking existing nodes
|
|
100
|
+
expect(proxmox).to receive(:get).with('nodes') do
|
|
101
|
+
nodes_info
|
|
102
|
+
end
|
|
103
|
+
extra_expects.call(proxmox) unless extra_expects.nil?
|
|
104
|
+
proxmox
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Get a mocking code corresponding to a call to Proxmox.new.
|
|
109
|
+
# This code should mock Proxmox starting a node
|
|
110
|
+
#
|
|
111
|
+
# Parameters::
|
|
112
|
+
# * *proxmox_user* (String or nil): Proxmox user used to connect to Proxmox API [default: nil]
|
|
113
|
+
# * *proxmox_password* (String or nil): Proxmox password used to connect to Proxmox API [default: nil]
|
|
114
|
+
# * *task_name* (String): Proxmox start task name [default: 'UPID:pve_node_name:0000A504:6DEABF24:5F44669B:start::root@pam:']
|
|
115
|
+
# * *task_status* (String or nil): Proxmox start task status, or nil if no task status query is to be expected [default: 'OK']
|
|
116
|
+
# * *nbr_api_errors* (Integer): Number of API errors 500 to mock before getting a successful query [defaults: 0]
|
|
117
|
+
# Result::
|
|
118
|
+
# * Proc: Code called in place of Proxmox.new. Signature is the same as Proxmox.new.
|
|
119
|
+
def mock_proxmox_to_start_node(
|
|
120
|
+
proxmox_user: nil,
|
|
121
|
+
proxmox_password: nil,
|
|
122
|
+
task_name: 'UPID:pve_node_name:0000A504:6DEABF24:5F44669B:start::root@pam:',
|
|
123
|
+
task_status: 'OK',
|
|
124
|
+
nbr_api_errors: 0
|
|
125
|
+
)
|
|
126
|
+
proc do |url, pve_node, user, password, realm, options|
|
|
127
|
+
expect(url).to eq 'https://my-proxmox.my-domain.com:8006/api2/json/'
|
|
128
|
+
expect(pve_node).to eq 'my-proxmox'
|
|
129
|
+
expect(user).to eq proxmox_user
|
|
130
|
+
expect(password).to eq proxmox_password
|
|
131
|
+
expect(realm).to eq 'pam'
|
|
132
|
+
expect(options[:verify_ssl]).to eq false
|
|
133
|
+
proxmox = double 'Proxmox create instance'
|
|
134
|
+
# Mock initialization
|
|
135
|
+
expect(proxmox).to receive(:logger=) do
|
|
136
|
+
# Nothing
|
|
137
|
+
end
|
|
138
|
+
expect(proxmox).to receive(:logger_stderr=) do
|
|
139
|
+
# Nothing
|
|
140
|
+
end
|
|
141
|
+
# Mock start a container
|
|
142
|
+
idx_try = 0
|
|
143
|
+
expect(proxmox).to receive(:post).exactly(nbr_api_errors + (task_status.nil? ? 0 : 1)).times.with('nodes/pve_node_name/lxc/1024/status/start') do
|
|
144
|
+
idx_try += 1
|
|
145
|
+
idx_try <= nbr_api_errors ? 'NOK: error code = 500' : task_name
|
|
146
|
+
end
|
|
147
|
+
# Mock checking task status
|
|
148
|
+
unless task_status.nil?
|
|
149
|
+
# Mock checking task status
|
|
150
|
+
expect(proxmox).to receive(:get).with("nodes/pve_node_name/tasks/#{task_name}/status") do
|
|
151
|
+
{ 'status' => task_status }
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
proxmox
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Get a mocking code corresponding to a call to Proxmox.new.
|
|
159
|
+
# This code should mock Proxmox stopping a node
|
|
160
|
+
#
|
|
161
|
+
# Parameters::
|
|
162
|
+
# * *proxmox_user* (String or nil): Proxmox user used to connect to Proxmox API [default: nil]
|
|
163
|
+
# * *proxmox_password* (String or nil): Proxmox password used to connect to Proxmox API [default: nil]
|
|
164
|
+
# * *task_status* (String): Proxmox stop task status [default: 'OK']
|
|
165
|
+
# Result::
|
|
166
|
+
# * Proc: Code called in place of Proxmox.new. Signature is the same as Proxmox.new.
|
|
167
|
+
def mock_proxmox_to_stop_node(
|
|
168
|
+
proxmox_user: nil,
|
|
169
|
+
proxmox_password: nil,
|
|
170
|
+
task_status: 'OK'
|
|
171
|
+
)
|
|
172
|
+
proc do |url, pve_node, user, password, realm, options|
|
|
173
|
+
expect(url).to eq 'https://my-proxmox.my-domain.com:8006/api2/json/'
|
|
174
|
+
expect(pve_node).to eq 'my-proxmox'
|
|
175
|
+
expect(user).to eq proxmox_user
|
|
176
|
+
expect(password).to eq proxmox_password
|
|
177
|
+
expect(realm).to eq 'pam'
|
|
178
|
+
expect(options[:verify_ssl]).to eq false
|
|
179
|
+
proxmox = double 'Proxmox create instance'
|
|
180
|
+
# Mock initialization
|
|
181
|
+
expect(proxmox).to receive(:logger=) do
|
|
182
|
+
# Nothing
|
|
183
|
+
end
|
|
184
|
+
expect(proxmox).to receive(:logger_stderr=) do
|
|
185
|
+
# Nothing
|
|
186
|
+
end
|
|
187
|
+
# Mock start a container
|
|
188
|
+
expect(proxmox).to receive(:post).with('nodes/pve_node_name/lxc/1024/status/stop') do
|
|
189
|
+
'UPID:pve_node_name:0000A504:6DEABF24:5F44669B:stop::root@pam:'
|
|
190
|
+
end
|
|
191
|
+
# Mock checking task status
|
|
192
|
+
expect(proxmox).to receive(:get).with('nodes/pve_node_name/tasks/UPID:pve_node_name:0000A504:6DEABF24:5F44669B:stop::root@pam:/status') do
|
|
193
|
+
{ 'status' => task_status }
|
|
194
|
+
end
|
|
195
|
+
proxmox
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Get a mocking code corresponding to a call to Proxmox.new.
|
|
200
|
+
# This code should mock Proxmox destroying a node
|
|
201
|
+
#
|
|
202
|
+
# Parameters::
|
|
203
|
+
# * *proxmox_user* (String or nil): Proxmox user used to connect to Proxmox API [default: nil]
|
|
204
|
+
# * *proxmox_password* (String or nil): Proxmox password used to connect to Proxmox API [default: nil]
|
|
205
|
+
# * *task_status* (String): Proxmox destroy task status [default: 'OK']
|
|
206
|
+
# Result::
|
|
207
|
+
# * Proc: Code called in place of Proxmox.new. Signature is the same as Proxmox.new.
|
|
208
|
+
def mock_proxmox_to_destroy_node(
|
|
209
|
+
proxmox_user: nil,
|
|
210
|
+
proxmox_password: nil,
|
|
211
|
+
task_status: 'OK'
|
|
212
|
+
)
|
|
213
|
+
proc do |url, pve_node, user, password, realm, options|
|
|
214
|
+
expect(url).to eq 'https://my-proxmox.my-domain.com:8006/api2/json/'
|
|
215
|
+
expect(pve_node).to eq 'my-proxmox'
|
|
216
|
+
expect(user).to eq proxmox_user
|
|
217
|
+
expect(password).to eq proxmox_password
|
|
218
|
+
expect(realm).to eq 'pam'
|
|
219
|
+
expect(options[:verify_ssl]).to eq false
|
|
220
|
+
proxmox = double 'Proxmox create instance'
|
|
221
|
+
# Mock initialization
|
|
222
|
+
expect(proxmox).to receive(:logger=) do
|
|
223
|
+
# Nothing
|
|
224
|
+
end
|
|
225
|
+
expect(proxmox).to receive(:logger_stderr=) do
|
|
226
|
+
# Nothing
|
|
227
|
+
end
|
|
228
|
+
# Mock start a container
|
|
229
|
+
expect(proxmox).to receive(:delete).with('nodes/pve_node_name/lxc/1024') do
|
|
230
|
+
'UPID:pve_node_name:0000A504:6DEABF24:5F44669B:destroy::root@pam:'
|
|
231
|
+
end
|
|
232
|
+
# Mock checking task status
|
|
233
|
+
expect(proxmox).to receive(:get).with('nodes/pve_node_name/tasks/UPID:pve_node_name:0000A504:6DEABF24:5F44669B:destroy::root@pam:/status') do
|
|
234
|
+
{ 'status' => task_status }
|
|
235
|
+
end
|
|
236
|
+
proxmox
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Get a mocking code corresponding to a call to Proxmox.new.
|
|
241
|
+
# This code should mock Proxmox getting the status a node
|
|
242
|
+
#
|
|
243
|
+
# Parameters::
|
|
244
|
+
# * *proxmox_user* (String or nil): Proxmox user used to connect to Proxmox API [default: nil]
|
|
245
|
+
# * *proxmox_password* (String or nil): Proxmox password used to connect to Proxmox API [default: nil]
|
|
246
|
+
# * *status* (String): Mocked status [default: 'created']
|
|
247
|
+
# Result::
|
|
248
|
+
# * Proc: Code called in place of Proxmox.new. Signature is the same as Proxmox.new.
|
|
249
|
+
def mock_proxmox_to_status_node(
|
|
250
|
+
proxmox_user: nil,
|
|
251
|
+
proxmox_password: nil,
|
|
252
|
+
task_status: 'OK'
|
|
253
|
+
)
|
|
254
|
+
proc do |url, pve_node, user, password, realm, options|
|
|
255
|
+
expect(url).to eq 'https://my-proxmox.my-domain.com:8006/api2/json/'
|
|
256
|
+
expect(pve_node).to eq 'my-proxmox'
|
|
257
|
+
expect(user).to eq proxmox_user
|
|
258
|
+
expect(password).to eq proxmox_password
|
|
259
|
+
expect(realm).to eq 'pam'
|
|
260
|
+
expect(options[:verify_ssl]).to eq false
|
|
261
|
+
proxmox = double 'Proxmox create instance'
|
|
262
|
+
# Mock initialization
|
|
263
|
+
expect(proxmox).to receive(:logger=) do
|
|
264
|
+
# Nothing
|
|
265
|
+
end
|
|
266
|
+
expect(proxmox).to receive(:logger_stderr=) do
|
|
267
|
+
# Nothing
|
|
268
|
+
end
|
|
269
|
+
# Mock getting status of a container
|
|
270
|
+
expect(proxmox).to receive(:get).with('nodes/pve_node_name/lxc') do
|
|
271
|
+
[
|
|
272
|
+
{
|
|
273
|
+
'vmid' => '1024'
|
|
274
|
+
}
|
|
275
|
+
]
|
|
276
|
+
end
|
|
277
|
+
expect(proxmox).to receive(:get).with('nodes/pve_node_name/lxc/1024/status/current') do
|
|
278
|
+
{
|
|
279
|
+
'status' => 'created'
|
|
280
|
+
}
|
|
281
|
+
end
|
|
282
|
+
proxmox
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Mock a call to the reserve_proxmox_container sync node
|
|
287
|
+
#
|
|
288
|
+
# Parameters::
|
|
289
|
+
# * *proxmox_user* (String or nil): Proxmox user used to connect to Proxmox API [default: nil]
|
|
290
|
+
# * *proxmox_password* (String or nil): Proxmox password used to connect to Proxmox API [default: nil]
|
|
291
|
+
# * *proxmox_realm* (String): Proxmox realm used to connect to Proxmox API [default: 'pam']
|
|
292
|
+
# * *error_on_create* (String or nil): Error to be mocked by reserve_proxmox_container create, or nil in case of success [default: nil]
|
|
293
|
+
# * *error_on_destroy* (String or nil): Error to be mocked by reserve_proxmox_container destroy, or nil in case of success [default: nil]
|
|
294
|
+
# * *destroy_vm* (Boolean): Should we expect also a VM destruction? [default: false]
|
|
295
|
+
# * *expected_file_id* (String): The expected config file IDs used [default: 'node_test']
|
|
296
|
+
# * *expected_sudo* (Boolean): Is sudo to be expected? [default: true]
|
|
297
|
+
def mock_call_to_reserve_proxmox_container(
|
|
298
|
+
proxmox_user: nil,
|
|
299
|
+
proxmox_password: nil,
|
|
300
|
+
proxmox_realm: 'pam',
|
|
301
|
+
error_on_create: nil,
|
|
302
|
+
error_on_destroy: nil,
|
|
303
|
+
destroy_vm: false,
|
|
304
|
+
expected_file_id: 'node_test',
|
|
305
|
+
expected_sudo: true
|
|
306
|
+
)
|
|
307
|
+
runs = [
|
|
308
|
+
proc do |actions|
|
|
309
|
+
expect(actions.keys).to eq ['node']
|
|
310
|
+
expect(actions['node'].size).to eq 4
|
|
311
|
+
# First action should be to copy the reserve_proxmox_container code
|
|
312
|
+
expect(actions['node'][0].keys).to eq [:scp]
|
|
313
|
+
expect(actions['node'][0][:scp].first[0]).to match /^.+\/hpc_plugins\/provisioner\/proxmox\/$/
|
|
314
|
+
expect(actions['node'][0][:scp].first[1]).to eq '.'
|
|
315
|
+
# Second action should be to create directories
|
|
316
|
+
expect(actions['node'][1]).to eq({
|
|
317
|
+
remote_bash: "mkdir -p ./proxmox/config\nmkdir -p ./proxmox/create"
|
|
318
|
+
})
|
|
319
|
+
# Next actions should be to copy the config/create/destroy files
|
|
320
|
+
expect(actions['node'][2].keys).to eq [:scp]
|
|
321
|
+
expect(actions['node'][2][:scp].first[0]).to match /^.+\/create_#{Regexp.escape(expected_file_id)}\.json$/
|
|
322
|
+
expect(actions['node'][2][:scp].first[1]).to eq './proxmox/create'
|
|
323
|
+
expect(actions['node'][3].keys).to eq [:scp]
|
|
324
|
+
expect(actions['node'][3][:scp].first[0]).to match /^.+\/config_#{Regexp.escape(expected_file_id)}\.json$/
|
|
325
|
+
expect(actions['node'][3][:scp].first[1]).to eq './proxmox/config'
|
|
326
|
+
@proxmox_create_options = JSON.parse(File.read(actions['node'][2][:scp].first[0]))
|
|
327
|
+
{ 'node' => [0, '', ''] }
|
|
328
|
+
end,
|
|
329
|
+
proc do |actions|
|
|
330
|
+
expect(actions).to eq({
|
|
331
|
+
'node' => {
|
|
332
|
+
remote_bash: {
|
|
333
|
+
commands: "#{expected_sudo ? 'sudo -E ' : ''}./proxmox/reserve_proxmox_container --create ./proxmox/create/create_#{expected_file_id}.json --config ./proxmox/config/config_#{expected_file_id}.json",
|
|
334
|
+
env: {
|
|
335
|
+
'hpc_user_for_proxmox' => proxmox_user,
|
|
336
|
+
'hpc_password_for_proxmox' => proxmox_password,
|
|
337
|
+
'hpc_realm_for_proxmox' => proxmox_realm
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
})
|
|
342
|
+
result =
|
|
343
|
+
if error_on_create
|
|
344
|
+
{ error: error_on_create }
|
|
345
|
+
else
|
|
346
|
+
{
|
|
347
|
+
pve_node: 'pve_node_name',
|
|
348
|
+
vm_id: 1024,
|
|
349
|
+
vm_ip: '192.168.0.100'
|
|
350
|
+
}
|
|
351
|
+
end
|
|
352
|
+
{ 'node' => [0, <<~EOS, ''] }
|
|
353
|
+
===== JSON =====
|
|
354
|
+
#{JSON.pretty_generate(result)}
|
|
355
|
+
EOS
|
|
356
|
+
end
|
|
357
|
+
]
|
|
358
|
+
if destroy_vm
|
|
359
|
+
runs.concat [
|
|
360
|
+
proc do |actions|
|
|
361
|
+
expect(actions.keys).to eq ['node']
|
|
362
|
+
expect(actions['node'].size).to eq 4
|
|
363
|
+
# First action should be to copy the reserve_proxmox_container code
|
|
364
|
+
expect(actions['node'][0].keys).to eq [:scp]
|
|
365
|
+
expect(actions['node'][0][:scp].first[0]).to match /^.+\/hpc_plugins\/provisioner\/proxmox\/$/
|
|
366
|
+
expect(actions['node'][0][:scp].first[1]).to eq '.'
|
|
367
|
+
# Second action should be to create directories
|
|
368
|
+
expect(actions['node'][1]).to eq({
|
|
369
|
+
remote_bash: "mkdir -p ./proxmox/config\nmkdir -p ./proxmox/destroy"
|
|
370
|
+
})
|
|
371
|
+
# Next actions should be to copy the config/create/destroy files
|
|
372
|
+
expect(actions['node'][2].keys).to eq [:scp]
|
|
373
|
+
expect(actions['node'][2][:scp].first[0]).to match /^.+\/destroy_#{Regexp.escape(expected_file_id)}\.json$/
|
|
374
|
+
expect(actions['node'][2][:scp].first[1]).to eq './proxmox/destroy'
|
|
375
|
+
expect(actions['node'][3].keys).to eq [:scp]
|
|
376
|
+
expect(actions['node'][3][:scp].first[0]).to match /^.+\/config_#{Regexp.escape(expected_file_id)}\.json$/
|
|
377
|
+
expect(actions['node'][3][:scp].first[1]).to eq './proxmox/config'
|
|
378
|
+
@proxmox_destroy_options = JSON.parse(File.read(actions['node'][2][:scp].first[0]))
|
|
379
|
+
{ 'node' => [0, '', ''] }
|
|
380
|
+
end,
|
|
381
|
+
proc do |actions|
|
|
382
|
+
expect(actions).to eq({
|
|
383
|
+
'node' => {
|
|
384
|
+
remote_bash: {
|
|
385
|
+
commands: "#{expected_sudo ? 'sudo -E ' : ''}./proxmox/reserve_proxmox_container --destroy ./proxmox/destroy/destroy_#{expected_file_id}.json --config ./proxmox/config/config_#{expected_file_id}.json",
|
|
386
|
+
env: {
|
|
387
|
+
'hpc_user_for_proxmox' => proxmox_user,
|
|
388
|
+
'hpc_password_for_proxmox' => proxmox_password,
|
|
389
|
+
'hpc_realm_for_proxmox' => proxmox_realm
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
})
|
|
394
|
+
result =
|
|
395
|
+
if error_on_destroy
|
|
396
|
+
{ error: error_on_destroy }
|
|
397
|
+
else
|
|
398
|
+
{
|
|
399
|
+
pve_node: 'pve_node_name',
|
|
400
|
+
vm_id: 1024,
|
|
401
|
+
vm_ip: '192.168.0.100'
|
|
402
|
+
}
|
|
403
|
+
end
|
|
404
|
+
{ 'node' => [0, <<~EOS, ''] }
|
|
405
|
+
===== JSON =====
|
|
406
|
+
#{JSON.pretty_generate(result)}
|
|
407
|
+
EOS
|
|
408
|
+
end
|
|
409
|
+
]
|
|
410
|
+
end
|
|
411
|
+
expect_actions_executor_runs runs
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
# Mock a series of Proxmox calls, and expect them to occur.
|
|
415
|
+
#
|
|
416
|
+
# Parameters::
|
|
417
|
+
# * *calls* (Array<Proc>): List of mocked calls
|
|
418
|
+
# * *proxmox_user* (String or nil): Proxmox user used to connect to Proxmox API [default: nil]
|
|
419
|
+
# * *proxmox_password* (String or nil): Proxmox password used to connect to Proxmox API [default: nil]
|
|
420
|
+
# * *proxmox_realm* (String): Proxmox realm used to connect to Proxmox API [default: 'pam']
|
|
421
|
+
# * *error_on_create* (String or nil): Error to be mocked by reserve_proxmox_container create, or nil in case of success [default: nil]
|
|
422
|
+
# * *error_on_destroy* (String or nil): Error to be mocked by reserve_proxmox_container destroy, or nil in case of success [default: nil]
|
|
423
|
+
# * *reserve* (Boolean): Do we expect the resource reservation to occur? [default: true]
|
|
424
|
+
# * *destroy_vm* (Boolean): Should we expect also a VM destruction? [default: false]
|
|
425
|
+
# * *expected_file_id* (String): The expected config file IDs used [default: 'node_test']
|
|
426
|
+
# * *expected_sudo* (Boolean): Is sudo to be expected? [default: true]
|
|
427
|
+
def mock_proxmox_calls_with(
|
|
428
|
+
calls,
|
|
429
|
+
proxmox_user: nil,
|
|
430
|
+
proxmox_password: nil,
|
|
431
|
+
proxmox_realm: 'pam',
|
|
432
|
+
error_on_create: nil,
|
|
433
|
+
error_on_destroy: nil,
|
|
434
|
+
reserve: true,
|
|
435
|
+
destroy_vm: false,
|
|
436
|
+
expected_file_id: 'node_test',
|
|
437
|
+
expected_sudo: true
|
|
438
|
+
)
|
|
439
|
+
if reserve || destroy_vm
|
|
440
|
+
# Mock querying reserve_proxmox_container
|
|
441
|
+
mock_call_to_reserve_proxmox_container(
|
|
442
|
+
proxmox_user: proxmox_user,
|
|
443
|
+
proxmox_password: proxmox_password,
|
|
444
|
+
proxmox_realm: proxmox_realm,
|
|
445
|
+
error_on_create: error_on_create,
|
|
446
|
+
error_on_destroy: error_on_destroy,
|
|
447
|
+
destroy_vm: destroy_vm,
|
|
448
|
+
expected_file_id: expected_file_id,
|
|
449
|
+
expected_sudo: expected_sudo
|
|
450
|
+
)
|
|
451
|
+
end
|
|
452
|
+
expect(::Proxmox::Proxmox).to receive(:new).exactly(calls.size).times do |url, pve_node, user, password, realm, options|
|
|
453
|
+
calls.shift.call(url, pve_node, user, password, realm, options)
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
# Mock the Proxmox API calls to map a given Proxmox status.
|
|
458
|
+
# Mock any call to the paths of the API to serve a given nodes information.
|
|
459
|
+
# Mock also calls to stop and destroy containers, and log those actions so that they can be checked by the test case later.
|
|
460
|
+
#
|
|
461
|
+
# Parameters::
|
|
462
|
+
# * *proxmox_user* (String): Proxmox user to be used for the API, or nil if none [default: nil]
|
|
463
|
+
# * *proxmox_password* (String): Proxmox password to be used for the API, or nil if none [default: nil]
|
|
464
|
+
# * *proxmox_realm* (String): Proxmox realm to be used for the API, or nil if none [default: 'pam']
|
|
465
|
+
# * *mocked_pve_nodes* (Array< Hash< String, Hash<Symbol,Object> > > or Hash< String, Hash<Symbol,Object> >):
|
|
466
|
+
# List of (or single) PVE node information, per PVE node name. [default: { 'pve_node_name' => {} }]
|
|
467
|
+
# If used as a list, it is expected that the Proxmox API be used as many times as the number of items in the list, and the mocked info will follow the list order.
|
|
468
|
+
# Here are the properties of a PVE node:
|
|
469
|
+
# * *loadavg* ([Float, Float, Float]): Load average of the node [default: [0.1, 0.2, 0.3]]
|
|
470
|
+
# * *memory_total* (Integer): Bytes of RAM of this PVE node [default: 16 * 1024 * 1024 * 1024]
|
|
471
|
+
# * *storage_total* (Integer): Bytes of disk of this PVE node [default: 100 * 1024 * 1024 * 1024]
|
|
472
|
+
# * *lxc_containers* (Hash<Integer, Hash<Symbol,Object> >): LXC containers info, per VM ID [default: {}]
|
|
473
|
+
# * *maxdisk* (Integer): Bytes of disk allocated to this VM [default: 1024 * 1024 * 1024]
|
|
474
|
+
# * *maxmem* (Integer): Bytes of RAM allocated to this VM [default: 1024 * 1024 * 1024]
|
|
475
|
+
# * *cpus* (Integer): CPUs allocated to this VM [default: 1]
|
|
476
|
+
# * *ip* (String): IP allocated to this node [default: 192.168.0.<vmid % 254 + 1>]
|
|
477
|
+
# * *status* (String): Status of this node [default: 'running']
|
|
478
|
+
# * *debug* (Boolean): Do we mark the VM as debug? [default: false]
|
|
479
|
+
# * *node* (String): Node for which this given container has been created [default: 'test_node']
|
|
480
|
+
# * *environment* (String): Environment for which this given container has been created [default: 'test_env']
|
|
481
|
+
def mock_proxmox(
|
|
482
|
+
proxmox_user: nil,
|
|
483
|
+
proxmox_password: nil,
|
|
484
|
+
proxmox_realm: 'pam',
|
|
485
|
+
mocked_pve_nodes: { 'pve_node_name' => {} }
|
|
486
|
+
)
|
|
487
|
+
# List of proxmox actions that have been mocked and their corresponding properties
|
|
488
|
+
# Array< [Symbol, Object] >
|
|
489
|
+
@proxmox_actions = []
|
|
490
|
+
mocked_pve_nodes = [mocked_pve_nodes] unless mocked_pve_nodes.is_a?(Array)
|
|
491
|
+
mock_proxmox_calls_with(
|
|
492
|
+
mocked_pve_nodes.map do |pve_nodes|
|
|
493
|
+
# Complete pve_nodes with default values
|
|
494
|
+
pve_nodes = Hash[pve_nodes.map do |pve_node_name, pve_node_info|
|
|
495
|
+
pve_node_info[:lxc_containers] = Hash[(pve_node_info.key?(:lxc_containers) ? pve_node_info[:lxc_containers] : {}).map do |vm_id, vm_info|
|
|
496
|
+
[
|
|
497
|
+
vm_id,
|
|
498
|
+
{
|
|
499
|
+
maxdisk: 1024 * 1024 * 1024,
|
|
500
|
+
maxmem: 1024 * 1024 * 1024,
|
|
501
|
+
cpus: 1,
|
|
502
|
+
ip: "192.168.0.#{(vm_id % 254) + 1}",
|
|
503
|
+
status: 'running',
|
|
504
|
+
creation_date: (Time.now - 60).utc,
|
|
505
|
+
debug: false,
|
|
506
|
+
node: 'test_node',
|
|
507
|
+
environment: 'test_env'
|
|
508
|
+
}.merge(vm_info)
|
|
509
|
+
]
|
|
510
|
+
end]
|
|
511
|
+
[
|
|
512
|
+
pve_node_name,
|
|
513
|
+
{
|
|
514
|
+
loadavg: [0.1, 0.2, 0.3],
|
|
515
|
+
memory_total: 16 * 1024 * 1024 * 1024,
|
|
516
|
+
storage_total: 100 * 1024 * 1024 * 1024
|
|
517
|
+
}.merge(pve_node_info)
|
|
518
|
+
]
|
|
519
|
+
end]
|
|
520
|
+
proc do |url, pve_node, user, password, realm, options|
|
|
521
|
+
expect(url).to eq 'https://my-proxmox.my-domain.com:8006/api2/json/'
|
|
522
|
+
expect(pve_node).to eq 'my-proxmox'
|
|
523
|
+
expect(user).to eq proxmox_user
|
|
524
|
+
expect(password).to eq proxmox_password
|
|
525
|
+
expect(realm).to eq proxmox_realm
|
|
526
|
+
expect(options[:verify_ssl]).to eq false
|
|
527
|
+
proxmox = double 'Proxmox create instance'
|
|
528
|
+
# Mock getting status of a container
|
|
529
|
+
allow(proxmox).to receive(:get) do |path|
|
|
530
|
+
case path
|
|
531
|
+
when 'nodes'
|
|
532
|
+
pve_nodes.keys.map { |pve_node_name| { 'node' => pve_node_name } }
|
|
533
|
+
when /^nodes\/([^\/]+)\/status$/
|
|
534
|
+
pve_node_name = $1
|
|
535
|
+
{
|
|
536
|
+
'loadavg' => pve_nodes[pve_node_name][:loadavg].map(&:to_s),
|
|
537
|
+
'memory' => {
|
|
538
|
+
'total' => pve_nodes[pve_node_name][:memory_total]
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
when /^nodes\/([^\/]+)\/storage$/
|
|
542
|
+
pve_node_name = $1
|
|
543
|
+
[
|
|
544
|
+
{
|
|
545
|
+
'storage' => 'local-lvm',
|
|
546
|
+
'total' => pve_nodes[pve_node_name][:storage_total]
|
|
547
|
+
}
|
|
548
|
+
]
|
|
549
|
+
when /^nodes\/([^\/]+)\/lxc$/
|
|
550
|
+
pve_node_name = $1
|
|
551
|
+
pve_nodes[pve_node_name][:lxc_containers].map do |vm_id, vm_info|
|
|
552
|
+
{
|
|
553
|
+
'vmid' => vm_id.to_s,
|
|
554
|
+
'maxdisk' => vm_info[:maxdisk],
|
|
555
|
+
'maxmem' => vm_info[:maxmem],
|
|
556
|
+
'cpus' => vm_info[:cpus]
|
|
557
|
+
}
|
|
558
|
+
end
|
|
559
|
+
when /^nodes\/([^\/]+)\/lxc\/([^\/]+)\/config$/
|
|
560
|
+
pve_node_name = $1
|
|
561
|
+
vmid = $2
|
|
562
|
+
{
|
|
563
|
+
'net0' => "ip=#{pve_nodes[pve_node_name][:lxc_containers][Integer(vmid)][:ip]}/32",
|
|
564
|
+
'description' => <<~EOS
|
|
565
|
+
===== HPC info =====
|
|
566
|
+
node: #{pve_nodes[pve_node_name][:lxc_containers][Integer(vmid)][:node]}
|
|
567
|
+
environment: #{pve_nodes[pve_node_name][:lxc_containers][Integer(vmid)][:environment]}
|
|
568
|
+
debug: #{pve_nodes[pve_node_name][:lxc_containers][Integer(vmid)][:debug] ? 'true' : 'false'}
|
|
569
|
+
creation_date: #{pve_nodes[pve_node_name][:lxc_containers][Integer(vmid)][:creation_date].strftime('%FT%T')}
|
|
570
|
+
EOS
|
|
571
|
+
}
|
|
572
|
+
when /^nodes\/([^\/]+)\/lxc\/([^\/]+)\/status\/current$/
|
|
573
|
+
pve_node_name = $1
|
|
574
|
+
vmid = $2
|
|
575
|
+
{
|
|
576
|
+
'status' => pve_nodes[pve_node_name][:lxc_containers][Integer(vmid)][:status]
|
|
577
|
+
}
|
|
578
|
+
when /^nodes\/([^\/]+)\/tasks\/([^\/]+)\/status$/
|
|
579
|
+
pve_node_name = $1
|
|
580
|
+
task = $2
|
|
581
|
+
# Mock tasks completion
|
|
582
|
+
{
|
|
583
|
+
'status' => 'OK'
|
|
584
|
+
}
|
|
585
|
+
else
|
|
586
|
+
raise "Unknown Proxmox API get call: #{path}. Please adapt the test framework."
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
# Mock some post actions
|
|
590
|
+
allow(proxmox).to receive(:post) do |path, args|
|
|
591
|
+
@proxmox_actions << [:post, path, args].compact
|
|
592
|
+
case path
|
|
593
|
+
when /^nodes\/([^\/]+)\/lxc$/
|
|
594
|
+
pve_node_name = $1
|
|
595
|
+
"UPID:#{pve_node_name}:0000A504:6DEABF24:5F44669B:create::root@pam:"
|
|
596
|
+
when /^nodes\/([^\/]+)\/lxc\/([^\/]+)\/status\/stop$/
|
|
597
|
+
pve_node_name = $1
|
|
598
|
+
vmid = $2
|
|
599
|
+
"UPID:#{pve_node_name}:0000A504:6DEABF24:5F44669B:stop_#{vmid}::root@pam:"
|
|
600
|
+
else
|
|
601
|
+
raise "Unknown Proxmox API post call: #{path}. Please adapt the test framework."
|
|
602
|
+
end
|
|
603
|
+
end
|
|
604
|
+
# Mock some delete actions
|
|
605
|
+
allow(proxmox).to receive(:delete) do |path|
|
|
606
|
+
@proxmox_actions << [:delete, path]
|
|
607
|
+
case path
|
|
608
|
+
when /^nodes\/([^\/]+)\/lxc\/([^\/]+)$/
|
|
609
|
+
pve_node_name = $1
|
|
610
|
+
vmid = $2
|
|
611
|
+
# Make sure we delete the mocked information as well
|
|
612
|
+
pve_nodes[pve_node_name][:lxc_containers].delete(Integer(vmid))
|
|
613
|
+
"UPID:#{pve_node_name}:0000A504:6DEABF24:5F44669B:destroy_#{vmid}::root@pam:"
|
|
614
|
+
else
|
|
615
|
+
raise "Unknown Proxmox API post call: #{path}. Please adapt the test framework."
|
|
616
|
+
end
|
|
617
|
+
end
|
|
618
|
+
proxmox
|
|
619
|
+
end
|
|
620
|
+
end,
|
|
621
|
+
reserve: false
|
|
622
|
+
)
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
# Prepare a repository to test reserve_proxmox_container
|
|
626
|
+
#
|
|
627
|
+
# Parameters::
|
|
628
|
+
# * Proc: Code to be called with repository setup
|
|
629
|
+
def with_sync_node
|
|
630
|
+
with_repository('sync_node') do |repository|
|
|
631
|
+
@repository = repository
|
|
632
|
+
yield
|
|
633
|
+
end
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
# Call the reserve_proxmox_container script using a given ARGV.
|
|
637
|
+
# Prerequisite: This is called within a with_sync_node session.
|
|
638
|
+
#
|
|
639
|
+
# Parameters::
|
|
640
|
+
# * *config* (Hash): Configuration overriding defaults to store in the config file [default: {}]
|
|
641
|
+
# * *max_retries* (Integer): Specify the max number of retries [default: 1]
|
|
642
|
+
# * *wait_before_retry* (Integer): Specify the number of seconds to wait before retry [default: 0]
|
|
643
|
+
# * *create* (Hash or nil): Create file content, or nil if none [default: nil]
|
|
644
|
+
# * *destroy* (Hash or nil): Destroy file content, or nil if none [default: nil]
|
|
645
|
+
# Result::
|
|
646
|
+
# * Hash: JSON result of the call
|
|
647
|
+
def call_reserve_proxmox_container_with(config: {}, max_retries: 1, wait_before_retry: 0, create: nil, destroy: nil)
|
|
648
|
+
# Make sure we set default values in the config
|
|
649
|
+
config = {
|
|
650
|
+
proxmox_api_url: 'https://my-proxmox.my-domain.com:8006',
|
|
651
|
+
futex_file: "#{@repository}/proxmox/allocations.futex",
|
|
652
|
+
logs_dir: "#{Dir.tmpdir}/hpc_test_proxmox_waiter_logs",
|
|
653
|
+
pve_nodes: ['pve_node_name'],
|
|
654
|
+
vm_ips_list: %w[
|
|
655
|
+
192.168.0.100
|
|
656
|
+
192.168.0.101
|
|
657
|
+
192.168.0.102
|
|
658
|
+
],
|
|
659
|
+
vm_ids_range: [1000, 1100],
|
|
660
|
+
coeff_ram_consumption: 10,
|
|
661
|
+
coeff_disk_consumption: 1,
|
|
662
|
+
expiration_period_secs: 24 * 60 * 60,
|
|
663
|
+
expire_stopped_vm_timeout_secs: 3,
|
|
664
|
+
limits: {
|
|
665
|
+
nbr_vms_max: 5,
|
|
666
|
+
cpu_loads_thresholds: [10, 10, 10],
|
|
667
|
+
ram_percent_used_max: 0.75,
|
|
668
|
+
disk_percent_used_max: 0.75
|
|
669
|
+
}
|
|
670
|
+
}.merge(config)
|
|
671
|
+
FileUtils.cp_r "#{__dir__}/../../../lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox", @repository
|
|
672
|
+
File.write("#{@repository}/proxmox/config.json", config.to_json)
|
|
673
|
+
script_args = [
|
|
674
|
+
'--max-retries', max_retries.to_s,
|
|
675
|
+
'--wait-before-retry', wait_before_retry.to_s
|
|
676
|
+
]
|
|
677
|
+
unless create.nil?
|
|
678
|
+
create_file = "#{@repository}/proxmox/create_vm.json"
|
|
679
|
+
File.write(create_file, create.to_json)
|
|
680
|
+
script_args.concat(['--create', create_file])
|
|
681
|
+
end
|
|
682
|
+
unless destroy.nil?
|
|
683
|
+
destroy_file = "#{@repository}/proxmox/destroy_vm.json"
|
|
684
|
+
File.write(destroy_file, destroy.to_json)
|
|
685
|
+
script_args.concat(['--destroy', destroy_file])
|
|
686
|
+
end
|
|
687
|
+
# Call the script by loading the Ruby file mocking the ARGV and ENV variables
|
|
688
|
+
old_argv = ARGV.dup
|
|
689
|
+
old_stdout = $stdout
|
|
690
|
+
ARGV.replace(script_args)
|
|
691
|
+
$stdout = StringIO.new unless logger.debug?
|
|
692
|
+
begin
|
|
693
|
+
load "#{@repository}/proxmox/reserve_proxmox_container"
|
|
694
|
+
if logger.debug?
|
|
695
|
+
raise 'This test can\'t run in debug mode.'
|
|
696
|
+
else
|
|
697
|
+
@stdout = $stdout.string
|
|
698
|
+
end
|
|
699
|
+
ensure
|
|
700
|
+
ARGV.replace old_argv
|
|
701
|
+
$stdout = old_stdout
|
|
702
|
+
end
|
|
703
|
+
stdout_lines = @stdout.split("\n")
|
|
704
|
+
JSON.parse(stdout_lines[stdout_lines.index('===== JSON =====') + 1..-1].join("\n")).transform_keys(&:to_sym)
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
# Call the reserve_proxmox_container script and get its result as JSON.
|
|
708
|
+
# Prerequisite: This is called within a with_sync_node session.
|
|
709
|
+
#
|
|
710
|
+
# Parameters::
|
|
711
|
+
# * *cpus* (Integer): Required CPUs
|
|
712
|
+
# * *ram_mb* (Integer): Required RAM MB
|
|
713
|
+
# * *disk_gb* (Integer): Required Disk GB
|
|
714
|
+
# * *config* (Hash): Configuration overriding defaults to store in the config file [default: {}]
|
|
715
|
+
# * *max_retries* (Integer): Specify the max number of retries [default: 1]
|
|
716
|
+
# * *wait_before_retry* (Integer): Specify the number of seconds to wait before retry [default: 0]
|
|
717
|
+
# Result::
|
|
718
|
+
# * Hash: JSON result of the call
|
|
719
|
+
def call_reserve_proxmox_container(cpus, ram_mb, disk_gb, config: {}, max_retries: 1, wait_before_retry: 0)
|
|
720
|
+
call_reserve_proxmox_container_with(
|
|
721
|
+
config: config,
|
|
722
|
+
max_retries: max_retries,
|
|
723
|
+
wait_before_retry: wait_before_retry,
|
|
724
|
+
create: {
|
|
725
|
+
ostemplate: 'test_template.iso',
|
|
726
|
+
hostname: 'test.hostname.my-domain.com',
|
|
727
|
+
description: "===== HPC info =====\nnode: test_node\nenvironment: test_env\n",
|
|
728
|
+
cores: cpus,
|
|
729
|
+
cpulimit: cpus,
|
|
730
|
+
memory: ram_mb,
|
|
731
|
+
rootfs: "local-lvm:#{disk_gb}",
|
|
732
|
+
net0: 'name=eth0,bridge=vmbr0,gw=172.16.16.16'
|
|
733
|
+
}
|
|
734
|
+
)
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
# Call the reserve_proxmox_container script to release a VM and get its result as JSON.
|
|
738
|
+
# Prerequisite: This is called within a with_sync_node session.
|
|
739
|
+
#
|
|
740
|
+
# Parameters::
|
|
741
|
+
# * *vm_id* (Integer): VM ID to release
|
|
742
|
+
# * *node* (String): Node for which the VM has been reserved
|
|
743
|
+
# * *environment* (String): Environment for which the VM has been reserved
|
|
744
|
+
# * *config* (Hash): Configuration overriding defaults to store in the config file [default: {}]
|
|
745
|
+
# * *max_retries* (Integer): Specify the max number of retries [default: 1]
|
|
746
|
+
# Result::
|
|
747
|
+
# * Hash: JSON result of the call
|
|
748
|
+
def call_release_proxmox_container(vm_id, node, environment, config: {}, max_retries: 1)
|
|
749
|
+
call_reserve_proxmox_container_with(
|
|
750
|
+
config: config,
|
|
751
|
+
max_retries: max_retries,
|
|
752
|
+
destroy: {
|
|
753
|
+
vm_id: vm_id,
|
|
754
|
+
node: node,
|
|
755
|
+
environment: environment
|
|
756
|
+
}
|
|
757
|
+
)
|
|
758
|
+
end
|
|
759
|
+
|
|
760
|
+
# Expect a list of Proxmox API calls to match a given list.
|
|
761
|
+
# Handle Regexp in the expectation.
|
|
762
|
+
#
|
|
763
|
+
# Parameters::
|
|
764
|
+
# * *expected_proxmox_actions* (Array<Array>): Expected Proxmox actions
|
|
765
|
+
def expect_proxmox_actions_to_be(expected_proxmox_actions)
|
|
766
|
+
expect(@proxmox_actions.size).to eq expected_proxmox_actions.size
|
|
767
|
+
@proxmox_actions.zip(expected_proxmox_actions).each do |proxmox_action, expected_proxmox_action|
|
|
768
|
+
expect(proxmox_action.size).to eq expected_proxmox_action.size
|
|
769
|
+
expect(proxmox_action[0..1]).to eq expected_proxmox_action[0..1]
|
|
770
|
+
if proxmox_action.size >= 3
|
|
771
|
+
# The third argument is a Hash that might have Regexp in the expectation
|
|
772
|
+
expect(proxmox_action[2].keys.sort).to eq expected_proxmox_action[2].keys.sort
|
|
773
|
+
proxmox_action[2].each do |property, value|
|
|
774
|
+
expected_value = expected_proxmox_action[2][property]
|
|
775
|
+
if expected_value.is_a?(Regexp)
|
|
776
|
+
expect(value).to match expected_value
|
|
777
|
+
else
|
|
778
|
+
expect(value).to eq expected_value
|
|
779
|
+
end
|
|
780
|
+
end
|
|
781
|
+
end
|
|
782
|
+
end
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
end
|
|
786
|
+
|
|
787
|
+
end
|
|
788
|
+
|
|
789
|
+
end
|