hybrid_platforms_conductor 32.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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