hybrid_platforms_conductor 32.3.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (244) hide show
  1. checksums.yaml +7 -0
  2. data/bin/check-node +24 -0
  3. data/bin/deploy +12 -0
  4. data/bin/dump_nodes_json +12 -0
  5. data/bin/free_ips +23 -0
  6. data/bin/free_veids +17 -0
  7. data/bin/get_impacted_nodes +43 -0
  8. data/bin/last_deploys +56 -0
  9. data/bin/nodes_to_deploy +104 -0
  10. data/bin/report +10 -0
  11. data/bin/run +39 -0
  12. data/bin/setup +11 -0
  13. data/bin/ssh_config +14 -0
  14. data/bin/test +13 -0
  15. data/bin/topograph +54 -0
  16. data/lib/hybrid_platforms_conductor/action.rb +82 -0
  17. data/lib/hybrid_platforms_conductor/actions_executor.rb +307 -0
  18. data/lib/hybrid_platforms_conductor/bitbucket.rb +123 -0
  19. data/lib/hybrid_platforms_conductor/cmd_runner.rb +188 -0
  20. data/lib/hybrid_platforms_conductor/cmdb.rb +34 -0
  21. data/lib/hybrid_platforms_conductor/common_config_dsl/bitbucket.rb +78 -0
  22. data/lib/hybrid_platforms_conductor/common_config_dsl/confluence.rb +43 -0
  23. data/lib/hybrid_platforms_conductor/common_config_dsl/file_system_tests.rb +110 -0
  24. data/lib/hybrid_platforms_conductor/common_config_dsl/idempotence_tests.rb +38 -0
  25. data/lib/hybrid_platforms_conductor/config.rb +263 -0
  26. data/lib/hybrid_platforms_conductor/confluence.rb +119 -0
  27. data/lib/hybrid_platforms_conductor/connector.rb +84 -0
  28. data/lib/hybrid_platforms_conductor/credentials.rb +127 -0
  29. data/lib/hybrid_platforms_conductor/current_dir_monitor.rb +42 -0
  30. data/lib/hybrid_platforms_conductor/deployer.rb +598 -0
  31. data/lib/hybrid_platforms_conductor/executable.rb +145 -0
  32. data/lib/hybrid_platforms_conductor/hpc_plugins/action/bash.rb +44 -0
  33. data/lib/hybrid_platforms_conductor/hpc_plugins/action/interactive.rb +44 -0
  34. data/lib/hybrid_platforms_conductor/hpc_plugins/action/my_action.rb.sample +79 -0
  35. data/lib/hybrid_platforms_conductor/hpc_plugins/action/remote_bash.rb +63 -0
  36. data/lib/hybrid_platforms_conductor/hpc_plugins/action/ruby.rb +69 -0
  37. data/lib/hybrid_platforms_conductor/hpc_plugins/action/scp.rb +61 -0
  38. data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/config.rb +78 -0
  39. data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/host_ip.rb +104 -0
  40. data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/host_keys.rb +114 -0
  41. data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/my_cmdb.rb.sample +129 -0
  42. data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/platform_handlers.rb +66 -0
  43. data/lib/hybrid_platforms_conductor/hpc_plugins/connector/my_connector.rb.sample +156 -0
  44. data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +702 -0
  45. data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/platform_handler_plugin.rb.sample +292 -0
  46. data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/docker.rb +148 -0
  47. data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/my_provisioner.rb.sample +103 -0
  48. data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/podman.rb +125 -0
  49. data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox.rb +522 -0
  50. data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox/proxmox_waiter.rb +707 -0
  51. data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox/reserve_proxmox_container +122 -0
  52. data/lib/hybrid_platforms_conductor/hpc_plugins/report/confluence.rb +69 -0
  53. data/lib/hybrid_platforms_conductor/hpc_plugins/report/mediawiki.rb +164 -0
  54. data/lib/hybrid_platforms_conductor/hpc_plugins/report/my_report_plugin.rb.sample +88 -0
  55. data/lib/hybrid_platforms_conductor/hpc_plugins/report/stdout.rb +61 -0
  56. data/lib/hybrid_platforms_conductor/hpc_plugins/report/templates/confluence_inventory.html.erb +33 -0
  57. data/lib/hybrid_platforms_conductor/hpc_plugins/test/bitbucket_conf.rb +137 -0
  58. data/lib/hybrid_platforms_conductor/hpc_plugins/test/can_be_checked.rb +21 -0
  59. data/lib/hybrid_platforms_conductor/hpc_plugins/test/check_deploy_and_idempotence.rb +112 -0
  60. data/lib/hybrid_platforms_conductor/hpc_plugins/test/check_from_scratch.rb +35 -0
  61. data/lib/hybrid_platforms_conductor/hpc_plugins/test/connection.rb +28 -0
  62. data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_freshness.rb +44 -0
  63. data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_from_scratch.rb +36 -0
  64. data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_removes_root_access.rb +49 -0
  65. data/lib/hybrid_platforms_conductor/hpc_plugins/test/divergence.rb +25 -0
  66. data/lib/hybrid_platforms_conductor/hpc_plugins/test/executables.rb +46 -0
  67. data/lib/hybrid_platforms_conductor/hpc_plugins/test/file_system.rb +45 -0
  68. data/lib/hybrid_platforms_conductor/hpc_plugins/test/file_system_hdfs.rb +45 -0
  69. data/lib/hybrid_platforms_conductor/hpc_plugins/test/hostname.rb +25 -0
  70. data/lib/hybrid_platforms_conductor/hpc_plugins/test/idempotence.rb +77 -0
  71. data/lib/hybrid_platforms_conductor/hpc_plugins/test/ip.rb +38 -0
  72. data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_conf.rb +56 -0
  73. data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_masters_ok.rb +54 -0
  74. data/lib/hybrid_platforms_conductor/hpc_plugins/test/linear_strategy.rb +47 -0
  75. data/lib/hybrid_platforms_conductor/hpc_plugins/test/local_users.rb +82 -0
  76. data/lib/hybrid_platforms_conductor/hpc_plugins/test/mounts.rb +120 -0
  77. data/lib/hybrid_platforms_conductor/hpc_plugins/test/my_test_plugin.rb.sample +143 -0
  78. data/lib/hybrid_platforms_conductor/hpc_plugins/test/orphan_files.rb +74 -0
  79. data/lib/hybrid_platforms_conductor/hpc_plugins/test/ports.rb +85 -0
  80. data/lib/hybrid_platforms_conductor/hpc_plugins/test/private_ips.rb +38 -0
  81. data/lib/hybrid_platforms_conductor/hpc_plugins/test/public_ips.rb +38 -0
  82. data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre-meltdown-checker.sh +1930 -0
  83. data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre.rb +56 -0
  84. data/lib/hybrid_platforms_conductor/hpc_plugins/test/veids.rb +31 -0
  85. data/lib/hybrid_platforms_conductor/hpc_plugins/test/vulnerabilities.rb +159 -0
  86. data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/confluence.rb +122 -0
  87. data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/my_test_report.rb.sample +48 -0
  88. data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/stdout.rb +120 -0
  89. data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/templates/_confluence_errors_status.html.erb +46 -0
  90. data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/templates/_confluence_gauge.html.erb +49 -0
  91. data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/templates/confluence.html.erb +242 -0
  92. data/lib/hybrid_platforms_conductor/io_router.rb +70 -0
  93. data/lib/hybrid_platforms_conductor/json_dumper.rb +88 -0
  94. data/lib/hybrid_platforms_conductor/logger_helpers.rb +319 -0
  95. data/lib/hybrid_platforms_conductor/mutex_dir +76 -0
  96. data/lib/hybrid_platforms_conductor/nodes_handler.rb +597 -0
  97. data/lib/hybrid_platforms_conductor/parallel_threads.rb +97 -0
  98. data/lib/hybrid_platforms_conductor/platform_handler.rb +188 -0
  99. data/lib/hybrid_platforms_conductor/platforms_handler.rb +118 -0
  100. data/lib/hybrid_platforms_conductor/plugin.rb +53 -0
  101. data/lib/hybrid_platforms_conductor/plugins.rb +101 -0
  102. data/lib/hybrid_platforms_conductor/provisioner.rb +181 -0
  103. data/lib/hybrid_platforms_conductor/report.rb +31 -0
  104. data/lib/hybrid_platforms_conductor/reports_handler.rb +84 -0
  105. data/lib/hybrid_platforms_conductor/services_handler.rb +274 -0
  106. data/lib/hybrid_platforms_conductor/test.rb +141 -0
  107. data/lib/hybrid_platforms_conductor/test_by_service.rb +22 -0
  108. data/lib/hybrid_platforms_conductor/test_report.rb +282 -0
  109. data/lib/hybrid_platforms_conductor/tests_runner.rb +590 -0
  110. data/lib/hybrid_platforms_conductor/thycotic.rb +92 -0
  111. data/lib/hybrid_platforms_conductor/topographer.rb +859 -0
  112. data/lib/hybrid_platforms_conductor/topographer/plugin.rb +20 -0
  113. data/lib/hybrid_platforms_conductor/topographer/plugins/graphviz.rb +127 -0
  114. data/lib/hybrid_platforms_conductor/topographer/plugins/json.rb +72 -0
  115. data/lib/hybrid_platforms_conductor/topographer/plugins/my_topographer_output_plugin.rb.sample +37 -0
  116. data/lib/hybrid_platforms_conductor/topographer/plugins/svg.rb +30 -0
  117. data/lib/hybrid_platforms_conductor/version.rb +5 -0
  118. data/spec/hybrid_platforms_conductor_test.rb +159 -0
  119. data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/bash_spec.rb +43 -0
  120. data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/interactive_spec.rb +18 -0
  121. data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/remote_bash_spec.rb +102 -0
  122. data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/ruby_spec.rb +108 -0
  123. data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/scp_spec.rb +79 -0
  124. data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions_spec.rb +199 -0
  125. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connection_spec.rb +212 -0
  126. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/cli_options_spec.rb +125 -0
  127. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/config_dsl_spec.rb +50 -0
  128. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connectable_nodes_spec.rb +28 -0
  129. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connections_spec.rb +448 -0
  130. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/global_helpers_spec.rb +313 -0
  131. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/node_helpers_spec.rb +32 -0
  132. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/remote_actions_spec.rb +134 -0
  133. data/spec/hybrid_platforms_conductor_test/api/actions_executor/logging_spec.rb +256 -0
  134. data/spec/hybrid_platforms_conductor_test/api/actions_executor/parallel_spec.rb +338 -0
  135. data/spec/hybrid_platforms_conductor_test/api/actions_executor/timeout_spec.rb +101 -0
  136. data/spec/hybrid_platforms_conductor_test/api/cmd_runner_spec.rb +165 -0
  137. data/spec/hybrid_platforms_conductor_test/api/config_spec.rb +238 -0
  138. data/spec/hybrid_platforms_conductor_test/api/deployer/check_spec.rb +9 -0
  139. data/spec/hybrid_platforms_conductor_test/api/deployer/deploy_spec.rb +243 -0
  140. data/spec/hybrid_platforms_conductor_test/api/deployer/parse_deploy_output_spec.rb +104 -0
  141. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioner_spec.rb +131 -0
  142. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/docker/Dockerfile +10 -0
  143. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/docker_spec.rb +123 -0
  144. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/podman_spec.rb +211 -0
  145. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/config_dsl_spec.rb +126 -0
  146. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/create_spec.rb +290 -0
  147. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/destroy_spec.rb +43 -0
  148. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/ip_spec.rb +60 -0
  149. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/proxmox.json +3 -0
  150. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/destroy_vm_spec.rb +82 -0
  151. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/expired_containers_spec.rb +786 -0
  152. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/ips_assignment_spec.rb +112 -0
  153. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/other_lxc_containers_resources_spec.rb +190 -0
  154. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/pve_node_resources_spec.rb +200 -0
  155. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/retries_spec.rb +35 -0
  156. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/vm_ids_assignment_spec.rb +67 -0
  157. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/start_spec.rb +79 -0
  158. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/state_spec.rb +28 -0
  159. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/stop_spec.rb +41 -0
  160. data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/config_spec.rb +33 -0
  161. data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/host_ip_spec.rb +64 -0
  162. data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/host_keys_spec.rb +133 -0
  163. data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/platform_handlers_spec.rb +19 -0
  164. data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs_plugins_api_spec.rb +446 -0
  165. data/spec/hybrid_platforms_conductor_test/api/nodes_handler/common_spec.rb +127 -0
  166. data/spec/hybrid_platforms_conductor_test/api/nodes_handler/git_diff_impacts_spec.rb +318 -0
  167. data/spec/hybrid_platforms_conductor_test/api/nodes_handler/nodes_selectors_spec.rb +132 -0
  168. data/spec/hybrid_platforms_conductor_test/api/nodes_handler/platform_handlers_plugins_api_spec.rb +60 -0
  169. data/spec/hybrid_platforms_conductor_test/api/nodes_handler/several_platforms_spec.rb +58 -0
  170. data/spec/hybrid_platforms_conductor_test/api/platform_handler_spec.rb +97 -0
  171. data/spec/hybrid_platforms_conductor_test/api/platforms_handler_spec.rb +104 -0
  172. data/spec/hybrid_platforms_conductor_test/api/plugins_spec.rb +243 -0
  173. data/spec/hybrid_platforms_conductor_test/api/reports_handler_spec.rb +44 -0
  174. data/spec/hybrid_platforms_conductor_test/api/services_handler/actions_to_deploy_spec.rb +121 -0
  175. data/spec/hybrid_platforms_conductor_test/api/services_handler/deploy_allowed_spec.rb +142 -0
  176. data/spec/hybrid_platforms_conductor_test/api/services_handler/log_info_spec.rb +101 -0
  177. data/spec/hybrid_platforms_conductor_test/api/services_handler/package_spec.rb +388 -0
  178. data/spec/hybrid_platforms_conductor_test/api/services_handler/parse_deploy_output_spec.rb +274 -0
  179. data/spec/hybrid_platforms_conductor_test/api/services_handler/prepare_for_deploy_spec.rb +264 -0
  180. data/spec/hybrid_platforms_conductor_test/api/tests_runner/common_spec.rb +194 -0
  181. data/spec/hybrid_platforms_conductor_test/api/tests_runner/global_spec.rb +37 -0
  182. data/spec/hybrid_platforms_conductor_test/api/tests_runner/node_check_spec.rb +194 -0
  183. data/spec/hybrid_platforms_conductor_test/api/tests_runner/node_spec.rb +137 -0
  184. data/spec/hybrid_platforms_conductor_test/api/tests_runner/node_ssh_spec.rb +257 -0
  185. data/spec/hybrid_platforms_conductor_test/api/tests_runner/platform_spec.rb +110 -0
  186. data/spec/hybrid_platforms_conductor_test/api/tests_runner/reports_spec.rb +367 -0
  187. data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_plugins/bitbucket_conf_spec.rb +111 -0
  188. data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_reports_plugins/confluence_spec.rb +29 -0
  189. data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb.rb +166 -0
  190. data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb2.rb +93 -0
  191. data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb_others.rb +60 -0
  192. data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb_others2.rb +58 -0
  193. data/spec/hybrid_platforms_conductor_test/executables/check-node_spec.rb +35 -0
  194. data/spec/hybrid_platforms_conductor_test/executables/deploy_spec.rb +35 -0
  195. data/spec/hybrid_platforms_conductor_test/executables/get_impacted_nodes_spec.rb +158 -0
  196. data/spec/hybrid_platforms_conductor_test/executables/last_deploys_spec.rb +173 -0
  197. data/spec/hybrid_platforms_conductor_test/executables/nodes_to_deploy_spec.rb +283 -0
  198. data/spec/hybrid_platforms_conductor_test/executables/options/actions_executor_spec.rb +28 -0
  199. data/spec/hybrid_platforms_conductor_test/executables/options/cmd_runner_spec.rb +28 -0
  200. data/spec/hybrid_platforms_conductor_test/executables/options/common_spec.rb +67 -0
  201. data/spec/hybrid_platforms_conductor_test/executables/options/deployer_spec.rb +251 -0
  202. data/spec/hybrid_platforms_conductor_test/executables/options/nodes_handler_spec.rb +111 -0
  203. data/spec/hybrid_platforms_conductor_test/executables/options/nodes_selectors_spec.rb +71 -0
  204. data/spec/hybrid_platforms_conductor_test/executables/options/reports_handler_spec.rb +54 -0
  205. data/spec/hybrid_platforms_conductor_test/executables/options/tests_runner_spec.rb +139 -0
  206. data/spec/hybrid_platforms_conductor_test/executables/report_spec.rb +60 -0
  207. data/spec/hybrid_platforms_conductor_test/executables/run_spec.rb +173 -0
  208. data/spec/hybrid_platforms_conductor_test/executables/ssh_config_spec.rb +35 -0
  209. data/spec/hybrid_platforms_conductor_test/executables/test_spec.rb +41 -0
  210. data/spec/hybrid_platforms_conductor_test/helpers/actions_executor_helpers.rb +98 -0
  211. data/spec/hybrid_platforms_conductor_test/helpers/cmd_runner_helpers.rb +92 -0
  212. data/spec/hybrid_platforms_conductor_test/helpers/cmdb_helpers.rb +37 -0
  213. data/spec/hybrid_platforms_conductor_test/helpers/config_helpers.rb +20 -0
  214. data/spec/hybrid_platforms_conductor_test/helpers/connector_ssh_helpers.rb +130 -0
  215. data/spec/hybrid_platforms_conductor_test/helpers/deployer_helpers.rb +149 -0
  216. data/spec/hybrid_platforms_conductor_test/helpers/deployer_test_helpers.rb +812 -0
  217. data/spec/hybrid_platforms_conductor_test/helpers/executables_helpers.rb +96 -0
  218. data/spec/hybrid_platforms_conductor_test/helpers/nodes_handler_helpers.rb +20 -0
  219. data/spec/hybrid_platforms_conductor_test/helpers/platform_handler_helpers.rb +35 -0
  220. data/spec/hybrid_platforms_conductor_test/helpers/platforms_handler_helpers.rb +127 -0
  221. data/spec/hybrid_platforms_conductor_test/helpers/plugins_helpers.rb +48 -0
  222. data/spec/hybrid_platforms_conductor_test/helpers/provisioner_proxmox_helpers.rb +789 -0
  223. data/spec/hybrid_platforms_conductor_test/helpers/reports_handler_helpers.rb +29 -0
  224. data/spec/hybrid_platforms_conductor_test/helpers/services_handler_helpers.rb +20 -0
  225. data/spec/hybrid_platforms_conductor_test/helpers/tests_runner_helpers.rb +38 -0
  226. data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem/hpc_plugins/test_plugin_type/test_plugin_id1.rb +22 -0
  227. data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem/hpc_plugins/test_plugin_type/test_plugin_id2.rb +22 -0
  228. data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem2/sub_dir/hpc_plugins/test_plugin_type/test_plugin_id3.rb +26 -0
  229. data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem2/sub_dir/hpc_plugins/test_plugin_type2/test_plugin_id4.rb +26 -0
  230. data/spec/hybrid_platforms_conductor_test/platform_handler_plugins/test.rb +225 -0
  231. data/spec/hybrid_platforms_conductor_test/platform_handler_plugins/test2.rb +11 -0
  232. data/spec/hybrid_platforms_conductor_test/report_plugin.rb +35 -0
  233. data/spec/hybrid_platforms_conductor_test/test_action.rb +66 -0
  234. data/spec/hybrid_platforms_conductor_test/test_connector.rb +151 -0
  235. data/spec/hybrid_platforms_conductor_test/test_plugins/global.rb +30 -0
  236. data/spec/hybrid_platforms_conductor_test/test_plugins/node.rb +53 -0
  237. data/spec/hybrid_platforms_conductor_test/test_plugins/node_check.rb +47 -0
  238. data/spec/hybrid_platforms_conductor_test/test_plugins/node_ssh.rb +42 -0
  239. data/spec/hybrid_platforms_conductor_test/test_plugins/platform.rb +50 -0
  240. data/spec/hybrid_platforms_conductor_test/test_plugins/several_checks.rb +50 -0
  241. data/spec/hybrid_platforms_conductor_test/test_provisioner.rb +95 -0
  242. data/spec/hybrid_platforms_conductor_test/tests_report_plugin.rb +49 -0
  243. data/spec/spec_helper.rb +111 -0
  244. metadata +566 -0
@@ -0,0 +1,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