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.
- checksums.yaml +7 -0
- data/bin/check-node +24 -0
- data/bin/deploy +12 -0
- data/bin/dump_nodes_json +12 -0
- data/bin/free_ips +23 -0
- data/bin/free_veids +17 -0
- data/bin/get_impacted_nodes +43 -0
- data/bin/last_deploys +56 -0
- data/bin/nodes_to_deploy +104 -0
- data/bin/report +10 -0
- data/bin/run +39 -0
- data/bin/setup +11 -0
- data/bin/ssh_config +14 -0
- data/bin/test +13 -0
- data/bin/topograph +54 -0
- data/lib/hybrid_platforms_conductor/action.rb +82 -0
- data/lib/hybrid_platforms_conductor/actions_executor.rb +307 -0
- data/lib/hybrid_platforms_conductor/bitbucket.rb +123 -0
- data/lib/hybrid_platforms_conductor/cmd_runner.rb +188 -0
- data/lib/hybrid_platforms_conductor/cmdb.rb +34 -0
- data/lib/hybrid_platforms_conductor/common_config_dsl/bitbucket.rb +78 -0
- data/lib/hybrid_platforms_conductor/common_config_dsl/confluence.rb +43 -0
- data/lib/hybrid_platforms_conductor/common_config_dsl/file_system_tests.rb +110 -0
- data/lib/hybrid_platforms_conductor/common_config_dsl/idempotence_tests.rb +38 -0
- data/lib/hybrid_platforms_conductor/config.rb +263 -0
- data/lib/hybrid_platforms_conductor/confluence.rb +119 -0
- data/lib/hybrid_platforms_conductor/connector.rb +84 -0
- data/lib/hybrid_platforms_conductor/credentials.rb +127 -0
- data/lib/hybrid_platforms_conductor/current_dir_monitor.rb +42 -0
- data/lib/hybrid_platforms_conductor/deployer.rb +598 -0
- data/lib/hybrid_platforms_conductor/executable.rb +145 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/bash.rb +44 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/interactive.rb +44 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/my_action.rb.sample +79 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/remote_bash.rb +63 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/ruby.rb +69 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/scp.rb +61 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/config.rb +78 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/host_ip.rb +104 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/host_keys.rb +114 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/my_cmdb.rb.sample +129 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/cmdb/platform_handlers.rb +66 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/my_connector.rb.sample +156 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +702 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/platform_handler_plugin.rb.sample +292 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/docker.rb +148 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/my_provisioner.rb.sample +103 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/podman.rb +125 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox.rb +522 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox/proxmox_waiter.rb +707 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox/reserve_proxmox_container +122 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/confluence.rb +69 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/mediawiki.rb +164 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/my_report_plugin.rb.sample +88 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/stdout.rb +61 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/templates/confluence_inventory.html.erb +33 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/bitbucket_conf.rb +137 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/can_be_checked.rb +21 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/check_deploy_and_idempotence.rb +112 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/check_from_scratch.rb +35 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/connection.rb +28 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_freshness.rb +44 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_from_scratch.rb +36 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_removes_root_access.rb +49 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/divergence.rb +25 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/executables.rb +46 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/file_system.rb +45 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/file_system_hdfs.rb +45 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/hostname.rb +25 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/idempotence.rb +77 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/ip.rb +38 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_conf.rb +56 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_masters_ok.rb +54 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/linear_strategy.rb +47 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/local_users.rb +82 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/mounts.rb +120 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/my_test_plugin.rb.sample +143 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/orphan_files.rb +74 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/ports.rb +85 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/private_ips.rb +38 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/public_ips.rb +38 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre-meltdown-checker.sh +1930 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre.rb +56 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/veids.rb +31 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/vulnerabilities.rb +159 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/confluence.rb +122 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/my_test_report.rb.sample +48 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/stdout.rb +120 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/templates/_confluence_errors_status.html.erb +46 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/templates/_confluence_gauge.html.erb +49 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/templates/confluence.html.erb +242 -0
- data/lib/hybrid_platforms_conductor/io_router.rb +70 -0
- data/lib/hybrid_platforms_conductor/json_dumper.rb +88 -0
- data/lib/hybrid_platforms_conductor/logger_helpers.rb +319 -0
- data/lib/hybrid_platforms_conductor/mutex_dir +76 -0
- data/lib/hybrid_platforms_conductor/nodes_handler.rb +597 -0
- data/lib/hybrid_platforms_conductor/parallel_threads.rb +97 -0
- data/lib/hybrid_platforms_conductor/platform_handler.rb +188 -0
- data/lib/hybrid_platforms_conductor/platforms_handler.rb +118 -0
- data/lib/hybrid_platforms_conductor/plugin.rb +53 -0
- data/lib/hybrid_platforms_conductor/plugins.rb +101 -0
- data/lib/hybrid_platforms_conductor/provisioner.rb +181 -0
- data/lib/hybrid_platforms_conductor/report.rb +31 -0
- data/lib/hybrid_platforms_conductor/reports_handler.rb +84 -0
- data/lib/hybrid_platforms_conductor/services_handler.rb +274 -0
- data/lib/hybrid_platforms_conductor/test.rb +141 -0
- data/lib/hybrid_platforms_conductor/test_by_service.rb +22 -0
- data/lib/hybrid_platforms_conductor/test_report.rb +282 -0
- data/lib/hybrid_platforms_conductor/tests_runner.rb +590 -0
- data/lib/hybrid_platforms_conductor/thycotic.rb +92 -0
- data/lib/hybrid_platforms_conductor/topographer.rb +859 -0
- data/lib/hybrid_platforms_conductor/topographer/plugin.rb +20 -0
- data/lib/hybrid_platforms_conductor/topographer/plugins/graphviz.rb +127 -0
- data/lib/hybrid_platforms_conductor/topographer/plugins/json.rb +72 -0
- data/lib/hybrid_platforms_conductor/topographer/plugins/my_topographer_output_plugin.rb.sample +37 -0
- data/lib/hybrid_platforms_conductor/topographer/plugins/svg.rb +30 -0
- data/lib/hybrid_platforms_conductor/version.rb +5 -0
- data/spec/hybrid_platforms_conductor_test.rb +159 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/bash_spec.rb +43 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/interactive_spec.rb +18 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/remote_bash_spec.rb +102 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/ruby_spec.rb +108 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/scp_spec.rb +79 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions_spec.rb +199 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connection_spec.rb +212 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/cli_options_spec.rb +125 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/config_dsl_spec.rb +50 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connectable_nodes_spec.rb +28 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connections_spec.rb +448 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/global_helpers_spec.rb +313 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/node_helpers_spec.rb +32 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/remote_actions_spec.rb +134 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/logging_spec.rb +256 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/parallel_spec.rb +338 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/timeout_spec.rb +101 -0
- data/spec/hybrid_platforms_conductor_test/api/cmd_runner_spec.rb +165 -0
- data/spec/hybrid_platforms_conductor_test/api/config_spec.rb +238 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/check_spec.rb +9 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/deploy_spec.rb +243 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/parse_deploy_output_spec.rb +104 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioner_spec.rb +131 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/docker/Dockerfile +10 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/docker_spec.rb +123 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/podman_spec.rb +211 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/config_dsl_spec.rb +126 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/create_spec.rb +290 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/destroy_spec.rb +43 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/ip_spec.rb +60 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/proxmox.json +3 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/destroy_vm_spec.rb +82 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/expired_containers_spec.rb +786 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/ips_assignment_spec.rb +112 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/other_lxc_containers_resources_spec.rb +190 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/pve_node_resources_spec.rb +200 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/retries_spec.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/reserve_proxmox_container/vm_ids_assignment_spec.rb +67 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/start_spec.rb +79 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/state_spec.rb +28 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/provisioners/proxmox/stop_spec.rb +41 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/config_spec.rb +33 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/host_ip_spec.rb +64 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/host_keys_spec.rb +133 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs/platform_handlers_spec.rb +19 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs_plugins_api_spec.rb +446 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/common_spec.rb +127 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/git_diff_impacts_spec.rb +318 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/nodes_selectors_spec.rb +132 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/platform_handlers_plugins_api_spec.rb +60 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/several_platforms_spec.rb +58 -0
- data/spec/hybrid_platforms_conductor_test/api/platform_handler_spec.rb +97 -0
- data/spec/hybrid_platforms_conductor_test/api/platforms_handler_spec.rb +104 -0
- data/spec/hybrid_platforms_conductor_test/api/plugins_spec.rb +243 -0
- data/spec/hybrid_platforms_conductor_test/api/reports_handler_spec.rb +44 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/actions_to_deploy_spec.rb +121 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/deploy_allowed_spec.rb +142 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/log_info_spec.rb +101 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/package_spec.rb +388 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/parse_deploy_output_spec.rb +274 -0
- data/spec/hybrid_platforms_conductor_test/api/services_handler/prepare_for_deploy_spec.rb +264 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/common_spec.rb +194 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/global_spec.rb +37 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/node_check_spec.rb +194 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/node_spec.rb +137 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/node_ssh_spec.rb +257 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/platform_spec.rb +110 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/reports_spec.rb +367 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_plugins/bitbucket_conf_spec.rb +111 -0
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_reports_plugins/confluence_spec.rb +29 -0
- data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb.rb +166 -0
- data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb2.rb +93 -0
- data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb_others.rb +60 -0
- data/spec/hybrid_platforms_conductor_test/cmdb_plugins/test_cmdb_others2.rb +58 -0
- data/spec/hybrid_platforms_conductor_test/executables/check-node_spec.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/executables/deploy_spec.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/executables/get_impacted_nodes_spec.rb +158 -0
- data/spec/hybrid_platforms_conductor_test/executables/last_deploys_spec.rb +173 -0
- data/spec/hybrid_platforms_conductor_test/executables/nodes_to_deploy_spec.rb +283 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/actions_executor_spec.rb +28 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/cmd_runner_spec.rb +28 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/common_spec.rb +67 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/deployer_spec.rb +251 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/nodes_handler_spec.rb +111 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/nodes_selectors_spec.rb +71 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/reports_handler_spec.rb +54 -0
- data/spec/hybrid_platforms_conductor_test/executables/options/tests_runner_spec.rb +139 -0
- data/spec/hybrid_platforms_conductor_test/executables/report_spec.rb +60 -0
- data/spec/hybrid_platforms_conductor_test/executables/run_spec.rb +173 -0
- data/spec/hybrid_platforms_conductor_test/executables/ssh_config_spec.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/executables/test_spec.rb +41 -0
- data/spec/hybrid_platforms_conductor_test/helpers/actions_executor_helpers.rb +98 -0
- data/spec/hybrid_platforms_conductor_test/helpers/cmd_runner_helpers.rb +92 -0
- data/spec/hybrid_platforms_conductor_test/helpers/cmdb_helpers.rb +37 -0
- data/spec/hybrid_platforms_conductor_test/helpers/config_helpers.rb +20 -0
- data/spec/hybrid_platforms_conductor_test/helpers/connector_ssh_helpers.rb +130 -0
- data/spec/hybrid_platforms_conductor_test/helpers/deployer_helpers.rb +149 -0
- data/spec/hybrid_platforms_conductor_test/helpers/deployer_test_helpers.rb +812 -0
- data/spec/hybrid_platforms_conductor_test/helpers/executables_helpers.rb +96 -0
- data/spec/hybrid_platforms_conductor_test/helpers/nodes_handler_helpers.rb +20 -0
- data/spec/hybrid_platforms_conductor_test/helpers/platform_handler_helpers.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/helpers/platforms_handler_helpers.rb +127 -0
- data/spec/hybrid_platforms_conductor_test/helpers/plugins_helpers.rb +48 -0
- data/spec/hybrid_platforms_conductor_test/helpers/provisioner_proxmox_helpers.rb +789 -0
- data/spec/hybrid_platforms_conductor_test/helpers/reports_handler_helpers.rb +29 -0
- data/spec/hybrid_platforms_conductor_test/helpers/services_handler_helpers.rb +20 -0
- data/spec/hybrid_platforms_conductor_test/helpers/tests_runner_helpers.rb +38 -0
- data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem/hpc_plugins/test_plugin_type/test_plugin_id1.rb +22 -0
- data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem/hpc_plugins/test_plugin_type/test_plugin_id2.rb +22 -0
- data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem2/sub_dir/hpc_plugins/test_plugin_type/test_plugin_id3.rb +26 -0
- data/spec/hybrid_platforms_conductor_test/mocked_lib/my_test_gem2/sub_dir/hpc_plugins/test_plugin_type2/test_plugin_id4.rb +26 -0
- data/spec/hybrid_platforms_conductor_test/platform_handler_plugins/test.rb +225 -0
- data/spec/hybrid_platforms_conductor_test/platform_handler_plugins/test2.rb +11 -0
- data/spec/hybrid_platforms_conductor_test/report_plugin.rb +35 -0
- data/spec/hybrid_platforms_conductor_test/test_action.rb +66 -0
- data/spec/hybrid_platforms_conductor_test/test_connector.rb +151 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/global.rb +30 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/node.rb +53 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/node_check.rb +47 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/node_ssh.rb +42 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/platform.rb +50 -0
- data/spec/hybrid_platforms_conductor_test/test_plugins/several_checks.rb +50 -0
- data/spec/hybrid_platforms_conductor_test/test_provisioner.rb +95 -0
- data/spec/hybrid_platforms_conductor_test/tests_report_plugin.rb +49 -0
- data/spec/spec_helper.rb +111 -0
- metadata +566 -0
|
@@ -0,0 +1,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
|