hybrid_platforms_conductor 32.3.6

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