smart_proxy_remote_execution_ssh 0.10.0 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '048f8694430967060fae6bd7790fe56930b5c2bac37f3bc26e7b13db69081da6'
4
- data.tar.gz: 5a3b1e344a47aa4c97dcce97f43dc9e424d398f79c67a6f1e066d670758c99f0
3
+ metadata.gz: debc9989aade4d23bda1b90e9fa8e85c99948f5b9ca37d6cecca7573bb994e5e
4
+ data.tar.gz: 38a2731c7f28643daaa33ddd29f93172b7467877f36b12c750b82f86e921c04d
5
5
  SHA512:
6
- metadata.gz: a4bc90b3dda6d190c8f94aeb6731a3a6679788ea4f950e1bb4196c1d5da4630b170fe152e9c96a5e4cb7dcd25ba1d6371292e52b4059773759c1fbe8461bd347
7
- data.tar.gz: f4849b32f7529cbb29d127ae1c4c9fd9642b0700c834b1e3eebf59b5d9cfca282fca674188a734a37b36d45ff3e423096aa3512ceae118aef7ff831cb1600a38
6
+ metadata.gz: a3f5776ce0f6ad361f2c344d0ff5d5cef9b6b032e23dc42ae0e877298abd9e95c0156c77334b106036f376e62c60c01ab13344d6bda53baa52c93c7caba79b71
7
+ data.tar.gz: d1de077038e5fce86df1871e4702e2abb4c7de4937f66aa8730803bb4542aa8f26c1c848d24bb74db1ce5594514d3a552b92b7ad315d346ead5e7586cb20da20
@@ -4,9 +4,20 @@ require 'time'
4
4
 
5
5
  module Proxy::RemoteExecution::Ssh::Actions
6
6
  class PullScript < Proxy::Dynflow::Action::Runner
7
+ include ::Dynflow::Action::Timeouts
8
+
7
9
  JobDelivered = Class.new
8
10
  PickupTimeout = Class.new
9
11
 
12
+ # The proxy has the job stored in its job storage
13
+ READY_FOR_PICKUP = 'ready_for_pickup'
14
+ # The host was notified over MQTT at least once
15
+ NOTIFIED = 'notified'
16
+ # The host has picked up the job
17
+ DELIVERED = 'delivered'
18
+ # We received at least one output from the host
19
+ RUNNING = 'running'
20
+
10
21
  execution_plan_hooks.use :cleanup, :on => :stopped
11
22
 
12
23
  def plan(action_input, mqtt: false)
@@ -16,14 +27,22 @@ module Proxy::RemoteExecution::Ssh::Actions
16
27
 
17
28
  def run(event = nil)
18
29
  if event == JobDelivered
19
- output[:state] = :delivered
30
+ output[:state] = DELIVERED
20
31
  suspend
21
32
  elsif event == PickupTimeout
22
33
  process_pickup_timeout
34
+ elsif event == ::Dynflow::Action::Timeouts::Timeout
35
+ process_timeout
36
+ elsif event.nil?
37
+ if (timeout = input['execution_timeout_interval'])
38
+ schedule_timeout(timeout, optional: true)
39
+ end
40
+ super
23
41
  else
24
42
  super
25
43
  end
26
44
  rescue => e
45
+ cleanup
27
46
  action_logger.error(e)
28
47
  process_update(Proxy::Dynflow::Runner::Update.encode_exception('Proxy error', e))
29
48
  end
@@ -36,7 +55,7 @@ module Proxy::RemoteExecution::Ssh::Actions
36
55
  plan_event(PickupTimeout, input[:time_to_pickup], optional: true) if input[:time_to_pickup]
37
56
 
38
57
  input[:job_uuid] = job_storage.store_job(host_name, execution_plan_id, run_step_id, input[:script].tr("\r", ''), effective_user: input[:effective_user])
39
- output[:state] = :ready_for_pickup
58
+ output[:state] = READY_FOR_PICKUP
40
59
  output[:result] = []
41
60
 
42
61
  mqtt_start(otp_password) if input[:with_mqtt]
@@ -50,7 +69,7 @@ module Proxy::RemoteExecution::Ssh::Actions
50
69
  end
51
70
 
52
71
  def process_external_event(event)
53
- output[:state] = :running
72
+ output[:state] = RUNNING
54
73
  data = event.data
55
74
  case data['version']
56
75
  when nil
@@ -89,19 +108,34 @@ module Proxy::RemoteExecution::Ssh::Actions
89
108
  process_update(Proxy::Dynflow::Runner::Update.new(continuous_output, exit_code))
90
109
  end
91
110
 
92
- def kill_run
111
+ def process_timeout
112
+ kill_run "Execution timeout exceeded"
113
+ end
114
+
115
+ def kill_run(fail_msg = 'The job was cancelled by the user')
116
+ continuous_output = Proxy::Dynflow::ContinuousOutput.new
117
+ exit_code = nil
118
+
93
119
  case output[:state]
94
- when :ready_for_pickup
120
+ when READY_FOR_PICKUP, NOTIFIED
95
121
  # If the job is not running yet on the client, wipe it from storage
96
122
  cleanup
97
- # TODO: Stop the action
98
- when :notified, :running
123
+ exit_code = 'EXCEPTION'
124
+ when DELIVERED, RUNNING
99
125
  # Client was notified or is already running, dealing with this situation
100
126
  # is only supported if mqtt is available
101
127
  # Otherwise we have to wait it out
102
- mqtt_cancel if input[:with_mqtt]
128
+ if input[:with_mqtt]
129
+ mqtt_cancel
130
+ fail_msg += ', notifying the host over MQTT'
131
+ else
132
+ fail_msg += ', however the job was triggered without MQTT and cannot be stopped'
133
+ end
103
134
  end
104
- suspend
135
+ continuous_output.add_output(fail_msg + "\n")
136
+ process_update(Proxy::Dynflow::Runner::Update.new(continuous_output, exit_code))
137
+
138
+ suspend unless exit_code
105
139
  end
106
140
 
107
141
  def mqtt_start(otp_password)
@@ -118,12 +152,12 @@ module Proxy::RemoteExecution::Ssh::Actions
118
152
  },
119
153
  )
120
154
  Proxy::RemoteExecution::Ssh::MQTT::Dispatcher.instance.new(input[:job_uuid], mqtt_topic, payload)
121
- output[:state] = :notified
155
+ output[:state] = NOTIFIED
122
156
  end
123
157
 
124
158
  def mqtt_cancel
125
- cleanup
126
159
  payload = mqtt_payload_base.merge(
160
+ content: "#{input[:proxy_url]}/ssh/jobs/#{input[:job_uuid]}/cancel",
127
161
  metadata: {
128
162
  'event': 'cancel',
129
163
  'job_uuid': input[:job_uuid]
@@ -163,11 +197,9 @@ module Proxy::RemoteExecution::Ssh::Actions
163
197
  end
164
198
 
165
199
  def process_pickup_timeout
166
- if output[:state] != :delivered
167
- raise "The job was not picked up in time"
168
- else
169
- suspend
170
- end
200
+ suspend unless [READY_FOR_PICKUP, NOTIFIED].include? output[:state]
201
+
202
+ kill_run 'The job was not picked up in time'
171
203
  end
172
204
  end
173
205
  end
@@ -71,6 +71,14 @@ module Proxy::RemoteExecution
71
71
  end
72
72
  end
73
73
 
74
+ get "/jobs/:job_uuid/cancel" do |job_uuid|
75
+ do_authorize_with_ssl_client
76
+
77
+ with_authorized_job(job_uuid) do |job_record|
78
+ {}
79
+ end
80
+ end
81
+
74
82
  private
75
83
 
76
84
  def notify_job(job_record, event)
@@ -154,6 +154,8 @@ module Proxy::RemoteExecution::Ssh::Runners
154
154
  ssh_options << "-o ControlPath=#{socket_file}"
155
155
  ssh_options << "-o ControlPersist=yes"
156
156
  ssh_options << "-o ProxyCommand=none"
157
+ ssh_options << "-o ServerAliveInterval=15"
158
+ ssh_options << "-o ServerAliveCountMax=3" # This is the default, but let's be explicit
157
159
  @establish_ssh_options = ssh_options
158
160
  end
159
161
 
@@ -1,7 +1,7 @@
1
1
  module Proxy
2
2
  module RemoteExecution
3
3
  module Ssh
4
- VERSION = '0.10.0'
4
+ VERSION = '0.10.1'
5
5
  end
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_proxy_remote_execution_ssh
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.10.1
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: 2022-12-12 00:00:00.000000000 Z
11
+ date: 2023-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler