kdeploy 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +101 -936
- data/exe/kdeploy +6 -0
- data/k.md +149 -0
- data/lib/kdeploy/banner.rb +44 -14
- data/lib/kdeploy/cli.rb +138 -1389
- data/lib/kdeploy/dsl.rb +66 -530
- data/lib/kdeploy/executor.rb +73 -0
- data/lib/kdeploy/initializer.rb +229 -0
- data/lib/kdeploy/runner.rb +40 -180
- data/lib/kdeploy/template.rb +18 -161
- data/lib/kdeploy/version.rb +1 -2
- data/lib/kdeploy.rb +9 -100
- metadata +75 -52
- data/.editorconfig +0 -12
- data/.rspec +0 -3
- data/.rubocop.yml +0 -100
- data/LICENSE +0 -21
- data/Rakefile +0 -45
- data/bin/kdeploy +0 -7
- data/kdeploy.gemspec +0 -49
- data/lib/kdeploy/command.rb +0 -182
- data/lib/kdeploy/configuration.rb +0 -83
- data/lib/kdeploy/host.rb +0 -85
- data/lib/kdeploy/inventory.rb +0 -243
- data/lib/kdeploy/logger.rb +0 -100
- data/lib/kdeploy/pipeline.rb +0 -249
- data/lib/kdeploy/ssh_connection.rb +0 -187
- data/lib/kdeploy/statistics.rb +0 -439
- data/lib/kdeploy/task.rb +0 -240
- data/scripts/common_tasks.rb +0 -218
- data/scripts/deploy.rb +0 -50
data/lib/kdeploy/command.rb
DELETED
@@ -1,182 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Kdeploy
|
4
|
-
# Command class for executing commands on remote hosts
|
5
|
-
class Command
|
6
|
-
attr_reader :name, :command, :options, :result
|
7
|
-
|
8
|
-
def initialize(name, command, options = {})
|
9
|
-
@name = name
|
10
|
-
@command = command
|
11
|
-
@options = default_options.merge(options)
|
12
|
-
@global_variables = options.delete(:global_variables) || {}
|
13
|
-
@result = nil
|
14
|
-
end
|
15
|
-
|
16
|
-
# Execute command on specified host
|
17
|
-
# @param host [Host] Target host
|
18
|
-
# @param connection [SSHConnection] SSH connection
|
19
|
-
# @return [Boolean] True if command succeeded
|
20
|
-
def execute(host, connection)
|
21
|
-
start_time = Time.now
|
22
|
-
processed_command = process_command_template(host)
|
23
|
-
|
24
|
-
log_command_start(host, processed_command)
|
25
|
-
@result = execute_with_retry(connection, processed_command)
|
26
|
-
duration = Time.now - start_time
|
27
|
-
|
28
|
-
log_result(host, duration)
|
29
|
-
record_statistics(host.hostname, duration, @result[:success])
|
30
|
-
|
31
|
-
@result[:success]
|
32
|
-
rescue StandardError => e
|
33
|
-
handle_execution_error(host, e, start_time)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Check if command should run on host
|
37
|
-
# @param host [Host] Target host
|
38
|
-
# @return [Boolean] True if command should run
|
39
|
-
def should_run_on?(host)
|
40
|
-
return true unless @options[:only] || @options[:except]
|
41
|
-
|
42
|
-
if @options[:only]
|
43
|
-
roles = Array(@options[:only])
|
44
|
-
return roles.any? { |role| host.has_role?(role) }
|
45
|
-
end
|
46
|
-
|
47
|
-
if @options[:except]
|
48
|
-
roles = Array(@options[:except])
|
49
|
-
return roles.none? { |role| host.has_role?(role) }
|
50
|
-
end
|
51
|
-
|
52
|
-
true
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def default_options
|
58
|
-
{
|
59
|
-
timeout: nil,
|
60
|
-
retry_count: nil,
|
61
|
-
retry_delay: nil,
|
62
|
-
ignore_errors: false,
|
63
|
-
only: nil,
|
64
|
-
except: nil
|
65
|
-
}
|
66
|
-
end
|
67
|
-
|
68
|
-
def process_command_template(host)
|
69
|
-
processed = @command.dup
|
70
|
-
process_global_variables(processed)
|
71
|
-
process_host_variables(processed, host)
|
72
|
-
process_host_info(processed, host)
|
73
|
-
end
|
74
|
-
|
75
|
-
def process_global_variables(command)
|
76
|
-
@global_variables.each_with_object(command) do |(key, value), cmd|
|
77
|
-
cmd.gsub!("{{#{key}}}", value.to_s)
|
78
|
-
cmd.gsub!("${#{key}}", value.to_s)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def process_host_variables(command, host)
|
83
|
-
host.vars.each_with_object(command) do |(key, value), cmd|
|
84
|
-
cmd.gsub!("{{#{key}}}", value.to_s)
|
85
|
-
cmd.gsub!("${#{key}}", value.to_s)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def process_host_info(command, host)
|
90
|
-
command.gsub('{{hostname}}', host.hostname)
|
91
|
-
.gsub('{{user}}', host.user)
|
92
|
-
.gsub('{{port}}', host.port.to_s)
|
93
|
-
end
|
94
|
-
|
95
|
-
def execute_with_retry(connection, command)
|
96
|
-
retry_count = @options[:retry_count] || Kdeploy.configuration&.retry_count || 0
|
97
|
-
retry_delay = @options[:retry_delay] || Kdeploy.configuration&.retry_delay || 1
|
98
|
-
|
99
|
-
result = nil
|
100
|
-
attempts = 0
|
101
|
-
|
102
|
-
loop do
|
103
|
-
attempts += 1
|
104
|
-
result = connection.execute(command, timeout: @options[:timeout])
|
105
|
-
|
106
|
-
break if result[:success] || attempts > retry_count
|
107
|
-
|
108
|
-
if attempts <= retry_count
|
109
|
-
log_retry_attempt(attempts, retry_count, retry_delay)
|
110
|
-
sleep(retry_delay)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
result
|
115
|
-
end
|
116
|
-
|
117
|
-
def log_command_start(host, command)
|
118
|
-
KdeployLogger.info("🚀 Executing '#{@name}' on #{host}")
|
119
|
-
KdeployLogger.debug(" Command: #{command}")
|
120
|
-
end
|
121
|
-
|
122
|
-
def log_retry_attempt(attempts, retry_count, retry_delay)
|
123
|
-
KdeployLogger.warn(
|
124
|
-
"Command '#{@name}' failed (attempt #{attempts}/#{retry_count + 1}), " \
|
125
|
-
"retrying in #{retry_delay}s..."
|
126
|
-
)
|
127
|
-
end
|
128
|
-
|
129
|
-
def log_result(host, duration)
|
130
|
-
if @result[:success]
|
131
|
-
log_success(host, duration)
|
132
|
-
else
|
133
|
-
log_failure(host, duration)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def log_success(host, duration)
|
138
|
-
KdeployLogger.info("✅ Command '#{@name}' completed on #{host} in #{duration.round(2)}s")
|
139
|
-
return if @result[:stdout].strip.empty?
|
140
|
-
|
141
|
-
KdeployLogger.info('📤 Output:')
|
142
|
-
@result[:stdout].strip.split("\n").each do |line|
|
143
|
-
KdeployLogger.info(" #{line}")
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
def log_failure(host, duration)
|
148
|
-
level = @options[:ignore_errors] ? :warn : :error
|
149
|
-
icon = @options[:ignore_errors] ? '⚠️' : '❌'
|
150
|
-
|
151
|
-
KdeployLogger.send(
|
152
|
-
level,
|
153
|
-
"#{icon} Command '#{@name}' failed on #{host} in #{duration.round(2)}s " \
|
154
|
-
"(exit code: #{@result[:exit_code]})"
|
155
|
-
)
|
156
|
-
|
157
|
-
KdeployLogger.send(level, "📤 STDERR: #{@result[:stderr]}") unless @result[:stderr].empty?
|
158
|
-
KdeployLogger.send(level, "📤 STDOUT: #{@result[:stdout]}") unless @result[:stdout].strip.empty?
|
159
|
-
end
|
160
|
-
|
161
|
-
def handle_execution_error(host, error, start_time)
|
162
|
-
duration = Time.now - start_time
|
163
|
-
KdeployLogger.error(
|
164
|
-
"Command '#{@name}' failed on #{host} after #{duration.round(2)}s: #{error.message}"
|
165
|
-
)
|
166
|
-
|
167
|
-
@result = {
|
168
|
-
stdout: '',
|
169
|
-
stderr: error.message,
|
170
|
-
exit_code: 1,
|
171
|
-
success: false
|
172
|
-
}
|
173
|
-
|
174
|
-
record_statistics(host.hostname, duration, false)
|
175
|
-
false
|
176
|
-
end
|
177
|
-
|
178
|
-
def record_statistics(hostname, duration, success)
|
179
|
-
Kdeploy.statistics.record_command(@name, hostname, success, duration)
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Kdeploy
|
4
|
-
# Configuration class for managing global settings
|
5
|
-
class Configuration
|
6
|
-
attr_accessor :max_concurrent_tasks, :ssh_timeout, :command_timeout,
|
7
|
-
:retry_count, :retry_delay, :log_level, :log_file,
|
8
|
-
:default_user, :default_port, :ssh_options, :inventory_file,
|
9
|
-
:template_dir
|
10
|
-
|
11
|
-
def initialize
|
12
|
-
set_default_values
|
13
|
-
end
|
14
|
-
|
15
|
-
# Load configuration from YAML file
|
16
|
-
# @param config_file [String] Path to configuration file
|
17
|
-
# @return [void]
|
18
|
-
def load_from_file(config_file)
|
19
|
-
return unless File.exist?(config_file)
|
20
|
-
|
21
|
-
config = YAML.load_file(config_file)
|
22
|
-
return unless config.is_a?(Hash)
|
23
|
-
|
24
|
-
apply_configuration(config)
|
25
|
-
end
|
26
|
-
|
27
|
-
# Merge SSH options with defaults
|
28
|
-
# @param options [Hash] SSH options to merge
|
29
|
-
# @return [Hash] Merged SSH options
|
30
|
-
def merged_ssh_options(options = {})
|
31
|
-
ssh_options.merge(options)
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
def set_default_values
|
37
|
-
set_default_timeouts
|
38
|
-
set_default_retry_settings
|
39
|
-
set_default_logging
|
40
|
-
set_default_ssh_settings
|
41
|
-
set_default_paths
|
42
|
-
end
|
43
|
-
|
44
|
-
def set_default_timeouts
|
45
|
-
@max_concurrent_tasks = 10
|
46
|
-
@ssh_timeout = 30
|
47
|
-
@command_timeout = 300
|
48
|
-
end
|
49
|
-
|
50
|
-
def set_default_retry_settings
|
51
|
-
@retry_count = 3
|
52
|
-
@retry_delay = 1
|
53
|
-
end
|
54
|
-
|
55
|
-
def set_default_logging
|
56
|
-
@log_level = :info
|
57
|
-
@log_file = nil
|
58
|
-
end
|
59
|
-
|
60
|
-
def set_default_ssh_settings
|
61
|
-
@default_user = ENV.fetch('USER', 'root')
|
62
|
-
@default_port = 22
|
63
|
-
@ssh_options = {
|
64
|
-
verify_host_key: :never,
|
65
|
-
non_interactive: true,
|
66
|
-
use_agent: true,
|
67
|
-
forward_agent: false
|
68
|
-
}
|
69
|
-
end
|
70
|
-
|
71
|
-
def set_default_paths
|
72
|
-
@inventory_file = 'inventory.yml'
|
73
|
-
@template_dir = 'templates'
|
74
|
-
end
|
75
|
-
|
76
|
-
def apply_configuration(config)
|
77
|
-
config.each do |key, value|
|
78
|
-
method_name = "#{key}="
|
79
|
-
send(method_name, value) if respond_to?(method_name)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
data/lib/kdeploy/host.rb
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Kdeploy
|
4
|
-
# Host class for managing remote host configuration and connection details
|
5
|
-
class Host
|
6
|
-
attr_reader :hostname, :user, :port, :ssh_options, :roles, :vars
|
7
|
-
|
8
|
-
def initialize(hostname, user: nil, port: nil, ssh_options: {}, roles: [], vars: {})
|
9
|
-
@hostname = hostname
|
10
|
-
@user = user || Kdeploy.configuration&.default_user || ENV.fetch('USER', nil)
|
11
|
-
@port = port || Kdeploy.configuration&.default_port || 22
|
12
|
-
@ssh_options = ssh_options
|
13
|
-
@roles = Array(roles)
|
14
|
-
@vars = vars || {}
|
15
|
-
end
|
16
|
-
|
17
|
-
# Check if host has specific role
|
18
|
-
# @param role [String, Symbol] Role to check
|
19
|
-
# @return [Boolean] True if host has role
|
20
|
-
def has_role?(role)
|
21
|
-
@roles.include?(role.to_s) || @roles.include?(role.to_sym)
|
22
|
-
end
|
23
|
-
|
24
|
-
# Get variable value
|
25
|
-
# @param key [String, Symbol] Variable key
|
26
|
-
# @return [Object] Variable value
|
27
|
-
def var(key)
|
28
|
-
@vars[key.to_s] || @vars[key.to_sym]
|
29
|
-
end
|
30
|
-
|
31
|
-
# Set variable value
|
32
|
-
# @param key [String, Symbol] Variable key
|
33
|
-
# @param value [Object] Variable value
|
34
|
-
# @return [Object] Set value
|
35
|
-
def set_var(key, value)
|
36
|
-
@vars[key.to_s] = value
|
37
|
-
end
|
38
|
-
|
39
|
-
# Get connection string for display
|
40
|
-
# @return [String] Connection string
|
41
|
-
def connection_string
|
42
|
-
"#{@user}@#{@hostname}:#{@port}"
|
43
|
-
end
|
44
|
-
|
45
|
-
# Get SSH connection options
|
46
|
-
# @return [Hash] SSH options
|
47
|
-
def connection_options
|
48
|
-
base_options = Kdeploy.configuration&.merged_ssh_options(@ssh_options) || @ssh_options
|
49
|
-
base_options.merge(
|
50
|
-
timeout: Kdeploy.configuration&.ssh_timeout || 30
|
51
|
-
)
|
52
|
-
end
|
53
|
-
|
54
|
-
# String representation of the host
|
55
|
-
# @return [String] Connection string
|
56
|
-
def to_s
|
57
|
-
connection_string
|
58
|
-
end
|
59
|
-
|
60
|
-
# Detailed string representation of the host
|
61
|
-
# @return [String] Host details
|
62
|
-
def inspect
|
63
|
-
"#<Kdeploy::Host #{connection_string} roles=#{@roles} vars=#{@vars.keys}>"
|
64
|
-
end
|
65
|
-
|
66
|
-
# Compare hosts for equality
|
67
|
-
# @param other [Host] Host to compare with
|
68
|
-
# @return [Boolean] True if hosts are equal
|
69
|
-
def ==(other)
|
70
|
-
return false unless other.is_a?(Host)
|
71
|
-
|
72
|
-
hostname == other.hostname &&
|
73
|
-
user == other.user &&
|
74
|
-
port == other.port
|
75
|
-
end
|
76
|
-
|
77
|
-
alias eql? ==
|
78
|
-
|
79
|
-
# Generate hash code for host
|
80
|
-
# @return [Integer] Hash code
|
81
|
-
def hash
|
82
|
-
[hostname, user, port].hash
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
data/lib/kdeploy/inventory.rb
DELETED
@@ -1,243 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Kdeploy
|
4
|
-
# Inventory class for managing host inventory and configuration
|
5
|
-
class Inventory
|
6
|
-
attr_reader :hosts, :groups, :vars
|
7
|
-
|
8
|
-
def initialize(inventory_file = nil)
|
9
|
-
@hosts = {}
|
10
|
-
@groups = {}
|
11
|
-
@vars = {}
|
12
|
-
load_from_file(inventory_file) if inventory_file && File.exist?(inventory_file)
|
13
|
-
end
|
14
|
-
|
15
|
-
# Load inventory from YAML file
|
16
|
-
# @param inventory_file [String] Path to inventory file
|
17
|
-
# @raise [ConfigurationError] If inventory file is invalid
|
18
|
-
def load_from_file(inventory_file)
|
19
|
-
inventory_data = YAML.load_file(inventory_file)
|
20
|
-
parse_inventory(inventory_data)
|
21
|
-
rescue Psych::SyntaxError => e
|
22
|
-
raise ConfigurationError, "Invalid YAML syntax in inventory file: #{e.message}"
|
23
|
-
rescue StandardError => e
|
24
|
-
raise ConfigurationError, "Failed to load inventory file: #{e.message}"
|
25
|
-
end
|
26
|
-
|
27
|
-
# Get all hosts in a group
|
28
|
-
# @param group_name [String, Symbol] Group name
|
29
|
-
# @return [Array<Host>] Hosts in the group
|
30
|
-
def hosts_in_group(group_name)
|
31
|
-
group_name = group_name.to_s
|
32
|
-
return [] unless @groups[group_name]
|
33
|
-
|
34
|
-
@groups[group_name][:hosts].map { |hostname| @hosts[hostname] }.compact
|
35
|
-
end
|
36
|
-
|
37
|
-
# Get all hosts with specific role
|
38
|
-
# @param role [String, Symbol] Role name
|
39
|
-
# @return [Array<Host>] Hosts with the role
|
40
|
-
def hosts_with_role(role)
|
41
|
-
@hosts.values.select { |host| host.has_role?(role) }
|
42
|
-
end
|
43
|
-
|
44
|
-
# Get all hosts
|
45
|
-
# @return [Array<Host>] All hosts
|
46
|
-
def all_hosts
|
47
|
-
@hosts.values
|
48
|
-
end
|
49
|
-
|
50
|
-
# Get host by hostname
|
51
|
-
# @param hostname [String] Hostname
|
52
|
-
# @return [Host, nil] Host object or nil
|
53
|
-
def host(hostname)
|
54
|
-
@hosts[hostname]
|
55
|
-
end
|
56
|
-
|
57
|
-
# Get group variable
|
58
|
-
# @param group_name [String, Symbol] Group name
|
59
|
-
# @param var_name [String, Symbol] Variable name
|
60
|
-
# @return [Object] Variable value
|
61
|
-
def group_var(group_name, var_name)
|
62
|
-
group_name = group_name.to_s
|
63
|
-
return nil unless @groups[group_name]
|
64
|
-
|
65
|
-
@groups[group_name][:vars][var_name.to_s] || @groups[group_name][:vars][var_name.to_sym]
|
66
|
-
end
|
67
|
-
|
68
|
-
# Get global variable
|
69
|
-
# @param var_name [String, Symbol] Variable name
|
70
|
-
# @return [Object] Variable value
|
71
|
-
def global_var(var_name)
|
72
|
-
@vars[var_name.to_s] || @vars[var_name.to_sym]
|
73
|
-
end
|
74
|
-
|
75
|
-
# Export inventory summary
|
76
|
-
# @return [Hash] Inventory summary
|
77
|
-
def summary
|
78
|
-
{
|
79
|
-
total_hosts: @hosts.size,
|
80
|
-
total_groups: @groups.size,
|
81
|
-
hosts: @hosts.keys,
|
82
|
-
groups: @groups.keys
|
83
|
-
}
|
84
|
-
end
|
85
|
-
|
86
|
-
private
|
87
|
-
|
88
|
-
def parse_inventory(inventory_data)
|
89
|
-
return unless inventory_data.is_a?(Hash)
|
90
|
-
|
91
|
-
@vars = extract_vars(inventory_data)
|
92
|
-
parse_groups(inventory_data)
|
93
|
-
parse_hosts(inventory_data)
|
94
|
-
apply_group_variables
|
95
|
-
end
|
96
|
-
|
97
|
-
def extract_vars(data)
|
98
|
-
data['vars'] || data[:vars] || {}
|
99
|
-
end
|
100
|
-
|
101
|
-
def parse_groups(inventory_data)
|
102
|
-
groups_data = inventory_data['groups'] || inventory_data[:groups] || {}
|
103
|
-
|
104
|
-
groups_data.each do |group_name, group_config|
|
105
|
-
process_group(group_name.to_s, group_config || {})
|
106
|
-
end
|
107
|
-
|
108
|
-
resolve_group_children
|
109
|
-
end
|
110
|
-
|
111
|
-
def process_group(group_name, group_config)
|
112
|
-
@groups[group_name] = {
|
113
|
-
hosts: extract_group_hosts(group_config),
|
114
|
-
vars: extract_group_vars(group_config),
|
115
|
-
children: extract_group_children(group_config)
|
116
|
-
}
|
117
|
-
end
|
118
|
-
|
119
|
-
def extract_group_hosts(config)
|
120
|
-
Array(config['hosts'] || config[:hosts] || [])
|
121
|
-
end
|
122
|
-
|
123
|
-
def extract_group_vars(config)
|
124
|
-
config['vars'] || config[:vars] || {}
|
125
|
-
end
|
126
|
-
|
127
|
-
def extract_group_children(config)
|
128
|
-
Array(config['children'] || config[:children] || [])
|
129
|
-
end
|
130
|
-
|
131
|
-
def parse_hosts(inventory_data)
|
132
|
-
hosts_data = inventory_data['hosts'] || inventory_data[:hosts] || {}
|
133
|
-
|
134
|
-
hosts_data.each do |hostname, host_config|
|
135
|
-
process_host(hostname, host_config || {})
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def process_host(hostname, host_config)
|
140
|
-
host_groups = find_host_groups(hostname)
|
141
|
-
host_roles = Array(host_config['roles'] || host_config[:roles] || host_groups)
|
142
|
-
|
143
|
-
@hosts[hostname] = create_host(hostname, host_config, host_roles)
|
144
|
-
end
|
145
|
-
|
146
|
-
def create_host(hostname, config, roles)
|
147
|
-
Host.new(
|
148
|
-
hostname,
|
149
|
-
user: config['user'] || config[:user],
|
150
|
-
port: config['port'] || config[:port],
|
151
|
-
ssh_options: parse_ssh_options(config),
|
152
|
-
roles: roles,
|
153
|
-
vars: config['vars'] || config[:vars] || {}
|
154
|
-
)
|
155
|
-
end
|
156
|
-
|
157
|
-
def parse_ssh_options(host_config)
|
158
|
-
ssh_config = host_config['ssh'] || host_config[:ssh] || {}
|
159
|
-
options = {}
|
160
|
-
|
161
|
-
process_ssh_key_options(ssh_config, options)
|
162
|
-
process_ssh_auth_options(ssh_config, options)
|
163
|
-
process_ssh_verification_options(ssh_config, options)
|
164
|
-
process_ssh_timeout_option(ssh_config, options)
|
165
|
-
|
166
|
-
options
|
167
|
-
end
|
168
|
-
|
169
|
-
def process_ssh_key_options(ssh_config, options)
|
170
|
-
if ssh_config['key_file'] || ssh_config[:key_file]
|
171
|
-
key_file = ssh_config['key_file'] || ssh_config[:key_file]
|
172
|
-
options[:keys] = [File.expand_path(key_file)]
|
173
|
-
end
|
174
|
-
|
175
|
-
return unless ssh_config['key_data'] || ssh_config[:key_data]
|
176
|
-
|
177
|
-
options[:key_data] = Array(ssh_config['key_data'] || ssh_config[:key_data])
|
178
|
-
end
|
179
|
-
|
180
|
-
def process_ssh_auth_options(ssh_config, options)
|
181
|
-
options[:password] = ssh_config['password'] || ssh_config[:password] if ssh_config['password'] || ssh_config[:password]
|
182
|
-
return unless ssh_config['passphrase'] || ssh_config[:passphrase]
|
183
|
-
|
184
|
-
options[:passphrase] = ssh_config['passphrase'] || ssh_config[:passphrase]
|
185
|
-
end
|
186
|
-
|
187
|
-
def process_ssh_verification_options(ssh_config, options)
|
188
|
-
return unless ssh_config.key?('verify_host_key') || ssh_config.key?(:verify_host_key)
|
189
|
-
|
190
|
-
verify_host_key = ssh_config['verify_host_key'] || ssh_config[:verify_host_key]
|
191
|
-
options[:verify_host_key] = verify_host_key ? :always : :never
|
192
|
-
end
|
193
|
-
|
194
|
-
def process_ssh_timeout_option(ssh_config, options)
|
195
|
-
options[:timeout] = ssh_config['timeout'] || ssh_config[:timeout] if ssh_config['timeout'] || ssh_config[:timeout]
|
196
|
-
end
|
197
|
-
|
198
|
-
def find_host_groups(hostname)
|
199
|
-
@groups.each_with_object([]) do |(group_name, group_config), groups|
|
200
|
-
groups << group_name if group_config[:hosts].include?(hostname)
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
def resolve_group_children
|
205
|
-
@groups.each do |group_name, group_config|
|
206
|
-
process_group_children(group_name, group_config)
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
def process_group_children(group_name, group_config)
|
211
|
-
group_config[:children].each do |child_group|
|
212
|
-
next unless @groups[child_group]
|
213
|
-
|
214
|
-
@groups[group_name][:hosts].concat(@groups[child_group][:hosts])
|
215
|
-
end
|
216
|
-
|
217
|
-
@groups[group_name][:hosts].uniq!
|
218
|
-
end
|
219
|
-
|
220
|
-
def apply_group_variables
|
221
|
-
@hosts.each do |hostname, host|
|
222
|
-
host_groups = find_host_groups(hostname)
|
223
|
-
apply_group_vars_to_host(host, host_groups)
|
224
|
-
apply_global_vars_to_host(host)
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
def apply_group_vars_to_host(host, host_groups)
|
229
|
-
host_groups.each do |group_name|
|
230
|
-
group_vars = @groups[group_name][:vars] || {}
|
231
|
-
group_vars.each do |key, value|
|
232
|
-
host.set_var(key, value) unless host.var(key)
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
def apply_global_vars_to_host(host)
|
238
|
-
@vars.each do |key, value|
|
239
|
-
host.set_var(key, value) unless host.var(key)
|
240
|
-
end
|
241
|
-
end
|
242
|
-
end
|
243
|
-
end
|
data/lib/kdeploy/logger.rb
DELETED
@@ -1,100 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Kdeploy
|
4
|
-
# Custom logger class for Kdeploy with colorized output
|
5
|
-
class KdeployLogger
|
6
|
-
class << self
|
7
|
-
attr_accessor :instance
|
8
|
-
|
9
|
-
# Set up logger instance with specified level and output file
|
10
|
-
# @param level [Symbol] Log level (:debug, :info, :warn, :error, :fatal)
|
11
|
-
# @param file [String, IO] Output file or IO stream
|
12
|
-
# @return [KdeployLogger] Logger instance
|
13
|
-
def setup(level: :info, file: nil)
|
14
|
-
@instance = new(level: level, file: file)
|
15
|
-
end
|
16
|
-
|
17
|
-
def method_missing(method_name, ...)
|
18
|
-
return super unless respond_to_missing?(method_name, false)
|
19
|
-
|
20
|
-
@instance ||= new
|
21
|
-
@instance.send(method_name, ...)
|
22
|
-
end
|
23
|
-
|
24
|
-
def respond_to_missing?(method_name, include_private = false)
|
25
|
-
return true if %i[debug info warn error fatal].include?(method_name)
|
26
|
-
|
27
|
-
super
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# Initialize logger with specified level and output file
|
32
|
-
# @param level [Symbol] Log level (:debug, :info, :warn, :error, :fatal)
|
33
|
-
# @param file [String, IO] Output file or IO stream
|
34
|
-
def initialize(level: :info, file: nil)
|
35
|
-
@logger = Logger.new(file || $stdout)
|
36
|
-
@logger.level = logger_level(level)
|
37
|
-
@logger.formatter = method(:format_message)
|
38
|
-
end
|
39
|
-
|
40
|
-
# Log debug message
|
41
|
-
# @param message [String] Message to log
|
42
|
-
def debug(message)
|
43
|
-
@logger.debug(message)
|
44
|
-
end
|
45
|
-
|
46
|
-
# Log info message
|
47
|
-
# @param message [String] Message to log
|
48
|
-
def info(message)
|
49
|
-
@logger.info(message)
|
50
|
-
end
|
51
|
-
|
52
|
-
# Log warning message
|
53
|
-
# @param message [String] Message to log
|
54
|
-
def warn(message)
|
55
|
-
@logger.warn(message)
|
56
|
-
end
|
57
|
-
|
58
|
-
# Log error message
|
59
|
-
# @param message [String] Message to log
|
60
|
-
def error(message)
|
61
|
-
@logger.error(message)
|
62
|
-
end
|
63
|
-
|
64
|
-
# Log fatal message
|
65
|
-
# @param message [String] Message to log
|
66
|
-
def fatal(message)
|
67
|
-
@logger.fatal(message)
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
def format_message(severity, datetime, _progname, msg)
|
73
|
-
timestamp = datetime.strftime('%Y-%m-%d %H:%M:%S')
|
74
|
-
colored_msg = colorize_message(severity, msg)
|
75
|
-
"[#{timestamp}] #{severity}: #{colored_msg}\n"
|
76
|
-
end
|
77
|
-
|
78
|
-
def logger_level(level)
|
79
|
-
case level.to_sym
|
80
|
-
when :debug then Logger::DEBUG
|
81
|
-
when :info then Logger::INFO
|
82
|
-
when :warn then Logger::WARN
|
83
|
-
when :error then Logger::ERROR
|
84
|
-
when :fatal then Logger::FATAL
|
85
|
-
else Logger::INFO
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def colorize_message(severity, message)
|
90
|
-
case severity
|
91
|
-
when 'DEBUG' then message.colorize(:light_black)
|
92
|
-
when 'INFO' then message.colorize(:green)
|
93
|
-
when 'WARN' then message.colorize(:yellow)
|
94
|
-
when 'ERROR' then message.colorize(:red)
|
95
|
-
when 'FATAL' then message.colorize(:light_red)
|
96
|
-
else message
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|