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,101 @@
1
+ require 'hybrid_platforms_conductor/logger_helpers'
2
+
3
+ module HybridPlatformsConductor
4
+
5
+ # Give a simple and harmonized way to access to plugins, whether they are in the common repository or in other gems
6
+ class Plugins
7
+
8
+ include LoggerHelpers
9
+
10
+ # Make sure we can iterate over plugins like a standard collection
11
+ include Enumerable
12
+
13
+ # Constructor
14
+ #
15
+ # Parameters::
16
+ # * *plugins_type* (Symbol): Plugins type to look for
17
+ # * *init_plugin* (Proc or nil): Proc used to initialize the plugin from the plugin class, or nil if no initialization [default: nil]
18
+ # * Parameters::
19
+ # * *plugin_class* (Class): The plugin class that has been found
20
+ # * Result::
21
+ # * Object: Corresponding object that will be used as the plugin instance
22
+ # * *parse_gems* (Boolean): Do we parse plugins from gems? [default: true]
23
+ # * *logger* (Logger): Logger to be used [default = Logger.new(STDOUT)]
24
+ # * *logger_stderr* (Logger): Logger to be used for stderr [default = Logger.new(STDERR)]
25
+ def initialize(plugins_type, init_plugin: nil, parse_gems: true, logger: Logger.new(STDOUT), logger_stderr: Logger.new(STDERR))
26
+ init_loggers(logger, logger_stderr)
27
+ @plugins_type = plugins_type
28
+ @init_plugin = init_plugin
29
+ # All the plugins classes we know of this type, per plugin ID
30
+ # Hash<Symbol, Class>
31
+ @plugins = {}
32
+ register_plugins_from_gems if parse_gems
33
+ end
34
+
35
+ # Make an API similar to a Hash, delegated to @plugins
36
+ extend Forwardable
37
+ def_delegators :@plugins, *%i[
38
+ []
39
+ each
40
+ empty?
41
+ key?
42
+ keys
43
+ select
44
+ to_hash
45
+ values
46
+ ]
47
+
48
+ # Register a new plugin
49
+ #
50
+ # Parameters::
51
+ # * *plugin_id* (Symbol): The plugin ID to register
52
+ # * *plugin_class* (Class): The corresponding plugin class
53
+ def []=(plugin_id, plugin_class)
54
+ if @plugins.key?(plugin_id)
55
+ log_warn "[ #{@plugins_type} ] - A plugin of type #{@plugins_type} named #{plugin_id} is already registered. Can't overwrite #{@plugins[plugin_id]} with #{plugin_class.name}. Will ignore #{plugin_class.name}."
56
+ else
57
+ # Set the logger in the class so that we can use it in class methods
58
+ plugin_class.logger = @logger
59
+ plugin_class.logger_stderr = @logger_stderr
60
+ if plugin_class.valid?
61
+ log_debug "[ #{@plugins_type} ] - Register #{plugin_id} to #{plugin_class.name}."
62
+ @plugins[plugin_id] = @init_plugin.nil? ? plugin_class : @init_plugin.call(plugin_class)
63
+ else
64
+ log_error "[ #{@plugins_type} ] - The plugin #{plugin_id} (#{plugin_class.name}) is missing some dependencies to be activated. Will ignore it."
65
+ end
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ # Register plugins by parsing gems
72
+ def register_plugins_from_gems
73
+ # Require all possible files that could define such a plugin, from all gems
74
+ files_regexp = /lib\/(.*hpc_plugins\/#{Regexp.escape(@plugins_type.to_s)}\/[^\/]+)\.rb$/
75
+ Gem.loaded_specs.each do |gem_name, gem_specs|
76
+ # Careful to not use gem_specs.files here as if your gem name contains "-" or other weird characters, files won't appear in the gemspec list.
77
+ Dir.glob("#{gem_specs.full_gem_path}/lib/**/*.rb").each do |file|
78
+ if file =~ files_regexp
79
+ require_name = $1
80
+ log_debug "[ #{@plugins_type} ] - Require from #{gem_name} file #{require_name}"
81
+ require require_name
82
+ end
83
+ end
84
+ end
85
+ # Parse the registered classes to search for our plugins
86
+ ancestor_class = HybridPlatformsConductor.const_get(@plugins_type.to_s.split('_').collect(&:capitalize).join.to_sym)
87
+ ObjectSpace.each_object(Class).each do |klass|
88
+ # Only select classes that:
89
+ # * have been defined by the requires (no unnamed class, as those can be created by clones when using concurrency),
90
+ # * inherit from the base plugin class,
91
+ # * have no descendants
92
+ if !klass.name.nil? && klass < ancestor_class && ObjectSpace.each_object(Class).all? { |other_klass| other_klass.name.nil? || !(other_klass < klass) }
93
+ plugin_id = klass.name.split('::').last.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase.to_sym
94
+ self[plugin_id] = klass
95
+ end
96
+ end
97
+ end
98
+
99
+ end
100
+
101
+ end
@@ -0,0 +1,181 @@
1
+ require 'hybrid_platforms_conductor/logger_helpers'
2
+ require 'hybrid_platforms_conductor/plugin'
3
+
4
+ module HybridPlatformsConductor
5
+
6
+ # Base class for any provisioner
7
+ class Provisioner < Plugin
8
+
9
+ include LoggerHelpers
10
+
11
+ # Constructor
12
+ #
13
+ # Parameters::
14
+ # * *node* (String): Node for which we provision a running instance
15
+ # * *environment* (String): Environment for which this running instance is provisioned [default: 'production']
16
+ # * *logger* (Logger): Logger to be used [default: Logger.new(STDOUT)]
17
+ # * *logger_stderr* (Logger): Logger to be used for stderr [default: Logger.new(STDERR)]
18
+ # * *config* (Config): Config to be used. [default: Config.new]
19
+ # * *cmd_runner* (CmdRunner): Command executor to be used. [default: CmdRunner.new]
20
+ # * *nodes_handler* (NodesHandler): Nodes handler to be used. [default: NodesHandler.new]
21
+ # * *actions_executor* (ActionsExecutor): Actions Executor to be used. [default: ActionsExecutor.new]
22
+ def initialize(
23
+ node,
24
+ environment: 'production',
25
+ logger: Logger.new(STDOUT),
26
+ logger_stderr: Logger.new(STDERR),
27
+ config: Config.new,
28
+ cmd_runner: CmdRunner.new,
29
+ nodes_handler: NodesHandler.new,
30
+ actions_executor: ActionsExecutor.new
31
+ )
32
+ super(logger: logger, logger_stderr: logger_stderr, config: config)
33
+ @node = node
34
+ @environment = environment
35
+ @cmd_runner = cmd_runner
36
+ @nodes_handler = nodes_handler
37
+ @actions_executor = actions_executor
38
+ end
39
+
40
+ # Return the default timeout to apply when waiting for an instance to be started/stopped...
41
+ #
42
+ # Result::
43
+ # * Integer: The timeout in seconds
44
+ def default_timeout
45
+ 60
46
+ end
47
+
48
+ # Provision a running instance for the needed node and environment.
49
+ # If the instance is already created, re-uses it.
50
+ # If the instance is already running, re-uses it.
51
+ # Enriches the nodes handler information with the instance metadata as well.
52
+ # Calls client code only when the instance is up and running, and fail otherwise.
53
+ #
54
+ # Parameters::
55
+ # * *stop_on_exit* (Boolean): Do we stop the instance when exiting? [default: false]
56
+ # * *destroy_on_exit* (Boolean): Do we destroy the instance when exiting? Ignored if stop_on_exit is false [default: false]
57
+ # * *port* (Integer or nil): Port to wait to be opened, or nil if none [default: nil]
58
+ # * Proc: Client code called with the instance up and running
59
+ def with_running_instance(stop_on_exit: false, destroy_on_exit: false, port: nil)
60
+ log_debug "[ #{@node}/#{@environment} ] - Create instance..."
61
+ create
62
+ begin
63
+ wait_for_state!(%i[running created exited])
64
+ if %i[created exited].include?(state)
65
+ log_debug "[ #{@node}/#{@environment} ] - Start instance..."
66
+ start
67
+ end
68
+ begin
69
+ wait_for_state!(:running)
70
+ instance_ip = ip
71
+ if instance_ip.nil?
72
+ log_debug "[ #{@node}/#{@environment} ] - No host_ip linked to the instance."
73
+ elsif instance_ip != @nodes_handler.get_host_ip_of(@node)
74
+ log_debug "[ #{@node}/#{@environment} ] - Set host_ip to #{instance_ip}."
75
+ # The instance is running on an IP that is not the one registered by default in the metadata.
76
+ # Make sure we update it.
77
+ @nodes_handler.override_metadata_of @node, :host_ip, instance_ip
78
+ @nodes_handler.invalidate_metadata_of @node, :host_keys
79
+ end
80
+ wait_for_port!(port) if port
81
+ yield
82
+ ensure
83
+ if stop_on_exit
84
+ log_debug "[ #{@node}/#{@environment} ] - Stop instance..."
85
+ stop
86
+ wait_for_state!(:exited)
87
+ end
88
+ end
89
+ ensure
90
+ if stop_on_exit && destroy_on_exit
91
+ log_debug "[ #{@node}/#{@environment} ] - Destroy instance..."
92
+ destroy
93
+ end
94
+ end
95
+ end
96
+
97
+ # Wait for an instance to be in a given state.
98
+ #
99
+ # Parameters::
100
+ # * *states* (Symbol or Array<Symbol>): States (or single state) the instance should be in
101
+ # * *timeout* (Integer): Timeout before failing, in seconds [default = default_timeout]
102
+ # Result::
103
+ # * Boolean: Is the instance in one of the expected states?
104
+ def wait_for_state(states, timeout = default_timeout)
105
+ states = [states] unless states.is_a?(Array)
106
+ log_debug "[ #{@node}/#{@environment} ] - Wait for instance to be in state #{states.join(', ')} (timeout #{timeout})..."
107
+ current_state = nil
108
+ remaining_timeout = timeout
109
+ until states.include?(current_state)
110
+ start_time = Time.now
111
+ current_state = state
112
+ sleep 1 unless states.include?(current_state)
113
+ remaining_timeout -= Time.now - start_time
114
+ break if remaining_timeout <= 0
115
+ end
116
+ log_debug "[ #{@node}/#{@environment} ] - Instance is in state #{current_state}"
117
+ states.include?(current_state)
118
+ end
119
+
120
+ # Wait for an instance to be in a given state, and fail if it can't.
121
+ #
122
+ # Parameters::
123
+ # * *states* (Symbol or Array<Symbol>): States (or single state) the instance should be in
124
+ # * *timeout* (Integer): Timeout before failing, in seconds [default = default_timeout]
125
+ def wait_for_state!(states, timeout = default_timeout)
126
+ states = [states] unless states.is_a?(Array)
127
+ raise "[ #{@node}/#{@environment} ] - Instance fails to be in a state among (#{states.join(', ')}) with timeout #{timeout}. Currently in state #{state}" unless wait_for_state(states, timeout)
128
+ end
129
+
130
+ # Wait for a given ip/port to be listening before continuing.
131
+ #
132
+ # Parameters::
133
+ # * *port* (Integer): Port to wait for
134
+ # * *timeout* (Integer): Timeout before failing, in seconds [default = default_timeout]
135
+ # Result::
136
+ # * Boolean: Is port listening?
137
+ def wait_for_port(port, timeout = default_timeout)
138
+ instance_ip = ip
139
+ log_debug "[ #{@node}/#{@environment} ] - Wait for #{instance_ip}:#{port} to be opened (timeout #{timeout})..."
140
+ port_listening = false
141
+ remaining_timeout = timeout
142
+ until port_listening
143
+ start_time = Time.now
144
+ port_listening =
145
+ begin
146
+ Socket.tcp(instance_ip, port, connect_timeout: remaining_timeout) { true }
147
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::EADDRNOTAVAIL, Errno::ETIMEDOUT
148
+ log_warn "[ #{@node}/#{@environment} ] - Can't connect to #{instance_ip}:#{port}: #{$!}"
149
+ false
150
+ end
151
+ sleep 1 unless port_listening
152
+ remaining_timeout -= Time.now - start_time
153
+ break if remaining_timeout <= 0
154
+ end
155
+ log_debug "[ #{@node}/#{@environment} ] - #{instance_ip}:#{port} is#{port_listening ? '' : ' not'} opened."
156
+ port_listening
157
+ end
158
+
159
+ # Wait for a given ip/port to be listening before continuing.
160
+ # Fail if it does not listen.
161
+ #
162
+ # Parameters::
163
+ # * *port* (Integer): Port to wait for
164
+ # * *timeout* (Integer): Timeout before failing, in seconds [default = default_timeout]
165
+ def wait_for_port!(port, timeout = default_timeout)
166
+ raise "[ #{@node}/#{@environment} ] - Instance fails to have port #{port} opened with timeout #{timeout}." unless wait_for_port(port, timeout)
167
+ end
168
+
169
+ # Return the IP address of an instance.
170
+ # Prerequisite: create has been called before.
171
+ # [API] - This method is optional
172
+ #
173
+ # Result::
174
+ # * String or nil: The instance IP address, or nil if this information is not relevant
175
+ def ip
176
+ nil
177
+ end
178
+
179
+ end
180
+
181
+ end
@@ -0,0 +1,31 @@
1
+ require 'hybrid_platforms_conductor/logger_helpers'
2
+ require 'hybrid_platforms_conductor/plugin'
3
+
4
+ module HybridPlatformsConductor
5
+
6
+ # Ancestor of all report plugins
7
+ class Report < Plugin
8
+
9
+ # Constructor
10
+ #
11
+ # Parameters::
12
+ # * *logger* (Logger): Logger to be used [default: Logger.new(STDOUT)]
13
+ # * *logger_stderr* (Logger): Logger to be used for stderr [default: Logger.new(STDERR)]
14
+ # * *config* (Config): Config to be used. [default: Config.new]
15
+ # * *platforms_handler* (PlatformsHandler): Platforms handler to be used. [default: PlatformsHandler.new]
16
+ # * *nodes_handler* (NodesHandler): Nodes handler to be used. [default: NodesHandler.new]
17
+ def initialize(
18
+ logger: Logger.new(STDOUT),
19
+ logger_stderr: Logger.new(STDERR),
20
+ config: Config.new,
21
+ platforms_handler: PlatformsHandler.new,
22
+ nodes_handler: NodesHandler.new
23
+ )
24
+ super(logger: logger, logger_stderr: logger_stderr, config: config)
25
+ @platforms_handler = platforms_handler
26
+ @nodes_handler = nodes_handler
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,84 @@
1
+ require 'logger'
2
+ require 'hybrid_platforms_conductor/logger_helpers'
3
+ require 'hybrid_platforms_conductor/plugins'
4
+
5
+ module HybridPlatformsConductor
6
+
7
+ # Gives ways to produce reports
8
+ class ReportsHandler
9
+
10
+ include LoggerHelpers
11
+
12
+ # Format in which the reports handler will provide reports
13
+ # Symbol
14
+ attr_accessor :format
15
+
16
+ # Locale in which the reports handler will provide reports
17
+ # Symbol
18
+ attr_accessor :locale
19
+
20
+ # Constructor
21
+ #
22
+ # Parameters::
23
+ # * *logger* (Logger): Logger to be used [default: Logger.new(STDOUT)]
24
+ # * *logger_stderr* (Logger): Logger to be used for stderr [default: Logger.new(STDERR)]
25
+ # * *config* (Config): Config to be used. [default: Config.new]
26
+ # * *platforms_handler* (PlatformsHandler): Platforms handler to be used. [default = PlatformsHandler.new]
27
+ # * *nodes_handler* (NodesHandler): Nodes handler to be used. [default = NodesHandler.new]
28
+ def initialize(
29
+ logger: Logger.new(STDOUT),
30
+ logger_stderr: Logger.new(STDERR),
31
+ config: Config.new,
32
+ platforms_handler: PlatformsHandler.new,
33
+ nodes_handler: NodesHandler.new
34
+ )
35
+ init_loggers(logger, logger_stderr)
36
+ @config = config
37
+ @platforms_handler = platforms_handler
38
+ @nodes_handler = nodes_handler
39
+ @platforms_handler.inject_dependencies(nodes_handler: @nodes_handler, actions_executor: nil)
40
+ # The list of reports plugins, with their associated class
41
+ # Hash< Symbol, Class >
42
+ @reports_plugins = Plugins.new(:report, logger: @logger, logger_stderr: @logger_stderr)
43
+ @format = :stdout
44
+ @locale = @reports_plugins[@format].supported_locales.first
45
+ end
46
+
47
+ # Complete an option parser with options meant to control this Reports handler
48
+ #
49
+ # Parameters::
50
+ # * *options_parser* (OptionParser): The option parser to complete
51
+ def options_parse(options_parser)
52
+ options_parser.separator ''
53
+ options_parser.separator 'Reports handler options:'
54
+ options_parser.on('-c', '--locale LOCALE_CODE', "Generate the report in the given format. Possible codes are formats specific. #{@reports_plugins.map { |format, klass| "[#{format}: #{klass.supported_locales.join(', ')}]" }.join(', ')}") do |str_locale|
55
+ @locale = str_locale.to_sym
56
+ end
57
+ options_parser.on('-f', '--format FORMAT', "Generate the report in the given format. Possible formats are #{@reports_plugins.keys.sort.join(', ')}. Default: #{@format}.") do |str_format|
58
+ @format = str_format.to_sym
59
+ end
60
+ end
61
+
62
+ # Validate that parsed parameters are valid
63
+ def validate_params
64
+ raise "Unknown format: #{@format}" unless @reports_plugins.keys.include? @format
65
+ end
66
+
67
+ # Produce a report for a given list of nodes selectors
68
+ #
69
+ # Parameters::
70
+ # * *nodes_selectors* (Array<Object>): List of nodes selectors to produce report for
71
+ def produce_report_for(nodes_selectors)
72
+ raise "Unknown locale for format #{@format}: #{@locale}" unless @reports_plugins[@format].supported_locales.include? @locale
73
+ @reports_plugins[@format].new(
74
+ logger: @logger,
75
+ logger_stderr: @logger_stderr,
76
+ config: @config,
77
+ platforms_handler: @platforms_handler,
78
+ nodes_handler: @nodes_handler
79
+ ).report_for(@nodes_handler.select_nodes(nodes_selectors), @locale)
80
+ end
81
+
82
+ end
83
+
84
+ end
@@ -0,0 +1,274 @@
1
+ require 'git'
2
+ require 'hybrid_platforms_conductor/cmd_runner'
3
+ require 'hybrid_platforms_conductor/cmdb'
4
+ require 'hybrid_platforms_conductor/logger_helpers'
5
+ require 'hybrid_platforms_conductor/parallel_threads'
6
+ require 'hybrid_platforms_conductor/platform_handler'
7
+
8
+ module HybridPlatformsConductor
9
+
10
+ # API around the services that can be deployed
11
+ class ServicesHandler
12
+
13
+ class << self
14
+
15
+ # List of deployments that have been packaged.
16
+ # Each deployment has the following info:
17
+ # * *platform_name* (String): The platform name
18
+ # * *services* (Hash< String, Array<String> >): Services to be deployed, per node
19
+ # * *secrets* (Hash): Secrets for which this has been packaged
20
+ # * *local_environment* (Boolean): Has it been packaged for local environment?
21
+ # Make this at class level as several Deployer instances can be used in a multi-thread environmnent.
22
+ # Array< Hash<Symbol, Object> >
23
+ attr_reader :packaged_deployments
24
+
25
+ end
26
+
27
+ @packaged_deployments = []
28
+
29
+ include LoggerHelpers, ParallelThreads
30
+
31
+ # Constructor
32
+ #
33
+ # Parameters::
34
+ # * *logger* (Logger): Logger to be used [default: Logger.new(STDOUT)]
35
+ # * *logger_stderr* (Logger): Logger to be used for stderr [default: Logger.new(STDERR)]
36
+ # * *config* (Config): Config to be used. [default: Config.new]
37
+ # * *cmd_runner* (CmdRunner): Command executor to be used. [default: CmdRunner.new]
38
+ # * *platforms_handler* (PlatformsHandler): Platforms Handler to be used. [default: PlatformsHandler.new]
39
+ # * *nodes_handler* (NodesHandler): Nodes Handler to be used. [default: NodesHandler.new]
40
+ # * *actions_executor* (ActionsExecutor): Actions Executor to be used. [default: ActionsExecutor.new]
41
+ def initialize(
42
+ logger: Logger.new(STDOUT),
43
+ logger_stderr: Logger.new(STDERR),
44
+ config: Config.new,
45
+ cmd_runner: CmdRunner.new,
46
+ platforms_handler: PlatformsHandler.new,
47
+ nodes_handler: NodesHandler.new,
48
+ actions_executor: ActionsExecutor.new
49
+ )
50
+ init_loggers(logger, logger_stderr)
51
+ @config = config
52
+ @cmd_runner = cmd_runner
53
+ @platforms_handler = platforms_handler
54
+ @nodes_handler = nodes_handler
55
+ @actions_executor = actions_executor
56
+ @platforms_handler.inject_dependencies(nodes_handler: @nodes_handler, actions_executor: @actions_executor)
57
+ end
58
+
59
+ # Are we allowed to deploy?
60
+ # This checks eventual restrictions on deployments, considering environments, options, secrets...
61
+ #
62
+ # Parameters::
63
+ # * *services* (Hash< String, Array<String> >): Services to be deployed, per node
64
+ # * *secrets* (Hash): Secrets to be used for deployment
65
+ # * *local_environment* (Boolean): Are we deploying to a local environment?
66
+ # Result::
67
+ # * String or nil: Reason for which we are not allowed to deploy, or nil if deployment is authorized
68
+ def deploy_allowed?(
69
+ services:,
70
+ secrets:,
71
+ local_environment:
72
+ )
73
+ if local_environment
74
+ nil
75
+ else
76
+ # Check that master is checked out correctly before deploying.
77
+ # Check it on every platform having at least 1 node to be deployed.
78
+ wrong_platforms = platforms_for(services).keys.select do |platform|
79
+ git = nil
80
+ begin
81
+ git = Git.open(platform.repository_path)
82
+ rescue
83
+ log_debug "Platform #{platform.repository_path} is not a git repository"
84
+ end
85
+ if git.nil?
86
+ false
87
+ else
88
+ head_commit_id = git.log.first.sha
89
+ git.branches.all? do |branch|
90
+ branch.gcommit.objectish.include?(' -> ') || (
91
+ !(branch.full == 'master' || branch.full =~ /^remotes\/.+\/master$/) || branch.gcommit.sha != head_commit_id
92
+ )
93
+ end
94
+ end
95
+ end
96
+ if wrong_platforms.empty?
97
+ nil
98
+ else
99
+ "The following platforms have not checked out master: #{wrong_platforms.map(&:repository_path).join(', ')}. Only master should be deployed in production."
100
+ end
101
+ end
102
+ end
103
+
104
+ # Package a configuration for a given deployment
105
+ #
106
+ # Parameters::
107
+ # * *services* (Hash< String, Array<String> >): Services to be deployed, per node
108
+ # * *secrets* (Hash): Secrets to be used for deployment
109
+ # * *local_environment* (Boolean): Are we deploying to a local environment?
110
+ def package(
111
+ services:,
112
+ secrets:,
113
+ local_environment:
114
+ )
115
+ platforms_for(services).each do |platform, platform_services|
116
+ platform_name = platform.name
117
+ deployment_info = {
118
+ platform_name: platform_name,
119
+ services: platform_services,
120
+ secrets: secrets,
121
+ local_environment: local_environment
122
+ }
123
+ if ServicesHandler.packaged_deployments.include?(deployment_info)
124
+ log_debug "Platform #{platform_name} has already been packaged for this deployment. Won't package it another time."
125
+ else
126
+ platform.package(
127
+ services: platform_services,
128
+ secrets: secrets,
129
+ local_environment: local_environment
130
+ )
131
+ ServicesHandler.packaged_deployments << deployment_info
132
+ end
133
+ end
134
+ end
135
+
136
+ # Prepare the deployment to be performed
137
+ #
138
+ # Parameters::
139
+ # * *services* (Hash< String, Array<String> >): Services to be deployed, per node
140
+ # * *secrets* (Hash): Secrets to be used for deployment
141
+ # * *local_environment* (Boolean): Are we deploying to a local environment?
142
+ # * *why_run* (Boolean): Are we deploying in why-run mode?
143
+ def prepare_for_deploy(
144
+ services:,
145
+ secrets:,
146
+ local_environment:,
147
+ why_run:
148
+ )
149
+ platforms_for(services).each do |platform, platform_services|
150
+ platform.prepare_for_deploy(
151
+ services: platform_services,
152
+ secrets: secrets,
153
+ local_environment: local_environment,
154
+ why_run: why_run
155
+ ) if platform.respond_to?(:prepare_for_deploy)
156
+ end
157
+ end
158
+
159
+ # Get actions to be executed to deploy services to a node
160
+ #
161
+ # Parameters::
162
+ # * *node* (String): The node to be deployed
163
+ # * *services* (Array<String>): List of services to deploy on this node
164
+ # * *why_run* (Boolean): Are we in why-run mode?
165
+ # Result::
166
+ # * Array< Hash<Symbol,Object> >: List of actions to be done
167
+ def actions_to_deploy_on(node, services, why_run)
168
+ services.map do |service|
169
+ platform = @platforms_handler.known_platforms.find { |platform| platform.deployable_services.include?(service) }
170
+ raise "No platform is able to deploy the service #{service}" if platform.nil?
171
+ # Add some markers in stdout and stderr so that parsing services-oriented deployment output is easier
172
+ deploy_marker = "===== [ #{node} / #{service} ] - HPC Service #{why_run ? 'Check' : 'Deploy' } ====="
173
+ [{
174
+ ruby: proc do |stdout, stderr|
175
+ stdout << "#{deploy_marker} Begin\n"
176
+ stderr << "#{deploy_marker} Begin\n"
177
+ end
178
+ }] +
179
+ platform.actions_to_deploy_on(node, service, use_why_run: why_run) +
180
+ [{
181
+ ruby: proc do |stdout, stderr|
182
+ stdout << "#{deploy_marker} End\n"
183
+ stderr << "#{deploy_marker} End\n"
184
+ end
185
+ }]
186
+ end.flatten
187
+ end
188
+
189
+ # Get some information to be logged regarding a deployment of services on a node
190
+ #
191
+ # Parameters::
192
+ # * *node* (String): The node for which we get the info
193
+ # * *services* (Array<String>): Services that have been deployed on this node
194
+ # Result::
195
+ # * Hash<Symbol,Object>: Information to be added to the deployment logs
196
+ def log_info_for(node, services)
197
+ log_info = {}
198
+ # Get all platforms involved in the deployment of those services on this node
199
+ platforms_for(node => services).keys.each.with_index do |platform, platform_idx|
200
+ log_info.merge!(
201
+ "repo_name_#{platform_idx}".to_sym => platform.name
202
+ )
203
+ if platform.info.key?(:commit)
204
+ log_info.merge!(
205
+ "commit_id_#{platform_idx}".to_sym => platform.info[:commit][:id],
206
+ "commit_message_#{platform_idx}".to_sym => platform.info[:commit][:message].split("\n").first,
207
+ "diff_files_#{platform_idx}".to_sym => (platform.info[:status][:changed_files] + platform.info[:status][:added_files] + platform.info[:status][:deleted_files] + platform.info[:status][:untracked_files]).join(', ')
208
+ )
209
+ end
210
+ end
211
+ log_info
212
+ end
213
+
214
+ # Regexp: The marker regexp used to separate services deployment
215
+ MARKER_REGEXP = /^===== \[ (.+?) \/ (.+?) \] - HPC Service (\w+) ===== Begin$(.+?)^===== \[ \1 \/ \2 \] - HPC Service \3 ===== End$/m
216
+
217
+ # Parse stdout and stderr of a given deploy run and get the list of tasks with their status, organized per service and node deployed.
218
+ #
219
+ # Parameters::
220
+ # * *stdout* (String): stdout to be parsed.
221
+ # * *stderr* (String): stderr to be parsed.
222
+ # Result::
223
+ # * Array< Hash<Symbol,Object> >: List of deployed services (in the order of the logs). Here are the returned properties:
224
+ # * *node* (String): Node that has been deployed
225
+ # * *service* (String): Service that has been deployed
226
+ # * *check* (Boolean): Has the service been deployed in check-mode?
227
+ # * *tasks* (Array< Hash<Symbol,Object> >): List of task properties. The following properties should be returned, among free ones:
228
+ # * *name* (String): Task name
229
+ # * *status* (Symbol): Task status. Should be on of:
230
+ # * *:changed*: The task has been changed
231
+ # * *:identical*: The task has not been changed
232
+ # * *diffs* (String): Differences, if any
233
+ def parse_deploy_output(stdout, stderr)
234
+ stdout.scan(MARKER_REGEXP).zip(stderr.scan(MARKER_REGEXP)).map do |((stdout_node, stdout_service, stdout_mode, stdout_logs), (stderr_node, stderr_service, stderr_mode, stderr_logs))|
235
+ # Some consistency checking
236
+ log_warn "Mismatch in deployment logs between stdout and stderr: stdout deployed node #{stdout_node}, stderr deployed node #{stderr_node}" unless stdout_node == stderr_node
237
+ log_warn "Mismatch in deployment logs between stdout and stderr: stdout deployed service #{stdout_service}, stderr deployed service #{stderr_service}" unless stdout_service == stderr_service
238
+ log_warn "Mismatch in deployment logs between stdout and stderr: stdout deployed mode is #{stdout_mode}, stderr deployed mode is #{stderr_mode}" unless stdout_mode == stderr_mode
239
+ platform = @platforms_handler.known_platforms.find { |platform| platform.deployable_services.include?(stdout_service) }
240
+ raise "No platform is able to deploy the service #{stdout_service}" if platform.nil?
241
+ {
242
+ node: stdout_node,
243
+ service: stdout_service,
244
+ check: stdout_mode == 'Check',
245
+ tasks: platform.parse_deploy_output(stdout_logs, stderr_logs || '')
246
+ }
247
+ end
248
+ end
249
+
250
+ private
251
+
252
+ # Get platforms concerned by a list of services to be deployed per node
253
+ #
254
+ # Parameters::
255
+ # * *services* (Hash< String, Array<String> >): Services to be deployed, per node
256
+ # Result::
257
+ # * Hash< PlatformHandler, Hash< String, Array<String> > >: List of services to be deployed, per node, per PlatformHandler handling those services
258
+ def platforms_for(services)
259
+ concerned_platforms = {}
260
+ @platforms_handler.known_platforms.each do |platform|
261
+ deployable_nodes = {}
262
+ platform_services = platform.deployable_services
263
+ services.each do |node, node_services|
264
+ node_deployable_services = platform_services & node_services
265
+ deployable_nodes[node] = node_deployable_services unless node_deployable_services.empty?
266
+ end
267
+ concerned_platforms[platform] = deployable_nodes unless deployable_nodes.empty?
268
+ end
269
+ concerned_platforms
270
+ end
271
+
272
+ end
273
+
274
+ end