smart_proxy_remote_execution_ssh 0.0.3 → 0.0.4

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 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: