smart_proxy_remote_execution_ssh 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d24214ae74bec3832ef4537c14025712548c7e5a
4
- data.tar.gz: 191de9ecde2996a5198967a9e2c26b4a969d8b45
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MTEyZjNlZjgzOGU2ODkzNmYyMGM1NTgwNWZjM2VjZmU2NDljZmEwMw==
5
+ data.tar.gz: !binary |-
6
+ YjVmNmNiNDdiNTA5ZTU1YjNiNzNkMzcxOTkxZDY3YTgwN2QxYjBhNQ==
5
7
  SHA512:
6
- metadata.gz: 42fe7d6f9697a08d08b535b5a19532d1625c6a72d733fcf715d3bc2aa89d51474798996a5717da7aea171dc16675a0edca5cf5fc6fb3c5668cdf24f41a4f0ea8
7
- data.tar.gz: 54ede07833fb417e55f0bbdf0c354d85efedde2e842b2b8fb7b2c8545127a2d7a0893d557d4d626aba0076722d508bece408336fa3244a83b8e0609ec52245d1
8
+ metadata.gz: !binary |-
9
+ NmJmOTc3Njg3MmE5Yzk0NWQ0MjI3MmMwYjM0Mjk3Mzg3NWYxZDY2ZWI0YzNi
10
+ MjE1MDBkMjMwYTc0N2FlYjUyY2Q1MzgwZTQ0NzA5YzIwYmUyNTBlNzQ0NzI1
11
+ OTZhOGU5MWMyZGU5MzE1YjI4MzhmMWIwYjg5YzNmNTkzNGVkMjM=
12
+ data.tar.gz: !binary |-
13
+ NWRjNDU2YzgzNzAxM2NlMDliYTY3MTE5MDM3OTRkN2NiMzVmNmVlNTgxNTE4
14
+ YTcyMjY5YTJlZmE0NTkxYTJlOGNhM2ZmODEzZDE4ZWIwOTU4NDIyN2U2ZjFj
15
+ MWZhNTMzNDNkN2Y5ZDU4ZDFhNmU0ZTA4NWRlNGI1YjRhODU3NjE=
@@ -0,0 +1 @@
1
+ gem 'pry'
@@ -16,7 +16,7 @@ module Proxy::RemoteExecution::Ssh
16
16
  case event
17
17
  when nil
18
18
  init_run
19
- when Dispatcher::CommandUpdate
19
+ when CommandUpdate
20
20
  update = event
21
21
  output[:result].concat(update.buffer_to_hash)
22
22
  if update.exit_status
@@ -0,0 +1,73 @@
1
+ module Proxy::RemoteExecution::Ssh
2
+ # update sent back to the suspended action
3
+ class CommandUpdate
4
+ attr_reader :buffer, :exit_status
5
+
6
+ def initialize(buffer)
7
+ @buffer = buffer
8
+ extract_exit_status
9
+ end
10
+
11
+ def extract_exit_status
12
+ @buffer.delete_if do |data|
13
+ if data.is_a? StatusData
14
+ @exit_status = data.data
15
+ true
16
+ end
17
+ end
18
+ end
19
+
20
+ def buffer_to_hash
21
+ buffer.map(&:to_hash)
22
+ end
23
+
24
+ def self.encode_exception(description, exception, fatal = true)
25
+ ret = [DebugData.new("#{description}\n#{exception.class} #{exception.message}")]
26
+ ret << StatusData.new('EXCEPTION') if fatal
27
+ return ret
28
+ end
29
+
30
+ class Data
31
+ attr_reader :data, :timestamp
32
+
33
+ def initialize(data, timestamp = Time.now)
34
+ @data = data
35
+ @timestamp = timestamp
36
+ end
37
+
38
+ def data_type
39
+ raise NotImplemented
40
+ end
41
+
42
+ def to_hash
43
+ { :output_type => data_type,
44
+ :output => data,
45
+ :timestamp => timestamp.to_f }
46
+ end
47
+ end
48
+
49
+ class StdoutData < Data
50
+ def data_type
51
+ :stdout
52
+ end
53
+ end
54
+
55
+ class StderrData < Data
56
+ def data_type
57
+ :stderr
58
+ end
59
+ end
60
+
61
+ class DebugData < Data
62
+ def data_type
63
+ :debug
64
+ end
65
+ end
66
+
67
+ class StatusData < Data
68
+ def data_type
69
+ :status
70
+ end
71
+ end
72
+ end
73
+ end
@@ -6,49 +6,6 @@ module Proxy::RemoteExecution::Ssh
6
6
  # Dynflow action. It runs just one (actor) thread for all the commands
7
7
  # running in the system and updates the Dynflow actions periodically.
8
8
  class Connector
9
- class Data
10
- attr_reader :data, :timestamp
11
-
12
- def initialize(data, timestamp = Time.now)
13
- @data = data
14
- @timestamp = timestamp
15
- end
16
-
17
- def data_type
18
- raise NotImplemented
19
- end
20
-
21
- def to_hash
22
- { :output_type => data_type,
23
- :output => data,
24
- :timestamp => timestamp.to_f }
25
- end
26
- end
27
-
28
- class StdoutData < Data
29
- def data_type
30
- :stdout
31
- end
32
- end
33
-
34
- class StderrData < Data
35
- def data_type
36
- :stderr
37
- end
38
- end
39
-
40
- class DebugData < Data
41
- def data_type
42
- :debug
43
- end
44
- end
45
-
46
- class StatusData < Data
47
- def data_type
48
- :status
49
- end
50
- end
51
-
52
9
  MAX_PROCESS_RETRIES = 3
53
10
 
54
11
  def initialize(host, user, options = {})
@@ -65,16 +22,16 @@ module Proxy::RemoteExecution::Ssh
65
22
  def async_run(command)
66
23
  started = false
67
24
  session.open_channel do |channel|
68
- channel.on_data { |ch, data| yield StdoutData.new(data) }
25
+ channel.on_data { |ch, data| yield CommandUpdate::StdoutData.new(data) }
69
26
 
70
- channel.on_extended_data { |ch, type, data| yield StderrData.new(data) }
27
+ channel.on_extended_data { |ch, type, data| yield CommandUpdate::StderrData.new(data) }
71
28
 
72
29
  # standard exit of the command
73
- channel.on_request("exit-status") { |ch, data| yield StatusData.new(data.read_long) }
30
+ channel.on_request("exit-status") { |ch, data| yield CommandUpdate::StatusData.new(data.read_long) }
74
31
 
75
32
  # on signal: sedning the signal value (such as 'TERM')
76
33
  channel.on_request("exit-signal") do |ch, data|
77
- yield(StatusData.new(data.read_string))
34
+ yield(CommandUpdate::StatusData.new(data.read_string))
78
35
  ch.close
79
36
  # wait for the channel to finish so that we know at the end
80
37
  # that the session is inactive
@@ -84,8 +41,9 @@ module Proxy::RemoteExecution::Ssh
84
41
  channel.exec(command) do |ch, success|
85
42
  started = true
86
43
  unless success
87
- yield DebugData.new("FAILED: couldn't execute command (ssh.channel.exec)")
88
- yield StatusData.new("INIT_ERROR")
44
+ CommandUpdate.encode_exception("Error initializing command #{command}", e).each do |data|
45
+ yield data
46
+ end
89
47
  end
90
48
  end
91
49
  end
@@ -155,10 +113,6 @@ module Proxy::RemoteExecution::Ssh
155
113
  end
156
114
  end
157
115
 
158
- def inactive?
159
- @session.nil? || @session.channels.empty?
160
- end
161
-
162
116
  def close
163
117
  @logger.debug("closing session to #{@user}@#{@host}")
164
118
  @session.close unless @session.nil? || @session.closed?
@@ -1,4 +1,4 @@
1
- require 'smart_proxy_remote_execution_ssh/connector'
1
+ require 'smart_proxy_remote_execution_ssh/session'
2
2
 
3
3
  module Proxy::RemoteExecution::Ssh
4
4
  # Service that handles running external commands for Actions::Command
@@ -28,204 +28,65 @@ module Proxy::RemoteExecution::Ssh
28
28
  end
29
29
  end
30
30
 
31
- # update sent back to the suspended action
32
- class CommandUpdate
33
- attr_reader :buffer, :exit_status
34
-
35
- def initialize(buffer, exit_status)
36
- @buffer = buffer
37
- @exit_status = exit_status
38
- end
39
-
40
- def buffer_to_hash
41
- buffer.map(&:to_hash)
42
- end
43
- end
44
-
45
31
  def initialize(options = {})
46
32
  @clock = options[:clock] || Dynflow::Clock.spawn('proxy-dispatcher-clock')
47
33
  @logger = options[:logger] || Logger.new($stderr)
48
- @connector_class = options[:connector_class] || Connector
49
- @local_working_dir = options[:local_working_dir] || '/tmp/foreman-proxy-ssh/server'
50
- @remote_working_dir = options[:remote_working_dir] || '/tmp/foreman-proxy-ssh/client'
51
- @refresh_interval = options[:refresh_interval] || 1
52
- @client_private_key_file = Proxy::RemoteExecution::Ssh.private_key_file
53
34
 
54
- @connectors = {}
55
- @command_buffer = Hash.new { |h, k| h[k] = [] }
56
- @refresh_planned = false
35
+ @session_args = { :logger => @logger,
36
+ :clock => @clock,
37
+ :connector_class => options[:connector_class] || Connector,
38
+ :local_working_dir => options[:local_working_dir] || '/tmp/foreman-proxy-ssh/server',
39
+ :remote_working_dir => options[:remote_working_dir] || '/tmp/foreman-proxy-ssh/client',
40
+ :client_private_key_file => Proxy::RemoteExecution::Ssh.private_key_file,
41
+ :refresh_interval => options[:refresh_interval] || 1 }
42
+
43
+ @sessions = {}
57
44
  end
58
45
 
59
46
  def initialize_command(command)
60
47
  @logger.debug("initalizing command [#{command}]")
61
- connector = self.connector_for_command(command)
62
- remote_script = cp_script_to_remote(connector, command)
63
- if command.effective_user && command.effective_user != command.ssh_user
64
- su_prefix = "su - #{command.effective_user} -c "
65
- end
66
- output_path = File.join(File.dirname(remote_script), 'output')
67
-
68
- connector.async_run("#{su_prefix}#{remote_script} | /usr/bin/tee #{output_path}") do |data|
69
- command_buffer(command) << data
70
- end
71
- rescue => e
72
- @logger.error("error while initalizing command #{e.class} #{e.message}:\n #{e.backtrace.join("\n")}")
73
- command_buffer(command).concat([Connector::DebugData.new("Exception: #{e.class} #{e.message}"),
74
- Connector::StatusData.new('INIT_ERROR')])
75
- ensure
76
- plan_next_refresh
77
- end
78
-
79
- def refresh
80
- finished_commands = []
81
- refresh_connectors
82
-
83
- @command_buffer.each do |command, buffer|
84
- unless buffer.empty?
85
- status = refresh_command_buffer(command, buffer)
86
- if status
87
- finished_commands << command
88
- end
89
- end
90
- end
91
-
92
- finished_commands.each { |command| finish_command(command) }
93
- close_inactive_connectors
94
- ensure
95
- @refresh_planned = false
96
- plan_next_refresh
97
- end
98
-
99
- def refresh_command_buffer(command, buffer)
100
- status = nil
101
- @logger.debug("command #{command} got new output: #{buffer.inspect}")
102
- buffer.delete_if do |data|
103
- if data.is_a? Connector::StatusData
104
- status = data.data
105
- true
106
- end
107
- end
108
- command.suspended_action << CommandUpdate.new(buffer, status)
109
- clear_command(command)
110
- if status
111
- @logger.debug("command [#{command}] finished with status #{status}")
112
- return status
113
- end
48
+ open_session(command)
49
+ rescue => exception
50
+ handle_command_exception(command, exception)
114
51
  end
