hybrid_platforms_conductor 32.3.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|