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,188 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'tty-command'
|
3
|
+
require 'hybrid_platforms_conductor/logger_helpers'
|
4
|
+
require 'hybrid_platforms_conductor/io_router'
|
5
|
+
|
6
|
+
module HybridPlatformsConductor
|
7
|
+
|
8
|
+
class CmdRunner
|
9
|
+
|
10
|
+
class UnexpectedExitCodeError < StandardError
|
11
|
+
end
|
12
|
+
|
13
|
+
class TimeoutError < StandardError
|
14
|
+
end
|
15
|
+
|
16
|
+
include LoggerHelpers
|
17
|
+
|
18
|
+
# Return the executables prefix to use to execute commands
|
19
|
+
#
|
20
|
+
# Result::
|
21
|
+
# * String: The executable prefix
|
22
|
+
def self.executables_prefix
|
23
|
+
$0.include?('/') ? "#{File.dirname($0)}/" : ''
|
24
|
+
end
|
25
|
+
|
26
|
+
# Dry-run switch. When true, then commands are just printed out without being executed.
|
27
|
+
# Boolean
|
28
|
+
attr_accessor :dry_run
|
29
|
+
|
30
|
+
# Constructor
|
31
|
+
#
|
32
|
+
# Parameters::
|
33
|
+
# * *logger* (Logger): Logger to be used [default = Logger.new(STDOUT)]
|
34
|
+
# * *logger_stderr* (Logger): Logger to be used for stderr [default = Logger.new(STDERR)]
|
35
|
+
def initialize(logger: Logger.new(STDOUT), logger_stderr: Logger.new(STDERR))
|
36
|
+
init_loggers(logger, logger_stderr)
|
37
|
+
@dry_run = false
|
38
|
+
end
|
39
|
+
|
40
|
+
# Complete an option parser with options meant to control this Actions Executor
|
41
|
+
#
|
42
|
+
# Parameters::
|
43
|
+
# * *options_parser* (OptionParser): The option parser to complete
|
44
|
+
# * *parallel* (Boolean): Do we activate options regarding parallel execution? [default = true]
|
45
|
+
def options_parse(options_parser, parallel: true)
|
46
|
+
options_parser.separator ''
|
47
|
+
options_parser.separator 'Command runner options:'
|
48
|
+
options_parser.on('-s', '--show-commands', 'Display the commands that would be run instead of running them') do
|
49
|
+
@dry_run = true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Run an external command.
|
54
|
+
# Handle dry-run mode, timeout, and check for an expected return code.
|
55
|
+
# Raise an exception if the exit status is not the expected one.
|
56
|
+
#
|
57
|
+
# Parameters::
|
58
|
+
# * *cmd* (String): Command to be run
|
59
|
+
# * *log_to_file* (String or nil): Log file capturing stdout or stderr (or nil for none). [default: nil]
|
60
|
+
# * *log_to_stdout* (Boolean): Do we send the output to stdout? [default: true]
|
61
|
+
# * *log_stdout_to_io* (IO or nil): IO to send command's stdout to, or nil for none. [default: nil]
|
62
|
+
# * *log_stderr_to_io* (IO or nil): IO to send command's stderr to, or nil for none. [default: nil]
|
63
|
+
# * *expected_code* (Integer, Symbol or Array<Integer or Symbol>): Return codes (or single one) that is expected [default: 0]
|
64
|
+
# Symbol error codes can be used:
|
65
|
+
# * *command_error*: The command could not be executed
|
66
|
+
# * *timeout*: The command ended in timeout
|
67
|
+
# * *timeout* (Integer or nil): Timeout to apply for the command to be run, or nil for no timeout [default: nil]
|
68
|
+
# * *no_exception* (Boolean): If true, don't throw exception in case of error [default: false]
|
69
|
+
# Result::
|
70
|
+
# * Integer or Symbol: Exit status of the command, or Symbol in case of error. In case of dry-run mode the expected code is returned without executing anything.
|
71
|
+
# * String: Standard output of the command
|
72
|
+
# * String: Standard error output of the command (can be a descriptive message of the error in case of error)
|
73
|
+
def run_cmd(
|
74
|
+
cmd,
|
75
|
+
log_to_file: nil,
|
76
|
+
log_to_stdout: true,
|
77
|
+
log_stdout_to_io: nil,
|
78
|
+
log_stderr_to_io: nil,
|
79
|
+
expected_code: 0,
|
80
|
+
timeout: nil,
|
81
|
+
no_exception: false
|
82
|
+
)
|
83
|
+
expected_code = [expected_code] unless expected_code.is_a?(Array)
|
84
|
+
if @dry_run
|
85
|
+
out cmd
|
86
|
+
return expected_code.first, '', ''
|
87
|
+
else
|
88
|
+
log_debug "#{timeout.nil? ? '' : "[ Timeout #{timeout} ] - "}#{cmd.light_cyan.bold}"
|
89
|
+
exit_status = nil
|
90
|
+
cmd_stdout = nil
|
91
|
+
cmd_stderr = nil
|
92
|
+
file_output =
|
93
|
+
if log_to_file
|
94
|
+
if File.exist?(log_to_file)
|
95
|
+
File.open(log_to_file, 'a')
|
96
|
+
else
|
97
|
+
FileUtils.mkdir_p(File.dirname(log_to_file))
|
98
|
+
File.open(log_to_file, 'w')
|
99
|
+
end
|
100
|
+
else
|
101
|
+
nil
|
102
|
+
end
|
103
|
+
start_time = Time.now if log_debug?
|
104
|
+
begin
|
105
|
+
# Make sure we keep a trace of stdout and stderr, even if it was not asked, just to use it in case of exceptions raised
|
106
|
+
cmd_result_stdout = ''
|
107
|
+
cmd_result_stderr = ''
|
108
|
+
# Route IOs
|
109
|
+
stdout_queue = Queue.new
|
110
|
+
stderr_queue = Queue.new
|
111
|
+
IoRouter.with_io_router(
|
112
|
+
stdout_queue => [cmd_result_stdout] +
|
113
|
+
(log_stdout_to_io ? [log_stdout_to_io] : []) +
|
114
|
+
(log_to_stdout ? [@logger] : []) +
|
115
|
+
(file_output.nil? ? [] : [file_output]),
|
116
|
+
stderr_queue => [cmd_result_stderr] +
|
117
|
+
(log_stderr_to_io ? [log_stderr_to_io] : []) +
|
118
|
+
(log_to_stdout ? [@logger_stderr] : []) +
|
119
|
+
(file_output.nil? ? [] : [file_output])
|
120
|
+
) do
|
121
|
+
cmd_result = TTY::Command.new(
|
122
|
+
printer: :null,
|
123
|
+
pty: true,
|
124
|
+
timeout: timeout,
|
125
|
+
uuid: false
|
126
|
+
).run!(cmd) do |stdout, stderr|
|
127
|
+
stdout_queue << stdout if stdout
|
128
|
+
stderr_queue << stderr if stderr
|
129
|
+
end
|
130
|
+
exit_status = cmd_result.exit_status
|
131
|
+
cmd_stdout = cmd_result.out
|
132
|
+
cmd_stderr = cmd_result.err
|
133
|
+
end
|
134
|
+
rescue TTY::Command::TimeoutExceeded
|
135
|
+
exit_status = :timeout
|
136
|
+
cmd_stdout = cmd_result_stdout
|
137
|
+
cmd_stderr = "#{cmd_result_stderr.empty? ? '' : "#{cmd_result_stderr}\n"}Timeout of #{timeout} triggered"
|
138
|
+
rescue
|
139
|
+
exit_status = :command_error
|
140
|
+
cmd_stdout = cmd_result_stdout
|
141
|
+
cmd_stderr = "#{cmd_result_stderr.empty? ? '' : "#{cmd_result_stderr}\n"}#{$!}\n#{$!.backtrace.join("\n")}"
|
142
|
+
ensure
|
143
|
+
file_output.close unless file_output.nil?
|
144
|
+
end
|
145
|
+
if log_debug?
|
146
|
+
elapsed = Time.now - start_time
|
147
|
+
log_debug "Finished in #{elapsed} seconds with exit status #{exit_status} (#{(expected_code.include?(exit_status) ? 'success'.light_green : 'failure'.light_red).bold})"
|
148
|
+
end
|
149
|
+
unless expected_code.include?(exit_status)
|
150
|
+
error_title = "Command '#{cmd.split("\n").first}' returned error code #{exit_status} (expected #{expected_code.join(', ')})."
|
151
|
+
if no_exception
|
152
|
+
# We consider the caller is responsible for logging what he wants about the details of the error (stdout and stderr)
|
153
|
+
log_error error_title
|
154
|
+
else
|
155
|
+
# The exception won't contain stdout and stderr details (unless output to stdout was on), so dump them now
|
156
|
+
log_error "#{error_title}#{log_to_stdout ? '' : "\n----- Command STDOUT:\n#{cmd_stdout}\n----- Command STDERR:\n#{cmd_stderr}"}"
|
157
|
+
raise exit_status == :timeout ? TimeoutError : UnexpectedExitCodeError, error_title
|
158
|
+
end
|
159
|
+
end
|
160
|
+
return exit_status, cmd_stdout, cmd_stderr
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Is the current user root?
|
165
|
+
# Look into the environment to decide.
|
166
|
+
#
|
167
|
+
# Result::
|
168
|
+
# Boolean: Is the current user root?
|
169
|
+
def root?
|
170
|
+
whoami == 'root'
|
171
|
+
end
|
172
|
+
|
173
|
+
# Who is the local user?
|
174
|
+
# Keep a cache of it.
|
175
|
+
#
|
176
|
+
# Result::
|
177
|
+
# String: Name of the local user
|
178
|
+
def whoami
|
179
|
+
unless defined?(@whoami)
|
180
|
+
_exit_status, stdout, _stderr = run_cmd 'whoami', log_to_stdout: log_debug?
|
181
|
+
@whoami = stdout.strip
|
182
|
+
end
|
183
|
+
@whoami
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'hybrid_platforms_conductor/logger_helpers'
|
2
|
+
require 'hybrid_platforms_conductor/plugin'
|
3
|
+
|
4
|
+
module HybridPlatformsConductor
|
5
|
+
|
6
|
+
# Base class for any CMDB plugin
|
7
|
+
class Cmdb < 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
|
+
# * *cmd_runner* (CmdRunner): Command Runner to be used. [default: CmdRunner.new]
|
16
|
+
# * *platforms_handler* (PlatformsHandler): Platforms Handler to be used. [default: PlatformsHandler.new]
|
17
|
+
# * *nodes_handler* (NodesHandler): Nodes Handler to be used. [default: NodesHandler.new]
|
18
|
+
def initialize(
|
19
|
+
logger: Logger.new(STDOUT),
|
20
|
+
logger_stderr: Logger.new(STDERR),
|
21
|
+
config: Config.new,
|
22
|
+
cmd_runner: CmdRunner.new,
|
23
|
+
platforms_handler: PlatformsHandler.new,
|
24
|
+
nodes_handler: NodesHandler.new
|
25
|
+
)
|
26
|
+
super(logger: logger, logger_stderr: logger_stderr, config: config)
|
27
|
+
@cmd_runner = cmd_runner
|
28
|
+
@platforms_handler = platforms_handler
|
29
|
+
@nodes_handler = nodes_handler
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'hybrid_platforms_conductor/bitbucket'
|
2
|
+
|
3
|
+
module HybridPlatformsConductor
|
4
|
+
|
5
|
+
module CommonConfigDsl
|
6
|
+
|
7
|
+
module Bitbucket
|
8
|
+
|
9
|
+
# Initialize the DSL
|
10
|
+
def init_bitbucket
|
11
|
+
# List of Bitbucket repositories definitions
|
12
|
+
# Array< Hash<Symbol, Object> >
|
13
|
+
# Each definition is just mapping the signature of #bitbucket_repos
|
14
|
+
@bitbucket_repos = []
|
15
|
+
end
|
16
|
+
|
17
|
+
# Register new Bitbucket repositories
|
18
|
+
#
|
19
|
+
# Parameters::
|
20
|
+
# * *url* (String): URL to the Bitbucket server
|
21
|
+
# * *project* (String): Project name from the Bitbucket server, storing repositories
|
22
|
+
# * *repos* (Array<String> or Symbol): List of repository names from this project, or :all for all [default: :all]
|
23
|
+
# * *jenkins_ci_url* (String or nil): Corresponding Jenkins CI URL, or nil if none [default: nil]
|
24
|
+
# * *checks* (Hash<Symbol, Object>): Checks definition to be perform on those repositories (see the #for_each_bitbucket_repo to know the structure) [default: {}]
|
25
|
+
def bitbucket_repos(url:, project:, repos: :all, jenkins_ci_url: nil, checks: {})
|
26
|
+
@bitbucket_repos << {
|
27
|
+
url: url,
|
28
|
+
project: project,
|
29
|
+
repos: repos,
|
30
|
+
jenkins_ci_url: jenkins_ci_url,
|
31
|
+
checks: checks
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
# Iterate over each Bitbucket repository
|
36
|
+
#
|
37
|
+
# Parameters::
|
38
|
+
# * Proc: Code called for each Bitbucket repository:
|
39
|
+
# * Parameters::
|
40
|
+
# * *bitbucket* (Bitbucket): The Bitbucket instance used to query the API for this repository
|
41
|
+
# * *repo_info* (Hash<Symbol, Object>): The repository info:
|
42
|
+
# * *name* (String): Repository name.
|
43
|
+
# * *project* (String): Project name.
|
44
|
+
# * *url* (String): Project Git URL.
|
45
|
+
# * *jenkins_ci_url* (String or nil): Corresponding Jenkins CI URL, or nil if none.
|
46
|
+
# * *checks* (Hash<Symbol, Object>): Checks to be performed on this repository:
|
47
|
+
# * *branch_permissions* (Array< Hash<Symbol, Object> >): List of branch permissions to check [optional]
|
48
|
+
# * *type* (String): Type of branch permissions to check. Examples of values are 'fast-forward-only', 'no-deletes', 'pull-request-only'.
|
49
|
+
# * *branch* (String): Branch on which those permissions apply.
|
50
|
+
# * *exempted_users* (Array<String>): List of exempted users for this permission [default: []]
|
51
|
+
# * *exempted_groups* (Array<String>): List of exempted groups for this permission [default: []]
|
52
|
+
# * *exempted_keys* (Array<String>): List of exempted access keys for this permission [default: []]
|
53
|
+
# * *pr_settings* (Hash<Symbol, Object>): PR specific settings to check [optional]
|
54
|
+
# * *required_approvers* (Integer): Number of required approvers [optional]
|
55
|
+
# * *required_builds* (Integer): Number of required successful builds [optional]
|
56
|
+
# * *default_merge_strategy* (String): Name of the default merge strategy. Example: 'rebase-no-ff' [optional]
|
57
|
+
# * *mandatory_default_reviewers* (Array<String>): List of mandatory reviewers to check [default: []]
|
58
|
+
def for_each_bitbucket_repo
|
59
|
+
@bitbucket_repos.each do |bitbucket_repo_info|
|
60
|
+
HybridPlatformsConductor::Bitbucket.with_bitbucket(bitbucket_repo_info[:url], @logger, @logger_stderr) do |bitbucket|
|
61
|
+
(bitbucket_repo_info[:repos] == :all ? bitbucket.repos(bitbucket_repo_info[:project])['values'].map { |repo_info| repo_info['slug'] } : bitbucket_repo_info[:repos]).each do |name|
|
62
|
+
yield bitbucket, {
|
63
|
+
name: name,
|
64
|
+
project: bitbucket_repo_info[:project],
|
65
|
+
url: "#{bitbucket_repo_info[:url]}/scm/#{bitbucket_repo_info[:project].downcase}/#{name}.git",
|
66
|
+
jenkins_ci_url: bitbucket_repo_info[:jenkins_ci_url].nil? ? nil : "#{bitbucket_repo_info[:jenkins_ci_url]}/job/#{name}",
|
67
|
+
checks: bitbucket_repo_info[:checks]
|
68
|
+
}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module HybridPlatformsConductor
|
2
|
+
|
3
|
+
module CommonConfigDsl
|
4
|
+
|
5
|
+
module Confluence
|
6
|
+
|
7
|
+
# Initialize the DSL
|
8
|
+
def init_confluence
|
9
|
+
# Confluence configuration (can be nil if none)
|
10
|
+
# Hash<Symbol, Object> or nil. See #confluence_info to know details.
|
11
|
+
@confluence = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
# Register a Confluence server
|
15
|
+
#
|
16
|
+
# Parameters::
|
17
|
+
# * *url* (String): URL to the Confluence server
|
18
|
+
# * *inventory_report_page_id* (String or nil): Confluence page id used for inventory reports, or nil if none [default: nil]
|
19
|
+
# * *tests_report_page_id* (String or nil): Confluence page id used for test reports, or nil if none [default: nil]
|
20
|
+
def confluence(url:, inventory_report_page_id: nil, tests_report_page_id: nil)
|
21
|
+
@confluence = {
|
22
|
+
url: url,
|
23
|
+
inventory_report_page_id: inventory_report_page_id,
|
24
|
+
tests_report_page_id: tests_report_page_id
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
# Return the Confluence information
|
29
|
+
#
|
30
|
+
# Result::
|
31
|
+
# * Hash<Symbol, Object> or nil: The Confluence information, or nil if none
|
32
|
+
# * *url* (String): The Confluence URL.
|
33
|
+
# * *inventory_report_page_id* (String or nil): Confluence page id used for inventory reports, or nil if none.
|
34
|
+
# * *tests_report_page_id* (String or nil): Confluence page id used for test reports, or nil if none.
|
35
|
+
def confluence_info
|
36
|
+
@confluence
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module HybridPlatformsConductor
|
2
|
+
|
3
|
+
module CommonConfigDsl
|
4
|
+
|
5
|
+
# Config DSL configuring file system testing (used by different test plugins)
|
6
|
+
module FileSystemTests
|
7
|
+
|
8
|
+
# List of paths rules to be checked. Each info has the following properties:
|
9
|
+
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by this rule
|
10
|
+
# * *paths* (Array<String>): List of paths to check.
|
11
|
+
# * *state* (Symbol): State those paths should be in. Possible states are:
|
12
|
+
# * *present*: Paths should exist
|
13
|
+
# * *absent*: Paths should not exist
|
14
|
+
# * *context* (Hash<Symbol,Object>): Context on which those paths are checked. Possible properties are
|
15
|
+
# * *sudo_user* (String or nil): Sudo user to be used to perform checks, or nil if none [default: nil]
|
16
|
+
# * *file_system_type* (Symbol): File system to be checked [default: :local]. Possible values:
|
17
|
+
# * *local*: Local file system
|
18
|
+
# * *hdfs*: HDFS file system
|
19
|
+
# Array< Hash<Symbol, Object> >
|
20
|
+
attr_reader :fs_paths_rules
|
21
|
+
|
22
|
+
# Initialize the DSL
|
23
|
+
def init_file_system_tests
|
24
|
+
@fs_paths_rules = []
|
25
|
+
@context = {
|
26
|
+
file_system_type: :local
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
# Give a list of paths to check for absence
|
31
|
+
#
|
32
|
+
# Parameters::
|
33
|
+
# * *paths* (String or Array<String>): List of (or single) paths
|
34
|
+
def check_files_do_not_exist(*paths)
|
35
|
+
@fs_paths_rules << {
|
36
|
+
paths: paths.flatten,
|
37
|
+
nodes_selectors_stack: current_nodes_selectors_stack,
|
38
|
+
context: @context.clone,
|
39
|
+
state: :absent
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
# Give a list of paths to check for presence
|
44
|
+
#
|
45
|
+
# Parameters::
|
46
|
+
# * *paths* (String or Array<String>): List of (or single) paths
|
47
|
+
def check_files_do_exist(*paths)
|
48
|
+
@fs_paths_rules << {
|
49
|
+
paths: paths.flatten,
|
50
|
+
nodes_selectors_stack: current_nodes_selectors_stack,
|
51
|
+
context: @context.clone,
|
52
|
+
state: :present
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
# Set the rules to be in a context of HDFS checking
|
57
|
+
#
|
58
|
+
# Parameters::
|
59
|
+
# * *with_sudo* (String or nil): Sudo user to be used to perform HDFS commands, or nil for none [default: nil]
|
60
|
+
# * Proc: Configuration code called within this context
|
61
|
+
def on_hdfs(with_sudo: nil)
|
62
|
+
old_context = @context.clone
|
63
|
+
begin
|
64
|
+
@context[:file_system_type] = :hdfs
|
65
|
+
@context[:sudo_user] = with_sudo unless with_sudo.nil?
|
66
|
+
yield
|
67
|
+
ensure
|
68
|
+
@context = old_context
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Aggregate a list of paths rules for a given file system type, per path to be checked
|
73
|
+
#
|
74
|
+
# Parameters::
|
75
|
+
# * *nodes_handler* (NodesHandler): NodesHandler to be sued to resolve nodes selections
|
76
|
+
# * *node* (String): Node for which we select rules
|
77
|
+
# * *file_system_type* (Symbol): File system type to be selected [default: :local]
|
78
|
+
# Result::
|
79
|
+
# * Hash<String, Hash<Symbol,Object> >: Rule infos, per path. Each info has the following properties:
|
80
|
+
# * *state* (Symbol): State the path should be in
|
81
|
+
# * *context* (Hash): Associated context, as defined by the configuration
|
82
|
+
def aggregate_files_rules(nodes_handler, node, file_system_type: :local)
|
83
|
+
nodes_handler.
|
84
|
+
select_confs_for_node(node, fs_paths_rules).
|
85
|
+
inject({}) do |merged_paths, paths_info|
|
86
|
+
if paths_info[:context][:file_system_type] == file_system_type
|
87
|
+
merged_paths.merge(Hash[paths_info[:paths].map do |path|
|
88
|
+
[
|
89
|
+
path,
|
90
|
+
{
|
91
|
+
state: paths_info[:state],
|
92
|
+
context: paths_info[:context]
|
93
|
+
}
|
94
|
+
]
|
95
|
+
end]) do |path, rule_info_1, rule_info_2|
|
96
|
+
# Just check that configuration is not inconsistent
|
97
|
+
raise "Inconsistent rule for #{file_system_type} file system checks in configuration for #{node}: #{path} is marked as being both #{rule_info_1[:state]} and #{rule_info_2[:state]}" if rule_info_1[:state] != rule_info_2[:state]
|
98
|
+
rule_info_2
|
99
|
+
end
|
100
|
+
else
|
101
|
+
merged_paths
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|