115
52
 
116
53
  def kill(command)
117
54
  @logger.debug("killing command [#{command}]")
118
- connector_for_command(command).run("pkill -f #{remote_command_file(command, 'script')}")
119
- end
120
-
121
- protected
122
-
123
- def connector_for_command(command, only_if_exists = false)
124
- if connector = @connectors[[command.host, command.ssh_user]]
125
- return connector
126
- end
127
- return nil if only_if_exists
128
- @connectors[[command.host, command.ssh_user]] = open_connector(command)
129
- end
130
-
131
- def local_command_dir(command)
132
- File.join(@local_working_dir, command.id)
133
- end
134
-
135
- def local_command_file(command, filename)
136
- File.join(local_command_dir(command), filename)
137
- end
138
-
139
- def remote_command_dir(command)
140
- File.join(@remote_working_dir, command.id)
141
- end
142
-
143
- def remote_command_file(command, filename)
144
- File.join(remote_command_dir(command), filename)
145
- end
146
-
147
- def ensure_local_directory(path)
148
- if File.exist?(path)
149
- raise "#{path} expected to be a directory" unless File.directory?(path)
150
- else
151
- FileUtils.mkdir_p(path)
152
- end
153
- return path
154
- end
155
-
156
- def cp_script_to_remote(connector, command)
157
- local_script_file = write_command_file_locally(command, 'script', command.script)
158
- File.chmod(0777, local_script_file)
159
- remote_script_file = remote_command_file(command, 'script')
160
- connector.upload_file(local_script_file, remote_script_file)
161
- return remote_script_file
162
- end
163
-
164
- def write_command_file_locally(command, filename, content)
165
- path = local_command_file(command, filename)
166
- ensure_local_directory(File.dirname(path))
167
- File.write(path, content)
168
- return path
169
- end
170
-
171
- def open_connector(command)
172
- options = { :logger => @logger }
173
- options[:known_hosts_file] = prepare_known_hosts(command)
174
- options[:client_private_key_file] = @client_private_key_file
175
- @connector_class.new(command.host, command.ssh_user, options)
176
- end
177
-
178
- def prepare_known_hosts(command)
179
- path = local_command_file(command, 'known_hosts')
180
- if command.host_public_key
181
- write_command_file_locally(command, 'known_hosts', "#{command.host} #{command.host_public_key}")
182
- end
183
- return path
184
- end
185
-
186
- def close_inactive_connectors
187
- @connectors.delete_if do |_, connector|
188
- if connector.inactive?
189
- connector.close
190
- true
191
- end
192
- end
55
+ session = @sessions[command.id]
56
+ session.tell(:kill) if session
57
+ rescue => exception
58
+ handle_command_exception(command, exception, false)
193
59
  end
194
60
 
195
- def refresh_connectors
196
- @logger.debug("refreshing #{@connectors.size} connectors")
197
-
198
- @connectors.values.each do |connector|
199
- begin
200
- connector.refresh
201
- rescue => e
202
- @command_buffer.each do |command, buffer|
203
- if connector_for_command(command, false)
204
- buffer << Connector::DebugData.new("Exception: #{e.class} #{e.message}")
205
- end
206
- end
207
- end
208
- end
61
+ def finish_command(command)
62
+ close_session(command)
63
+ rescue => exception
64
+ handle_command_exception(command, exception)
209
65
  end
210
66
 
211
- def command_buffer(command)
212
- @command_buffer[command]
213
- end
67
+ private
214
68
 
215
- def clear_command(command)
216
- @command_buffer[command] = []
69
+ def handle_command_exception(command, exception, fatal = true)
70
+ @logger.error("error while dispatching command #{command} to session:"\
71
+ "#{exception.class} #{exception.message}:\n #{exception.backtrace.join("\n")}")
72
+ command_data = CommandUpdate.encode_exception("Failed to dispatch the command", exception, fatal)
73
+ command.suspended_action << CommandUpdate.new(command_data)
74
+ close_session(command) if fatal
217
75
  end
218
76
 
219
- def finish_command(command)
220
- @command_buffer.delete(command)
77
+ def open_session(command)
78
+ raise "Session already opened for command #{command}" if @sessions[command.id]
79
+ options = { :name => "proxy-ssh-session-#{command.host}-#{command.ssh_user}-#{command.id}",
80
+ :args => [@session_args.merge(:command => command)],
81
+ :supervise => true }
82
+ @sessions[command.id] = Proxy::RemoteExecution::Ssh::Session.spawn(options)
221
83
  end
222
84
 
223
- def plan_next_refresh
224
- if @connectors.any? && !@refresh_planned
225
- @logger.debug("planning to refresh")
226
- @clock.ping(reference, Time.now + @refresh_interval, :refresh)
227
- @refresh_planned = true
228
- end
85
+ def close_session(command)
86
+ session = @sessions.delete(command.id)
87
+ return unless session
88
+ @logger.debug("closing session for command [#{command}], #{@sessions.size} session(s) left ")
89
+ session.tell([:start_termination, Concurrent.future])
229
90
  end
230
91
  end
231
92
  end
@@ -0,0 +1,169 @@
1
+ require 'smart_proxy_remote_execution_ssh/session'
2
+
3
+ module Proxy::RemoteExecution::Ssh
4
+ # Service that handles running external commands for Actions::Command
5
+ # Dynflow action. It runs just one (actor) thread for all the commands
6
+ # running in the system and updates the Dynflow actions periodically.
7
+ class Session < ::Dynflow::Actor
8
+ def initialize(options = {})
9
+ @clock = options[:clock] || Dynflow::Clock.spawn('proxy-dispatcher-clock')
10
+ @logger = options[:logger] || Logger.new($stderr)
11
+ @connector_class = options[:connector_class] || Connector
12
+ @local_working_dir = options[:local_working_dir] || '/tmp/foreman-proxy-ssh/server'
13
+ @remote_working_dir = options[:remote_working_dir] || '/tmp/foreman-proxy-ssh/client'
14
+ @refresh_interval = options[:refresh_interval] || 1
15
+ @client_private_key_file = Proxy::RemoteExecution::Ssh.private_key_file
16
+ @command = options[:command]
17
+
18
+ @command_buffer = []
19
+ @refresh_planned = false
20
+
21
+ reference.tell(:initialize_command)
22
+ end
23
+
24
+ def initialize_command
25
+ @logger.debug("initalizing command [#{@command}]")
26
+ open_connector
27
+ remote_script = cp_script_to_remote
28
+ if @command.effective_user && @command.effective_user != @command.ssh_user
29
+ su_prefix = "su - #{@command.effective_user} -c "
30
+ end
31
+ output_path = File.join(File.dirname(remote_script), 'output')
32
+
33
+ @connector.async_run("#{su_prefix}#{remote_script} | /usr/bin/tee #{output_path}") do |data|
34
+ @command_buffer << data
35
+ end
36
+ rescue => e
37
+ @logger.error("error while initalizing command #{e.class} #{e.message}:\n #{e.backtrace.join("\n")}")
38
+ @command_buffer.concat(CommandUpdate.encode_exception("Error initializing command #{@command}", e))
39
+ refresh
40
+ ensure
41
+ plan_next_refresh
42
+ end
43
+
44
+ def refresh
45
+ @connector.refresh if @connector
46
+
47
+ unless @command_buffer.empty?
48
+ status = refresh_command_buffer
49
+ if status
50
+ finish_command
51
+ end
52
+ end
53
+ rescue => e
54
+ @command_buffer.concat(CommandUpdate.encode_exception("Failed to refresh the connector", e, false))
55
+ ensure
56
+ @refresh_planned = false
57
+ plan_next_refresh
58
+ end
59
+
60
+ def refresh_command_buffer
61
+ @logger.debug("command #{@command} got new output: #{@command_buffer.inspect}")
62
+ command_update = CommandUpdate.new(@command_buffer)
63
+ @command.suspended_action << command_update
64
+ @command_buffer = []
65
+ if command_update.exit_status
66
+ @logger.debug("command [#{@command}] finished with status #{command_update.exit_status}")
67
+ return command_update.exit_status
68
+ end
69
+ end
70
+
71
+ def kill
72
+ @logger.debug("killing command [#{@command}]")
73
+ if @connector
74
+ @connector.run("pkill -f #{remote_command_file('script')}")
75
+ else
76
+ @logger.debug("connection closed")
77
+ end
78
+ rescue => e
79
+ @command_buffer.concat(CommandUpdate.encode_exception("Failed to kill the command", e, false))
80
+ plan_next_refresh
81
+ end
82
+
83
+ def finish_command
84
+ close
85
+ dispatcher.tell([:finish_command, @command])
86
+ end
87
+
88
+ def dispatcher
89
+ self.parent
90
+ end
91
+
92
+ def start_termination(*args)
93
+ super
94
+ close
95
+ finish_termination
96
+ end
97
+
98
+ private
99
+
100
+ def open_connector
101
+ raise 'Connector already opened' if @connector
102
+ options = { :logger => @logger }
103
+ options[:known_hosts_file] = prepare_known_hosts
104
+ options[:client_private_key_file] = @client_private_key_file
105
+ @connector = @connector_class.new(@command.host, @command.ssh_user, options)
106
+ end
107
+
108
+ def local_command_dir
109
+ File.join(@local_working_dir, @command.id)
110
+ end
111
+
112
+ def local_command_file(filename)
113
+ File.join(local_command_dir, filename)
114
+ end
115
+
116
+ def remote_command_dir
117
+ File.join(@remote_working_dir, @command.id)
118
+ end
119
+
120
+ def remote_command_file(filename)
121
+ File.join(remote_command_dir, filename)
122
+ end
123
+
124
+ def ensure_local_directory(path)
125
+ if File.exist?(path)
126
+ raise "#{path} expected to be a directory" unless File.directory?(path)
127
+ else
128
+ FileUtils.mkdir_p(path)
129
+ end
130
+ return path
131
+ end
132
+
133
+ def cp_script_to_remote
134
+ local_script_file = write_command_file_locally('script', @command.script)
135
+ File.chmod(0777, local_script_file)
136
+ remote_script_file = remote_command_file('script')
137
+ @connector.upload_file(local_script_file, remote_script_file)
138
+ return remote_script_file
139
+ end
140
+
141
+ def write_command_file_locally(filename, content)
142
+ path = local_command_file(filename)
143
+ ensure_local_directory(File.dirname(path))
144
+ File.write(path, content)
145
+ return path
146
+ end
147
+
148
+ def prepare_known_hosts
149
+ path = local_command_file('known_hosts')
150
+ if @command.host_public_key
151
+ write_command_file_locally('known_hosts', "#{@command.host} #{@command.host_public_key}")
152
+ end
153
+ return path
154
+ end
155
+
156
+ def close
157
+ @connector.close if @connector
158
+ @connector = nil
159
+ end
160
+
161
+ def plan_next_refresh
162
+ if @connector && !@refresh_planned
163
+ @logger.debug("planning to refresh")
164
+ @clock.ping(reference, Time.now + @refresh_interval, :refresh)
165
+ @refresh_planned = true
166
+ end
167
+ end
168
+ end
169
+ end
@@ -1,7 +1,7 @@
1
1
  module Proxy
2
2
  module RemoteExecution
3
3
  module Ssh
4
- VERSION = '0.0.3'
4
+ VERSION = '0.0.4'
5
5
  end
6
6
  end
7
7
  end
@@ -3,6 +3,8 @@ require 'smart_proxy_dynflow'
3
3
  require 'smart_proxy_remote_execution_ssh/version'
4
4
  require 'smart_proxy_remote_execution_ssh/plugin'
5
5
 
6
+ require 'smart_proxy_remote_execution_ssh/connector'
7
+ require 'smart_proxy_remote_execution_ssh/command_update'
6
8
  require 'smart_proxy_remote_execution_ssh/dispatcher'
7
9
  require 'smart_proxy_remote_execution_ssh/command_action'
8
10
 
metadata CHANGED
@@ -1,97 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_proxy_remote_execution_ssh
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Nečas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-20 00:00:00.000000000 Z
11
+ date: 2015-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ~>
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.7'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ~>
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.7'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
33
  version: '10.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - ! '>='
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - ! '>='
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: mocha
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: '1'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ~>
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: webmock
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ~>
74
74
  - !ruby/object:Gem::Version
75
75
  version: '1'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ~>
81
81
  - !ruby/object:Gem::Version
82
82
  version: '1'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rack-test
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ~>
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ~>
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
@@ -112,46 +112,47 @@ dependencies:
112
112
  name: smart_proxy_dynflow
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - "~>"
115
+ - - ~>
116
116
  - !ruby/object:Gem::Version
117
117
  version: 0.0.3
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - "~>"
122
+ - - ~>
123
123
  - !ruby/object:Gem::Version
124
124
  version: 0.0.3
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: net-ssh
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - ">="
129
+ - - ! '>='
130
130
  - !ruby/object:Gem::Version
131
131
  version: '0'
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - ">="
136
+ - - ! '>='
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: net-scp
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - ">="
143
+ - - ! '>='
144
144
  - !ruby/object:Gem::Version
145
145
  version: '0'
146
146
  type: :runtime
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - ">="
150
+ - - ! '>='
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
- description: |2
154
- Ssh remote execution provider for Foreman Smart-Proxy
153
+ description: ! ' Ssh remote execution provider for Foreman Smart-Proxy
154
+
155
+ '
155
156
  email:
156
157
  - inecas@redhat.com
157
158
  executables: []
@@ -162,14 +163,17 @@ extra_rdoc_files:
162
163
  files:
163
164
  - LICENSE
164
165
  - README.md
166
+ - bundler.d/Gemfile.local.rb
165
167
  - bundler.d/remote_execution_ssh.rb
166
168
  - lib/smart_proxy_remote_execution_ssh.rb
167
169
  - lib/smart_proxy_remote_execution_ssh/api.rb
168
170
  - lib/smart_proxy_remote_execution_ssh/command_action.rb
171
+ - lib/smart_proxy_remote_execution_ssh/command_update.rb
169
172
  - lib/smart_proxy_remote_execution_ssh/connector.rb
170
173
  - lib/smart_proxy_remote_execution_ssh/dispatcher.rb
171
174
  - lib/smart_proxy_remote_execution_ssh/http_config.ru
172
175
  - lib/smart_proxy_remote_execution_ssh/plugin.rb
176
+ - lib/smart_proxy_remote_execution_ssh/session.rb
173
177
  - lib/smart_proxy_remote_execution_ssh/version.rb
174
178
  - settings.d/remote_execution_ssh.yml.example
175
179
  homepage: https://github.com/theforeman/smart_proxy_remote_execution_ssh
@@ -182,18 +186,19 @@ require_paths:
182
186
  - lib
183
187
  required_ruby_version: !ruby/object:Gem::Requirement
184
188
  requirements:
185
- - - ">="
189
+ - - ! '>='
186
190
  - !ruby/object:Gem::Version
187
191
  version: '0'
188
192
  required_rubygems_version: !ruby/object:Gem::Requirement
189
193
  requirements:
190
- - - ">="
194
+ - - ! '>='
191
195
  - !ruby/object:Gem::Version
192
196
  version: '0'
193
197
  requirements: []
194
198
  rubyforge_project:
195
- rubygems_version: 2.4.5
199
+ rubygems_version: 2.4.8
196
200
  signing_key:
197
201
  specification_version: 4
198
202
  summary: Ssh remote execution provider for Foreman Smart-Proxy
199
203
  test_files: []
204
+ has_rdoc: