smart_proxy_remote_execution_ssh 0.10.0 → 0.10.1

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