hybrid_platforms_conductor 32.3.6
Sign up to get free protection for your applications and to get access to all the features.
- 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,66 @@
|
|
1
|
+
module HybridPlatformsConductor
|
2
|
+
|
3
|
+
module HpcPlugins
|
4
|
+
|
5
|
+
module Cmdb
|
6
|
+
|
7
|
+
# CMDB getting metadata from the Platform Handlers directly
|
8
|
+
class PlatformHandlers < HybridPlatformsConductor::Cmdb
|
9
|
+
|
10
|
+
# get_* methods are automatically detected as possible metadata properties this plugin can fill.
|
11
|
+
# The property name filled by such method is given by the method's name: get_my_property will fill the :my_property metadata.
|
12
|
+
# The method get_others is used specifically to return properties whose name is unknown before fetching them.
|
13
|
+
|
14
|
+
# Get a specific property for a given set of nodes.
|
15
|
+
# [API] - @platforms_handler can be used.
|
16
|
+
# [API] - @nodes_handler can be used.
|
17
|
+
# [API] - @cmd_runner can be used.
|
18
|
+
#
|
19
|
+
# Parameters::
|
20
|
+
# * *nodes* (Array<String>): The nodes to lookup the property for.
|
21
|
+
# * *metadata* (Hash<String, Hash<Symbol,Object> >): Existing metadata for each node. Dependent properties should be present here.
|
22
|
+
# Result::
|
23
|
+
# * Hash<String, Object>: The corresponding property, per required node.
|
24
|
+
# Nodes for which the property can't be fetched can be ommitted.
|
25
|
+
def get_services(nodes, metadata)
|
26
|
+
Hash[nodes.map { |node| [node, platform_for(node).services_for(node)] }]
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get other properties for a given set of nodes.
|
30
|
+
# It's better to not use this method and prefer using methods naming the property being returned.
|
31
|
+
# As the nodes_handler can't know in advance which properties will be returned, it will call it every time there is a missing property.
|
32
|
+
# If this method always returns the same values, it would be clever to cache it here.
|
33
|
+
# [API] - This method is optional.
|
34
|
+
# [API] - @platforms_handler can be used.
|
35
|
+
# [API] - @nodes_handler can be used.
|
36
|
+
# [API] - @cmd_runner can be used.
|
37
|
+
#
|
38
|
+
# Parameters::
|
39
|
+
# * *nodes* (Array<String>): The nodes to lookup the property for.
|
40
|
+
# * *metadata* (Hash<String, Hash<Symbol,Object> >): Existing metadata for each node. Dependent properties should be present here.
|
41
|
+
# Result::
|
42
|
+
# * Hash<String, Hash<Symbol,Object> >: The corresponding properties, per required node.
|
43
|
+
# Nodes for which the property can't be fetched can be ommitted.
|
44
|
+
def get_others(nodes, metadata)
|
45
|
+
Hash[nodes.map { |node| [node, platform_for(node).metadata_for(node)] }]
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# Get the platform that defines a node's inventory
|
51
|
+
#
|
52
|
+
# Parameters::
|
53
|
+
# * *node* (String): The node name
|
54
|
+
# Result::
|
55
|
+
# * PlatformHandler or nil: The platform defining the node's inventory, or nil if none
|
56
|
+
def platform_for(node)
|
57
|
+
@platforms_handler.known_platforms.find { |platform| platform.known_nodes.include?(node) }
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
module HybridPlatformsConductor
|
2
|
+
|
3
|
+
module HpcPlugins
|
4
|
+
|
5
|
+
module Connector
|
6
|
+
|
7
|
+
# Sample connector
|
8
|
+
class MyConnector < HybridPlatformsConductor::Connector
|
9
|
+
|
10
|
+
# Are dependencies met before using this plugin?
|
11
|
+
# [API] - This method is optional
|
12
|
+
#
|
13
|
+
# Result::
|
14
|
+
# * Boolean: Are dependencies met before using this plugin?
|
15
|
+
def self.valid?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
# Add a Mixin to the DSL parsing the platforms configuration file.
|
20
|
+
# This can be used by any plugin to add plugin-specific configuration getters and setters, accessible later from NodesHandler instances.
|
21
|
+
# An optional initializer can also be given.
|
22
|
+
# [API] - Those calls are optional
|
23
|
+
module MyDSLExtension
|
24
|
+
|
25
|
+
attr_accessor :my_property
|
26
|
+
|
27
|
+
# Initialize the DSL
|
28
|
+
def init_my_dsl_extension
|
29
|
+
@my_property = 42
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
self.extend_config_dsl_with MyDSLExtension, :init_my_dsl_extension
|
34
|
+
|
35
|
+
# Initialize the connector.
|
36
|
+
# This can be used to initialize global variables that are used for this connector
|
37
|
+
# [API] - This method is optional
|
38
|
+
# [API] - @cmd_runner can be used
|
39
|
+
# [API] - @nodes_handler can be used
|
40
|
+
def init
|
41
|
+
@logger_ip = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
# Complete an option parser with options meant to control this connector
|
45
|
+
# [API] - This method is optional
|
46
|
+
# [API] - @cmd_runner can be used
|
47
|
+
# [API] - @nodes_handler can be used
|
48
|
+
#
|
49
|
+
# Parameters::
|
50
|
+
# * *options_parser* (OptionParser): The option parser to complete
|
51
|
+
def options_parse(options_parser)
|
52
|
+
options_parser.on('--logger-ip IP', 'If specified, then log everything to a given IP') do |ip|
|
53
|
+
@logger_ip = ip
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Validate that parsed parameters are valid
|
58
|
+
# [API] - This method is optional
|
59
|
+
# [API] - @cmd_runner can be used
|
60
|
+
# [API] - @nodes_handler can be used
|
61
|
+
def validate_params
|
62
|
+
# Check that the logger IP is valid if specified
|
63
|
+
raise "Invalid IP: #{@logger_ip}" if @logger_ip && !(@logger_ip =~ /^\d+\.\d+\.\d+\.\d+$/)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Select nodes where this connector can connect.
|
67
|
+
# [API] - This method is mandatory
|
68
|
+
# [API] - @cmd_runner can be used
|
69
|
+
# [API] - @nodes_handler can be used
|
70
|
+
#
|
71
|
+
# Parameters::
|
72
|
+
# * *nodes* (Array<String>): List of candidate nodes
|
73
|
+
# Result::
|
74
|
+
# * Array<String>: List of nodes we can connect to from the candidates
|
75
|
+
def connectable_nodes_from(nodes)
|
76
|
+
nodes.select { |node| @nodes_handler.get_ip_of(node) =~ /^192\.168\..+$/ }
|
77
|
+
end
|
78
|
+
|
79
|
+
# Prepare connections to a given set of nodes.
|
80
|
+
# Useful to prefetch metadata or open bulk connections.
|
81
|
+
# [API] - This method is optional
|
82
|
+
# [API] - @cmd_runner can be used
|
83
|
+
# [API] - @nodes_handler can be used
|
84
|
+
#
|
85
|
+
# Parameters::
|
86
|
+
# * *nodes* (Array<String>): Nodes to prepare the connection to
|
87
|
+
# * *no_exception* (Boolean): Should we still continue if some nodes have connection errors? [default: false]
|
88
|
+
# * Proc: Code called with the connections prepared.
|
89
|
+
# * Parameters::
|
90
|
+
# * *connected_nodes* (Array<String>): The list of connected nodes (should be equal to nodes unless no_exception == true and some nodes failed to connect)
|
91
|
+
def with_connection_to(nodes, no_exception: false)
|
92
|
+
register_nodes_in_logger(@logger_ip, nodes) if @logger_ip
|
93
|
+
yield nodes
|
94
|
+
end
|
95
|
+
|
96
|
+
# Run bash commands on a given node.
|
97
|
+
# [API] - This method is mandatory
|
98
|
+
# [API] - If defined, then with_connection_to has been called before this method.
|
99
|
+
# [API] - @cmd_runner can be used
|
100
|
+
# [API] - @nodes_handler can be used
|
101
|
+
# [API] - @node can be used to access the node on which we execute the remote bash
|
102
|
+
# [API] - @timeout can be used to know when the action should fail
|
103
|
+
# [API] - @stdout_io can be used to send stdout output
|
104
|
+
# [API] - @stderr_io can be used to send stderr output
|
105
|
+
#
|
106
|
+
# Parameters::
|
107
|
+
# * *bash_cmds* (String): Bash commands to execute
|
108
|
+
def remote_bash(bash_cmds)
|
109
|
+
MyConnectLib.connect_to(@nodes_handler.get_host_ip_of(@node)).run_bash(bash_cmds)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Execute an interactive shell on the remote node
|
113
|
+
# [API] - This method is mandatory
|
114
|
+
# [API] - If defined, then with_connection_to has been called before this method.
|
115
|
+
# [API] - @cmd_runner can be used
|
116
|
+
# [API] - @nodes_handler can be used
|
117
|
+
# [API] - @node can be used to access the node on which we execute the remote bash
|
118
|
+
# [API] - @timeout can be used to know when the action should fail
|
119
|
+
# [API] - @stdout_io can be used to send stdout output
|
120
|
+
# [API] - @stderr_io can be used to send stderr output
|
121
|
+
def remote_interactive
|
122
|
+
MyConnectLib.connect_to(@nodes_handler.get_host_ip_of(@node)).interactive
|
123
|
+
end
|
124
|
+
|
125
|
+
# Copy a file to the remote node in a directory
|
126
|
+
# [API] - This method is mandatory
|
127
|
+
# [API] - If defined, then with_connection_to has been called before this method.
|
128
|
+
# [API] - @cmd_runner can be used
|
129
|
+
# [API] - @nodes_handler can be used
|
130
|
+
# [API] - @node can be used to access the node on which we execute the remote bash
|
131
|
+
# [API] - @timeout can be used to know when the action should fail
|
132
|
+
# [API] - @stdout_io can be used to send stdout output
|
133
|
+
# [API] - @stderr_io can be used to send stderr output
|
134
|
+
#
|
135
|
+
# Parameters::
|
136
|
+
# * *from* (String): Local file to copy
|
137
|
+
# * *to* (String): Remote directory to copy to
|
138
|
+
# * *sudo* (Boolean): Do we use sudo to copy? [default: false]
|
139
|
+
# * *owner* (String or nil): Owner to be used when copying the files, or nil for current one [default: nil]
|
140
|
+
# * *group* (String or nil): Group to be used when copying the files, or nil for current one [default: nil]
|
141
|
+
def remote_copy(from, to, sudo: false, owner: nil, group: nil)
|
142
|
+
MyConnectLib.connect_to(
|
143
|
+
@nodes_handler.get_host_ip_of(@node),
|
144
|
+
sudo: sudo,
|
145
|
+
user: owner,
|
146
|
+
group: group
|
147
|
+
).cp from, to
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
@@ -0,0 +1,702 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'digest'
|
3
|
+
|
4
|
+
module HybridPlatformsConductor
|
5
|
+
|
6
|
+
module HpcPlugins
|
7
|
+
|
8
|
+
module Connector
|
9
|
+
|
10
|
+
# Connect to node using SSH
|
11
|
+
class Ssh < HybridPlatformsConductor::Connector
|
12
|
+
|
13
|
+
module PlatformsDslSsh
|
14
|
+
|
15
|
+
# Initialize the DSL
|
16
|
+
def init_ssh
|
17
|
+
# List of gateway configurations, per gateway config name
|
18
|
+
# Hash<Symbol, String>
|
19
|
+
@gateways = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
# Register a new gateway configuration
|
23
|
+
#
|
24
|
+
# Parameters::
|
25
|
+
# * *gateway_conf* (Symbol): Name of the gateway configuration
|
26
|
+
# * *ssh_def_erb* (String): Corresponding SSH ERB configuration
|
27
|
+
def gateway(gateway_conf, ssh_def_erb)
|
28
|
+
raise "Gateway #{gateway_conf} already defined to #{@gateways[gateway_conf]}" if @gateways.key?(gateway_conf)
|
29
|
+
@gateways[gateway_conf] = ssh_def_erb
|
30
|
+
end
|
31
|
+
|
32
|
+
# Get the list of known gateway configurations
|
33
|
+
#
|
34
|
+
# Result::
|
35
|
+
# * Array<Symbol>: List of known gateway configuration names
|
36
|
+
def known_gateways
|
37
|
+
@gateways.keys
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get the SSH configuration for a given gateway configuration name and a list of variables that could be used in the gateway template.
|
41
|
+
#
|
42
|
+
# Parameters::
|
43
|
+
# * *gateway_conf* (Symbol): Name of the gateway configuration.
|
44
|
+
# * *variables* (Hash<Symbol,Object>): The possible variables to interpolate in the ERB gateway template [default = {}].
|
45
|
+
# Result::
|
46
|
+
# * String: The corresponding SSH configuration
|
47
|
+
def ssh_for_gateway(gateway_conf, variables = {})
|
48
|
+
erb_context = self.clone
|
49
|
+
def erb_context.get_binding
|
50
|
+
binding
|
51
|
+
end
|
52
|
+
variables.each do |var_name, var_value|
|
53
|
+
erb_context.instance_variable_set("@#{var_name}".to_sym, var_value)
|
54
|
+
end
|
55
|
+
ERB.new(@gateways[gateway_conf]).result(erb_context.get_binding)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
self.extend_config_dsl_with PlatformsDslSsh, :init_ssh
|
60
|
+
|
61
|
+
# Name of the gateway user to be used. [default: ENV['hpc_ssh_gateway_user'] or ubradm]
|
62
|
+
# String
|
63
|
+
attr_accessor :ssh_gateway_user
|
64
|
+
|
65
|
+
# Name of the gateways configuration, or nil if no gateway. [default: ENV['hpc_ssh_gateways_conf'] or nil]
|
66
|
+
# Symbol or nil
|
67
|
+
attr_accessor :ssh_gateways_conf
|
68
|
+
|
69
|
+
# User name used in SSH connections. [default: ENV['hpc_ssh_user'] or ENV['USER']]
|
70
|
+
# String
|
71
|
+
attr_accessor :ssh_user
|
72
|
+
|
73
|
+
# Do we use strict host key checking in our SSH commands? [default: true]
|
74
|
+
# Boolean
|
75
|
+
attr_accessor :ssh_strict_host_key_checking
|
76
|
+
|
77
|
+
# Do we use the control master? [default: true]
|
78
|
+
# Boolean
|
79
|
+
attr_accessor :ssh_use_control_master
|
80
|
+
|
81
|
+
# Passwords to be used, per node [default: {}]
|
82
|
+
# Hash<String, String>
|
83
|
+
attr_accessor :passwords
|
84
|
+
|
85
|
+
# Do we expect some connections to require password authentication? [default: false]
|
86
|
+
# Boolean
|
87
|
+
attr_accessor :auth_password
|
88
|
+
|
89
|
+
# String: Sub-path of the system's temporary directory where temporary SSH config are generated
|
90
|
+
TMP_SSH_SUB_DIR = 'hpc_ssh'
|
91
|
+
|
92
|
+
# Initialize the connector.
|
93
|
+
# This can be used to initialize global variables that are used for this connector
|
94
|
+
# [API] - This method is optional
|
95
|
+
# [API] - @cmd_runner can be used
|
96
|
+
# [API] - @nodes_handler can be used
|
97
|
+
def init
|
98
|
+
# Default values
|
99
|
+
@ssh_user = ENV['hpc_ssh_user']
|
100
|
+
@ssh_user = ENV['USER'] if @ssh_user.nil? || @ssh_user.empty?
|
101
|
+
@ssh_use_control_master = true
|
102
|
+
@ssh_strict_host_key_checking = true
|
103
|
+
@passwords = {}
|
104
|
+
@auth_password = false
|
105
|
+
@ssh_gateways_conf = ENV['hpc_ssh_gateways_conf'].nil? ? nil : ENV['hpc_ssh_gateways_conf'].to_sym
|
106
|
+
@ssh_gateway_user = ENV['hpc_ssh_gateway_user'].nil? ? 'ubradm' : ENV['hpc_ssh_gateway_user']
|
107
|
+
# The map of existing ssh directories that have been created, per node that can access them
|
108
|
+
# Array< String, Array<String> >
|
109
|
+
@ssh_dirs = {}
|
110
|
+
# Mutex protecting the map to make sure it's thread-safe
|
111
|
+
@ssh_dirs_mutex = Mutex.new
|
112
|
+
# Temporary directory used by all ActionsExecutors, even from different processes
|
113
|
+
@tmp_dir = "#{Dir.tmpdir}/#{TMP_SSH_SUB_DIR}"
|
114
|
+
FileUtils.mkdir_p @tmp_dir
|
115
|
+
end
|
116
|
+
|
117
|
+
# Complete an option parser with options meant to control this connector
|
118
|
+
# [API] - This method is optional
|
119
|
+
# [API] - @cmd_runner can be used
|
120
|
+
# [API] - @nodes_handler can be used
|
121
|
+
#
|
122
|
+
# Parameters::
|
123
|
+
# * *options_parser* (OptionParser): The option parser to complete
|
124
|
+
def options_parse(options_parser)
|
125
|
+
options_parser.on('-g', '--ssh-gateway-user USER', "Name of the gateway user to be used by the gateways. Can also be set from environment variable hpc_ssh_gateway_user. Defaults to #{@ssh_gateway_user}.") do |user|
|
126
|
+
@ssh_gateway_user = user
|
127
|
+
end
|
128
|
+
options_parser.on('-j', '--ssh-no-control-master', 'If used, don\'t create SSH control masters for connections.') do
|
129
|
+
@ssh_use_control_master = false
|
130
|
+
end
|
131
|
+
options_parser.on('-q', '--ssh-no-host-key-checking', 'If used, don\'t check for SSH host keys.') do
|
132
|
+
@ssh_strict_host_key_checking = false
|
133
|
+
end
|
134
|
+
options_parser.on('-u', '--ssh-user USER', 'Name of user to be used in SSH connections (defaults to hpc_ssh_user or USER environment variables)') do |user|
|
135
|
+
@ssh_user = user
|
136
|
+
end
|
137
|
+
options_parser.on('-w', '--password', 'If used, then expect SSH connections to ask for a password.') do
|
138
|
+
@auth_password = true
|
139
|
+
end
|
140
|
+
options_parser.on('-y', '--ssh-gateways-conf GATEWAYS_CONF', "Name of the gateways configuration to be used. Can also be set from environment variable hpc_ssh_gateways_conf.") do |gateway|
|
141
|
+
@ssh_gateways_conf = gateway.to_sym
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Validate that parsed parameters are valid
|
146
|
+
# [API] - This method is optional
|
147
|
+
# [API] - @cmd_runner can be used
|
148
|
+
# [API] - @nodes_handler can be used
|
149
|
+
def validate_params
|
150
|
+
raise 'No SSH user name specified. Please use --ssh-user option or hpc_ssh_user environment variable to set it.' if @ssh_user.nil? || @ssh_user.empty?
|
151
|
+
known_gateways = @config.known_gateways
|
152
|
+
raise "Unknown gateway configuration provided: #{@ssh_gateways_conf}. Possible values are: #{known_gateways.join(', ')}." if !@ssh_gateways_conf.nil? && !known_gateways.include?(@ssh_gateways_conf)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Select nodes where this connector can connect.
|
156
|
+
# [API] - This method is mandatory
|
157
|
+
# [API] - @cmd_runner can be used
|
158
|
+
# [API] - @nodes_handler can be used
|
159
|
+
#
|
160
|
+
# Parameters::
|
161
|
+
# * *nodes* (Array<String>): List of candidate nodes
|
162
|
+
# Result::
|
163
|
+
# * Array<String>: List of nodes we can connect to from the candidates
|
164
|
+
def connectable_nodes_from(nodes)
|
165
|
+
@nodes_handler.prefetch_metadata_of nodes, :host_ip
|
166
|
+
nodes.select { |node| @nodes_handler.get_host_ip_of(node) }
|
167
|
+
end
|
168
|
+
|
169
|
+
# Prepare connections to a given set of nodes.
|
170
|
+
# Useful to prefetch metadata or open bulk connections.
|
171
|
+
# [API] - This method is optional
|
172
|
+
# [API] - @cmd_runner can be used
|
173
|
+
# [API] - @nodes_handler can be used
|
174
|
+
#
|
175
|
+
# Parameters::
|
176
|
+
# * *nodes* (Array<String>): Nodes to prepare the connection to
|
177
|
+
# * *no_exception* (Boolean): Should we still continue if some nodes have connection errors? [default: false]
|
178
|
+
# * Proc: Code called with the connections prepared.
|
179
|
+
# * Parameters::
|
180
|
+
# * *connected_nodes* (Array<String>): The list of connected nodes (should be equal to nodes unless no_exception == true and some nodes failed to connect)
|
181
|
+
def with_connection_to(nodes, no_exception: false)
|
182
|
+
with_ssh_master_to(nodes, no_exception: no_exception) do |connected_nodes|
|
183
|
+
yield connected_nodes
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Integer: Max size for an argument that can be executed without getting through an intermediary file
|
188
|
+
MAX_CMD_ARG_LENGTH = 131_055
|
189
|
+
|
190
|
+
# Run bash commands on a given node.
|
191
|
+
# [API] - This method is mandatory
|
192
|
+
# [API] - If defined, then with_connection_to has been called before this method.
|
193
|
+
# [API] - @cmd_runner can be used
|
194
|
+
# [API] - @nodes_handler can be used
|
195
|
+
# [API] - @node can be used to access the node on which we execute the remote bash
|
196
|
+
# [API] - @timeout can be used to know when the action should fail
|
197
|
+
# [API] - @stdout_io can be used to send stdout output
|
198
|
+
# [API] - @stderr_io can be used to send stderr output
|
199
|
+
#
|
200
|
+
# Parameters::
|
201
|
+
# * *bash_cmds* (String): Bash commands to execute
|
202
|
+
def remote_bash(bash_cmds)
|
203
|
+
ssh_cmd = "#{ssh_exec} #{ssh_url} /bin/bash <<'EOF'\n#{bash_cmds}\nEOF"
|
204
|
+
# Due to a limitation of Process.spawn, each individual argument is limited to 128KB of size.
|
205
|
+
# Therefore we need to make sure that if bash_cmds exceeds MAX_CMD_ARG_LENGTH bytes (considering EOF chars) then we use an intermediary shell script to store the commands.
|
206
|
+
if bash_cmds.size > MAX_CMD_ARG_LENGTH
|
207
|
+
# Write the commands in a file
|
208
|
+
temp_file = "#{Dir.tmpdir}/hpc_temp_cmds_#{Digest::MD5.hexdigest(bash_cmds)}.sh"
|
209
|
+
File.open(temp_file, 'w+') do |file|
|
210
|
+
file.write ssh_cmd
|
211
|
+
file.chmod 0700
|
212
|
+
end
|
213
|
+
begin
|
214
|
+
run_cmd(temp_file)
|
215
|
+
ensure
|
216
|
+
File.unlink(temp_file)
|
217
|
+
end
|
218
|
+
else
|
219
|
+
run_cmd ssh_cmd
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Execute an interactive shell on the remote node
|
224
|
+
# [API] - This method is mandatory
|
225
|
+
# [API] - If defined, then with_connection_to has been called before this method.
|
226
|
+
# [API] - @cmd_runner can be used
|
227
|
+
# [API] - @nodes_handler can be used
|
228
|
+
# [API] - @node can be used to access the node on which we execute the remote bash
|
229
|
+
# [API] - @timeout can be used to know when the action should fail
|
230
|
+
# [API] - @stdout_io can be used to send stdout output
|
231
|
+
# [API] - @stderr_io can be used to send stderr output
|
232
|
+
def remote_interactive
|
233
|
+
interactive_cmd = "#{ssh_exec} #{ssh_url}"
|
234
|
+
out interactive_cmd
|
235
|
+
# As we're not using run_cmd here, make sure we handle the dry_run switch ourselves
|
236
|
+
if @cmd_runner.dry_run
|
237
|
+
out 'Won\'t execute interactive shell in dry_run mode'
|
238
|
+
else
|
239
|
+
system interactive_cmd
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
# Copy a file to the remote node in a directory
|
244
|
+
# [API] - This method is mandatory
|
245
|
+
# [API] - If defined, then with_connection_to has been called before this method.
|
246
|
+
# [API] - @cmd_runner can be used
|
247
|
+
# [API] - @nodes_handler can be used
|
248
|
+
# [API] - @node can be used to access the node on which we execute the remote bash
|
249
|
+
# [API] - @timeout can be used to know when the action should fail
|
250
|
+
# [API] - @stdout_io can be used to send stdout output
|
251
|
+
# [API] - @stderr_io can be used to send stderr output
|
252
|
+
#
|
253
|
+
# Parameters::
|
254
|
+
# * *from* (String): Local file to copy
|
255
|
+
# * *to* (String): Remote directory to copy to
|
256
|
+
# * *sudo* (Boolean): Do we use sudo to copy? [default: false]
|
257
|
+
# * *owner* (String or nil): Owner to be used when copying the files, or nil for current one [default: nil]
|
258
|
+
# * *group* (String or nil): Group to be used when copying the files, or nil for current one [default: nil]
|
259
|
+
def remote_copy(from, to, sudo: false, owner: nil, group: nil)
|
260
|
+
run_cmd <<~EOS
|
261
|
+
cd #{File.dirname(from)} && \
|
262
|
+
tar \
|
263
|
+
--create \
|
264
|
+
--gzip \
|
265
|
+
--file - \
|
266
|
+
#{owner.nil? ? '' : "--owner #{owner}"} \
|
267
|
+
#{group.nil? ? '' : "--group #{group}"} \
|
268
|
+
#{File.basename(from)} | \
|
269
|
+
#{ssh_exec} \
|
270
|
+
#{ssh_url} \
|
271
|
+
\"#{sudo ? 'sudo ' : ''}tar \
|
272
|
+
--extract \
|
273
|
+
--gunzip \
|
274
|
+
--file - \
|
275
|
+
--directory #{to} \
|
276
|
+
--owner root \
|
277
|
+
\"
|
278
|
+
EOS
|
279
|
+
end
|
280
|
+
|
281
|
+
# Get the ssh executable to be used when connecting to the current node
|
282
|
+
#
|
283
|
+
# Result::
|
284
|
+
# * String: The ssh executable
|
285
|
+
def ssh_exec
|
286
|
+
ssh_exec_for @node
|
287
|
+
end
|
288
|
+
|
289
|
+
# Get the ssh URL to be used to connect to the current node
|
290
|
+
#
|
291
|
+
# Result::
|
292
|
+
# * String: The ssh URL connecting to the current node
|
293
|
+
def ssh_url
|
294
|
+
"#{@ssh_user}@hpc.#{@node}"
|
295
|
+
end
|
296
|
+
|
297
|
+
# Get an SSH configuration content giving access to nodes of the platforms with the current configuration
|
298
|
+
#
|
299
|
+
# Parameters::
|
300
|
+
# * *ssh_exec* (String): SSH command to be used [default: 'ssh']
|
301
|
+
# * *known_hosts_file* (String or nil): Path to the known hosts file, or nil for default [default: nil]
|
302
|
+
# * *nodes* (Array<String>): List of nodes to generate the config for [default: @nodes_handler.known_nodes]
|
303
|
+
# Result::
|
304
|
+
# * String: The SSH config
|
305
|
+
def ssh_config(ssh_exec: 'ssh', known_hosts_file: nil, nodes: @nodes_handler.known_nodes)
|
306
|
+
config_content = <<~EOS
|
307
|
+
############
|
308
|
+
# GATEWAYS #
|
309
|
+
############
|
310
|
+
|
311
|
+
#{@ssh_gateways_conf.nil? || !@config.known_gateways.include?(@ssh_gateways_conf) ? '' : @config.ssh_for_gateway(@ssh_gateways_conf, ssh_exec: ssh_exec, user: @ssh_user)}
|
312
|
+
|
313
|
+
#############
|
314
|
+
# ENDPOINTS #
|
315
|
+
#############
|
316
|
+
|
317
|
+
Host *
|
318
|
+
User #{@ssh_user}
|
319
|
+
# Default control socket path to be used when multiplexing SSH connections
|
320
|
+
ControlPath #{control_master_file('%h', '%p', '%r')}
|
321
|
+
#{open_ssh_major_version >= 7 ? 'PubkeyAcceptedKeyTypes +ssh-dss' : ''}
|
322
|
+
#{known_hosts_file.nil? ? '' : "UserKnownHostsFile #{known_hosts_file}"}
|
323
|
+
#{@ssh_strict_host_key_checking ? '' : 'StrictHostKeyChecking no'}
|
324
|
+
|
325
|
+
EOS
|
326
|
+
|
327
|
+
# Add each node
|
328
|
+
# Query for the metadata of all nodes at once
|
329
|
+
@nodes_handler.prefetch_metadata_of nodes, %i[private_ips hostname host_ip description]
|
330
|
+
nodes.sort.each do |node|
|
331
|
+
# Generate the conf for the node
|
332
|
+
connection, gateway, gateway_user = connection_info_for(node)
|
333
|
+
config_content << "# #{node} - #{connection} - #{@nodes_handler.get_description_of(node) || ''}\n"
|
334
|
+
config_content << "Host #{ssh_aliases_for(node).join(' ')}\n"
|
335
|
+
config_content << " Hostname #{connection}\n"
|
336
|
+
config_content << " ProxyCommand #{ssh_exec} -q -W %h:%p #{gateway_user}@#{gateway}\n" unless gateway.nil?
|
337
|
+
if @passwords.key?(node)
|
338
|
+
config_content << " PreferredAuthentications password\n"
|
339
|
+
config_content << " PubkeyAuthentication no\n"
|
340
|
+
end
|
341
|
+
config_content << "\n"
|
342
|
+
end
|
343
|
+
config_content
|
344
|
+
end
|
345
|
+
|
346
|
+
private
|
347
|
+
|
348
|
+
# Is sshpass installed?
|
349
|
+
# Keep a cache of it.
|
350
|
+
#
|
351
|
+
# Result::
|
352
|
+
# * Boolean: Is sshpass installed?
|
353
|
+
def ssh_pass_installed?
|
354
|
+
cache_filled = defined?(@ssh_pass_installed)
|
355
|
+
unless cache_filled
|
356
|
+
exit_code, _stdout, _stderr = @cmd_runner.run_cmd 'sshpass -V', log_to_stdout: log_debug?, no_exception: true
|
357
|
+
@ssh_pass_installed = (exit_code == 0)
|
358
|
+
end
|
359
|
+
@ssh_pass_installed
|
360
|
+
end
|
361
|
+
|
362
|
+
# Get the env system path
|
363
|
+
# Keep a cache of it.
|
364
|
+
#
|
365
|
+
# Result::
|
366
|
+
# * String: The env system path
|
367
|
+
def env_system_path
|
368
|
+
cache_filled = defined?(@env_system_path)
|
369
|
+
unless cache_filled
|
370
|
+
_exit_status, stdout, _stderr = @cmd_runner.run_cmd 'which env', log_to_stdout: log_debug?
|
371
|
+
@env_system_path = stdout.strip
|
372
|
+
end
|
373
|
+
@env_system_path
|
374
|
+
end
|
375
|
+
|
376
|
+
# Get the installed ssh version.
|
377
|
+
# Mock it in case of dry run.
|
378
|
+
# Keep a cache of it.
|
379
|
+
#
|
380
|
+
# Result::
|
381
|
+
# * String: The installed SSH major version
|
382
|
+
def open_ssh_major_version
|
383
|
+
cache_filled = defined?(@open_ssh_major_version)
|
384
|
+
unless cache_filled
|
385
|
+
_exit_status, stdout, _stderr = @cmd_runner.run_cmd 'ssh -V 2>&1', log_to_stdout: log_debug?
|
386
|
+
# Make sure we have a fake value in case of dry-run
|
387
|
+
if @cmd_runner.dry_run
|
388
|
+
log_debug 'Mock OpenSSH version because of dry-run mode'
|
389
|
+
stdout = 'OpenSSH_7.4p1 Debian-10+deb9u7, OpenSSL 1.0.2u 20 Dec 2019'
|
390
|
+
end
|
391
|
+
@open_ssh_major_version = stdout.match(/^OpenSSH_(\d)\..+$/)[1].to_i
|
392
|
+
end
|
393
|
+
@open_ssh_major_version
|
394
|
+
end
|
395
|
+
|
396
|
+
# Return the ssh executable that can be used for a given node
|
397
|
+
#
|
398
|
+
# Parameters::
|
399
|
+
# * *node* (String): The node wanting to access its SSH executable
|
400
|
+
# Result::
|
401
|
+
# * String: The path to the ssh executable that contains the node's config
|
402
|
+
def ssh_exec_for(node)
|
403
|
+
"#{@ssh_dirs[node].last}/ssh"
|
404
|
+
end
|
405
|
+
|
406
|
+
# Max number of threads to use to parallelize ControlMaster connections
|
407
|
+
MAX_THREADS_CONTROL_MASTER = 32
|
408
|
+
|
409
|
+
# Max number of retries because a system is booting up
|
410
|
+
MAX_RETRIES_FOR_BOOT = 10
|
411
|
+
|
412
|
+
# Time in seconds to wait between different retries because system is booting up
|
413
|
+
WAIT_TIME_FOR_BOOT = 10
|
414
|
+
|
415
|
+
# Open an SSH control master to multiplex connections to a given list of nodes.
|
416
|
+
# This method is re-entrant and reuses the same control masters.
|
417
|
+
# It is multi-processes:
|
418
|
+
# * A file-mutex is used to keep track of all processes connecting to a user@node.
|
419
|
+
# * When the last process has finished using the control master, it closes it.
|
420
|
+
#
|
421
|
+
# Parameters::
|
422
|
+
# * *nodes* (String or Array<String>): The nodes (or single node) for which we open the Control Master.
|
423
|
+
# * *timeout* (Integer or nil): Timeout in seconds, or nil if none. [default: nil]
|
424
|
+
# * *no_exception* (Boolean): If true, then don't raise any exception in case of impossible connection to the ControlMaster. [default: false]
|
425
|
+
# * Proc: Code called while the ControlMaster exists.
|
426
|
+
# * Parameters::
|
427
|
+
# * *connected_nodes* (Array<String>): The list of connected nodes (should be equal to nodes unless no_exception == true and some nodes failed to connect)
|
428
|
+
def with_ssh_master_to(nodes, timeout: nil, no_exception: false)
|
429
|
+
nodes = [nodes] if nodes.is_a?(String)
|
430
|
+
with_platforms_ssh(nodes: nodes) do
|
431
|
+
# List of user_ids that acquired a lock, per node
|
432
|
+
user_locks = {}
|
433
|
+
user_locks_mutex = Mutex.new
|
434
|
+
begin
|
435
|
+
if @ssh_use_control_master
|
436
|
+
@nodes_handler.for_each_node_in(
|
437
|
+
nodes,
|
438
|
+
parallel: true,
|
439
|
+
nbr_threads_max: MAX_THREADS_CONTROL_MASTER,
|
440
|
+
progress: log_debug? ? 'Getting SSH ControlMasters' : nil
|
441
|
+
) do |node|
|
442
|
+
with_lock_on_control_master_for(node) do |current_users, user_id|
|
443
|
+
working_master = false
|
444
|
+
ssh_exec = ssh_exec_for(node)
|
445
|
+
ssh_url = "#{@ssh_user}@hpc.#{node}"
|
446
|
+
if current_users.empty?
|
447
|
+
log_debug "[ ControlMaster - #{ssh_url} ] - Creating SSH ControlMaster..."
|
448
|
+
# Create the control master
|
449
|
+
ssh_control_master_start_cmd = "#{ssh_exec}#{@passwords.key?(node) || @auth_password ? '' : ' -o BatchMode=yes'} -o ControlMaster=yes -o ControlPersist=yes #{ssh_url} true"
|
450
|
+
exit_status = nil
|
451
|
+
idx_try = 0
|
452
|
+
loop do
|
453
|
+
stderr = nil
|
454
|
+
exit_status, _stdout, stderr = @cmd_runner.run_cmd ssh_control_master_start_cmd, log_to_stdout: log_debug?, no_exception: true, timeout: timeout
|
455
|
+
if exit_status == 0
|
456
|
+
break
|
457
|
+
elsif stderr =~ /System is booting up/
|
458
|
+
if idx_try == MAX_RETRIES_FOR_BOOT
|
459
|
+
if no_exception
|
460
|
+
break
|
461
|
+
else
|
462
|
+
raise ActionsExecutor::ConnectionError, "Tried #{idx_try} times to create SSH Control Master with #{ssh_control_master_start_cmd} but system says it's booting up."
|
463
|
+
end
|
464
|
+
end
|
465
|
+
# Wait a bit and try again
|
466
|
+
idx_try += 1
|
467
|
+
log_debug "[ ControlMaster - #{ssh_url} ] - System is booting up (try ##{idx_try}). Wait #{WAIT_TIME_FOR_BOOT} seconds before trying ControlMaster's creation again."
|
468
|
+
sleep WAIT_TIME_FOR_BOOT
|
469
|
+
elsif no_exception
|
470
|
+
break
|
471
|
+
else
|
472
|
+
raise ActionsExecutor::ConnectionError, "Error while starting SSH Control Master with #{ssh_control_master_start_cmd}: #{stderr.strip}"
|
473
|
+
end
|
474
|
+
end
|
475
|
+
if exit_status == 0
|
476
|
+
log_debug "[ ControlMaster - #{ssh_url} ] - ControlMaster created"
|
477
|
+
working_master = true
|
478
|
+
else
|
479
|
+
log_error "[ ControlMaster - #{ssh_url} ] - ControlMaster could not be started"
|
480
|
+
end
|
481
|
+
else
|
482
|
+
# The control master should already exist
|
483
|
+
log_debug "[ ControlMaster - #{ssh_url} ] - Using existing SSH ControlMaster..."
|
484
|
+
# Test that it is working
|
485
|
+
ssh_control_master_check_cmd = "#{ssh_exec} -O check #{ssh_url}"
|
486
|
+
begin
|
487
|
+
exit_status, _stdout, _stderr = @cmd_runner.run_cmd ssh_control_master_check_cmd, log_to_stdout: log_debug?, no_exception: no_exception, timeout: timeout
|
488
|
+
rescue CmdRunner::UnexpectedExitCodeError
|
489
|
+
raise ActionsExecutor::ConnectionError, "Error while checking SSH Control Master with #{ssh_control_master_check_cmd}"
|
490
|
+
end
|
491
|
+
if exit_status == 0
|
492
|
+
log_debug "[ ControlMaster - #{ssh_url} ] - ControlMaster checked ok"
|
493
|
+
working_master = true
|
494
|
+
else
|
495
|
+
log_error "[ ControlMaster - #{ssh_url} ] - ControlMaster could not be used"
|
496
|
+
end
|
497
|
+
end
|
498
|
+
# Make sure we register ourselves among the users if the master is working
|
499
|
+
if working_master
|
500
|
+
user_locks_mutex.synchronize { user_locks[node] = user_id }
|
501
|
+
true
|
502
|
+
else
|
503
|
+
false
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end
|
507
|
+
end
|
508
|
+
yield user_locks.keys
|
509
|
+
ensure
|
510
|
+
user_locks_mutex.synchronize do
|
511
|
+
user_locks.each do |node, user_id|
|
512
|
+
with_lock_on_control_master_for(node, user_id: user_id) do |current_users, user_id|
|
513
|
+
ssh_url = "#{@ssh_user}@hpc.#{node}"
|
514
|
+
log_warn "[ ControlMaster - #{ssh_url} ] - Current process/thread was not part of the ControlMaster users anymore whereas it should have been" unless current_users.include?(user_id)
|
515
|
+
remaining_users = current_users - [user_id]
|
516
|
+
if remaining_users.empty?
|
517
|
+
# Stop the ControlMaster
|
518
|
+
log_debug "[ ControlMaster - #{ssh_url} ] - Stopping ControlMaster..."
|
519
|
+
# Dumb verbose ssh! Tricky trick to just silence what is useless.
|
520
|
+
# Don't fail if the connection close fails (but still log the error), as it can be seen as only a warning: it means the connection was closed anyway.
|
521
|
+
@cmd_runner.run_cmd "#{ssh_exec_for(node)} -O exit #{ssh_url} 2>&1 | grep -v 'Exit request sent.'", log_to_stdout: log_debug?, expected_code: 1, timeout: timeout, no_exception: true
|
522
|
+
log_debug "[ ControlMaster - #{ssh_url} ] - ControlMaster stopped"
|
523
|
+
# Uncomment if you want to test that the connection has been closed
|
524
|
+
# @cmd_runner.run_cmd "#{ssh_exec_for(node)} -O check #{ssh_url}", log_to_stdout: log_debug?, expected_code: 255, timeout: timeout
|
525
|
+
else
|
526
|
+
log_debug "[ ControlMaster - #{ssh_url} ] - Leaving ControlMaster started as #{remaining_users.size} processes/threads are still using it."
|
527
|
+
end
|
528
|
+
false
|
529
|
+
end
|
530
|
+
end
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
# Get the lock to access users of a given node's ControlMaster.
|
537
|
+
# Make sure the lock is released when exiting client code.
|
538
|
+
# Handle stalled ControlMaster files as well.
|
539
|
+
#
|
540
|
+
# Parameters::
|
541
|
+
# * *node* (String): Node to access
|
542
|
+
# * *user_id* (String or nil): User ID that wants to access the lock, or nil to get a new generated one. [default: nil]
|
543
|
+
# * Proc: The code to be called with lock taken
|
544
|
+
# * Parameters::
|
545
|
+
# * *current_users* (Array<String>): Current user IDs having the lock
|
546
|
+
# * *user_id* (String): The user ID
|
547
|
+
# * Result::
|
548
|
+
# * Boolean: Should we stay as users of the lock?
|
549
|
+
def with_lock_on_control_master_for(node, user_id: nil)
|
550
|
+
user_id = "#{Process.pid}.#{Thread.current.object_id}.#{SecureRandom.uuid}" if user_id.nil?
|
551
|
+
control_master_users_file = "#{@tmp_dir}/#{@ssh_user}.#{node}.users"
|
552
|
+
# Make sure we remove our token for this control master
|
553
|
+
Futex.new(control_master_users_file).open do
|
554
|
+
# TODO: Add test case when control file is missing ad when it is stale
|
555
|
+
# Get the list of existing process/thread ids using this control master
|
556
|
+
existing_users = File.exist?(control_master_users_file) ? File.read(control_master_users_file).split("\n") : []
|
557
|
+
ssh_url = "#{@ssh_user}@hpc.#{node}"
|
558
|
+
control_path_file = control_master_file(connection_info_for(node).first, '22', @ssh_user)
|
559
|
+
if existing_users.empty?
|
560
|
+
# Make sure there is no stale one.
|
561
|
+
if File.exist?(control_path_file)
|
562
|
+
log_warn "[ ControlMaster - #{ssh_url} ] - Removing stale SSH control file #{control_path_file}"
|
563
|
+
File.unlink control_path_file
|
564
|
+
end
|
565
|
+
elsif !File.exist?(control_path_file)
|
566
|
+
# Make sure the control file is still present, otherwise it means we should not have users
|
567
|
+
log_warn "[ ControlMaster - #{ssh_url} ] - Missing SSH control file #{control_path_file} whereas the following users were supposed to use it: #{existing_users.join(', ')}"
|
568
|
+
existing_users = []
|
569
|
+
end
|
570
|
+
confirmed_user = yield existing_users, user_id
|
571
|
+
user_already_included = existing_users.include?(user_id)
|
572
|
+
existing_users_to_update = nil
|
573
|
+
if confirmed_user
|
574
|
+
existing_users_to_update = existing_users + [user_id] unless user_already_included
|
575
|
+
elsif user_already_included
|
576
|
+
existing_users_to_update = existing_users - [user_id]
|
577
|
+
end
|
578
|
+
File.write(control_master_users_file, existing_users_to_update.join("\n")) if existing_users_to_update
|
579
|
+
end
|
580
|
+
user_id
|
581
|
+
end
|
582
|
+
|
583
|
+
# Return the name of a ControlMaster file used for a given host, port and user
|
584
|
+
#
|
585
|
+
# Parameters::
|
586
|
+
# * *host* (String): The host
|
587
|
+
# * *port* (String): The port. Can be a string as ssh config uses wildchars.
|
588
|
+
# * *user* (String): The user
|
589
|
+
def control_master_file(host, port, user)
|
590
|
+
"#{@tmp_dir}/hpc_actions_executor_mux_#{host}_#{port}_#{user}"
|
591
|
+
end
|
592
|
+
|
593
|
+
# Provide a bootstrapped ssh executable that includes an SSH config allowing access to nodes.
|
594
|
+
#
|
595
|
+
# Parameters::
|
596
|
+
# * *nodes* (Array<String>): List of nodes for which we need the config to be created [default: @nodes_handler.known_nodes ]
|
597
|
+
# * Proc: Code called with the given ssh executable to be used to get TI config
|
598
|
+
def with_platforms_ssh(nodes: @nodes_handler.known_nodes)
|
599
|
+
platforms_ssh_dir = Dir.mktmpdir("platforms_ssh_#{self.object_id}", @tmp_dir)
|
600
|
+
log_debug "Generate temporary SSH configuration in #{platforms_ssh_dir} for #{nodes.size} nodes..."
|
601
|
+
begin
|
602
|
+
ssh_conf_file = "#{platforms_ssh_dir}/ssh_config"
|
603
|
+
ssh_exec_file = "#{platforms_ssh_dir}/ssh"
|
604
|
+
known_hosts_file = "#{platforms_ssh_dir}/known_hosts"
|
605
|
+
raise 'sshpass is not installed. Can\'t use automatic passwords handling without it. Please install it.' if !@passwords.empty? && !ssh_pass_installed?
|
606
|
+
File.open(ssh_exec_file, 'w+', 0700) do |file|
|
607
|
+
file.puts "#!#{env_system_path} bash"
|
608
|
+
# TODO: Make a mechanism that uses sshpass and the correct password only for the correct hostname (this requires parsing ssh parameters $*).
|
609
|
+
# Current implementation is much simpler: it uses sshpass if at least 1 password is needed, and always uses the first password.
|
610
|
+
# So far it is enough for our usage as we intend to use this only when deploying first time using root account, and all root accounts will have the same password.
|
611
|
+
file.puts "#{@passwords.empty? ? '' : "sshpass -p#{@passwords.first[1]} "}ssh -F #{ssh_conf_file} $*"
|
612
|
+
end
|
613
|
+
File.write(ssh_conf_file, ssh_config(ssh_exec: ssh_exec_file, known_hosts_file: known_hosts_file, nodes: nodes))
|
614
|
+
# Make sure all host keys are setup in the known hosts file
|
615
|
+
File.open(known_hosts_file, 'w+', 0700) do |file|
|
616
|
+
if @ssh_strict_host_key_checking
|
617
|
+
# In the case of an overriden connection, get host key for the overriden connection
|
618
|
+
@nodes_handler.prefetch_metadata_of nodes, :host_keys
|
619
|
+
nodes.sort.each do |node|
|
620
|
+
host_keys = @nodes_handler.get_host_keys_of(node)
|
621
|
+
if host_keys && !host_keys.empty?
|
622
|
+
connection, _gateway, _gateway_user = connection_info_for(node)
|
623
|
+
host_keys.each do |host_key|
|
624
|
+
file.puts "#{connection} #{host_key}"
|
625
|
+
end
|
626
|
+
end
|
627
|
+
end
|
628
|
+
end
|
629
|
+
end
|
630
|
+
# Mark this directory as accessible for the nodes
|
631
|
+
@ssh_dirs_mutex.synchronize do
|
632
|
+
nodes.each do |node|
|
633
|
+
@ssh_dirs[node] = [] unless @ssh_dirs.key?(node)
|
634
|
+
@ssh_dirs[node] << platforms_ssh_dir
|
635
|
+
end
|
636
|
+
end
|
637
|
+
yield
|
638
|
+
ensure
|
639
|
+
# It's very important to remove the directory as soon as it is useless, as it contains eventual passwords
|
640
|
+
FileUtils.remove_entry platforms_ssh_dir
|
641
|
+
# Mark this directory as not accessible anymore for the nodes
|
642
|
+
@ssh_dirs_mutex.synchronize do
|
643
|
+
nodes.each do |node|
|
644
|
+
# Check that the key exists as it is possible that an exception occurred before setting @ssh_dirs
|
645
|
+
@ssh_dirs[node].delete(platforms_ssh_dir) if @ssh_dirs.key?(node)
|
646
|
+
end
|
647
|
+
end
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
# Get the connection information for a given node.
|
652
|
+
#
|
653
|
+
# Parameters::
|
654
|
+
# * *node* (String): The node to access
|
655
|
+
# Result::
|
656
|
+
# * String: The real hostname or IP to be used to connect
|
657
|
+
# * String or nil: The gateway name to be used (should be defined by the gateways configurations), or nil if no gateway to be used.
|
658
|
+
# * String or nil: The gateway user to be used, or nil if none.
|
659
|
+
def connection_info_for(node)
|
660
|
+
connection =
|
661
|
+
if @nodes_handler.get_host_ip_of(node)
|
662
|
+
@nodes_handler.get_host_ip_of(node)
|
663
|
+
elsif @nodes_handler.get_private_ips_of(node)
|
664
|
+
@nodes_handler.get_private_ips_of(node).first
|
665
|
+
elsif @nodes_handler.get_hostname_of(node)
|
666
|
+
@nodes_handler.get_hostname_of(node)
|
667
|
+
else
|
668
|
+
raise "No connection possible to #{node}"
|
669
|
+
end
|
670
|
+
gateway = @nodes_handler.get_gateway_of node
|
671
|
+
gateway_user = @nodes_handler.get_gateway_user_of node
|
672
|
+
gateway_user = @ssh_gateway_user if !gateway.nil? && gateway_user.nil?
|
673
|
+
[connection, gateway, gateway_user]
|
674
|
+
end
|
675
|
+
|
676
|
+
# Get the possible SSH aliases for a given node.
|
677
|
+
#
|
678
|
+
# Parameters::
|
679
|
+
# * *node* (String): The node to access
|
680
|
+
# Result::
|
681
|
+
# * Array<String>: The list of possible SSH aliases
|
682
|
+
def ssh_aliases_for(node)
|
683
|
+
aliases = ["hpc.#{node}"]
|
684
|
+
# Make sure the real hostname that could be used by other processes also route to the real IP.
|
685
|
+
# Especially useful when connections are overriden to a different IP.
|
686
|
+
aliases << @nodes_handler.get_hostname_of(node) if @nodes_handler.get_hostname_of(node)
|
687
|
+
if @nodes_handler.get_private_ips_of(node)
|
688
|
+
aliases.concat(@nodes_handler.get_private_ips_of(node).map do |ip|
|
689
|
+
split_ip = ip.split('.').map(&:to_i)
|
690
|
+
"hpc.#{(split_ip[0..1] == [172, 16] ? split_ip[2..3] : split_ip).join('.')}"
|
691
|
+
end)
|
692
|
+
end
|
693
|
+
aliases
|
694
|
+
end
|
695
|
+
|
696
|
+
end
|
697
|
+
|
698
|
+
end
|
699
|
+
|
700
|
+
end
|
701
|
+
|
702
|
+
end
|