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 +4 -4
- data/lib/smart_proxy_remote_execution_ssh/actions/pull_script.rb +48 -16
- data/lib/smart_proxy_remote_execution_ssh/api.rb +8 -0
- data/lib/smart_proxy_remote_execution_ssh/multiplexed_ssh_connection.rb +2 -0
- data/lib/smart_proxy_remote_execution_ssh/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: debc9989aade4d23bda1b90e9fa8e85c99948f5b9ca37d6cecca7573bb994e5e
|
4
|
+
data.tar.gz: 38a2731c7f28643daaa33ddd29f93172b7467877f36b12c750b82f86e921c04d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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] =
|
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] =
|
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] =
|
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
|
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
|
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
|
-
|
98
|
-
when
|
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
|
-
|
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
|
-
|
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] =
|
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
|
-
|
167
|
-
|
168
|
-
|
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
|
|
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.
|
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:
|
11
|
+
date: 2023-01-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|