cpee 2.1.122 → 2.1.123
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/cpee.gemspec +1 -1
- data/lib/cpee/persistence.rb +20 -11
- data/server/executionhandlers/eval/connection.rb +5 -2
- data/server/executionhandlers/eval/controller.rb +1 -0
- data/server/executionhandlers/eval/execution.rb +32 -17
- data/server/executionhandlers/ruby/connection.rb +13 -7
- data/server/executionhandlers/ruby/controller.rb +4 -8
- data/server/executionhandlers/ruby/dsl_to_dslx.xsl +6 -3
- data/server/executionhandlers/ruby/execution.rb +31 -17
- data/server/routing/end.pid +1 -1
- data/server/routing/forward-events-00.pid +1 -1
- data/server/routing/forward-votes.pid +1 -1
- data/server/routing/persist.pid +1 -1
- data/server/routing/persist.rb +9 -1
- metadata +1 -1
- data/server/executionhandlers/eval/controller.rb +0 -226
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 63c48292c70c40336ce8385bb86fbea2722ebb3becbfe091843f5d7f60268d0c
|
|
4
|
+
data.tar.gz: 8b53f0ea495c73ccc423ad1cbca5c764928fdee41ab7af9c853f725c3dc3ed34
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 977f66a12107bd16c154d55320a3d1f42bf15713419e50dcf1456532dffd332b6d465ec97f2721b61b3ec0d50aab5768b3dabb77a8ecc87ae3e78f63aa63ac77
|
|
7
|
+
data.tar.gz: 6038b1ba120f2b8ca11e53f5b00987658c6789f33382c215be5bcf5b252f88d3e215c3a4281d614236a40bd93926e2bd4ab90ddb49f97195f67fdead80b5411d
|
data/cpee.gemspec
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Gem::Specification.new do |s|
|
|
2
2
|
s.name = "cpee"
|
|
3
|
-
s.version = "2.1.
|
|
3
|
+
s.version = "2.1.123"
|
|
4
4
|
s.platform = Gem::Platform::RUBY
|
|
5
5
|
s.license = "LGPL-3.0-or-later"
|
|
6
6
|
s.summary = "The cloud process execution engine (cpee.org). If you just need workflow execution, without a rest service exposing it, then use WEEL."
|
data/lib/cpee/persistence.rb
CHANGED
|
@@ -41,15 +41,19 @@ module CPEE
|
|
|
41
41
|
when 'endpoints' then endpoints
|
|
42
42
|
when 'dataelements' then dataelements
|
|
43
43
|
end
|
|
44
|
+
sort = []
|
|
44
45
|
if diff
|
|
45
46
|
deletions = oldvalues.keys - values.keys
|
|
47
|
+
if oldvalues.length > 1 && oldvalues.length == values.length && deletions.length == 0 && oldvalues.keys != values.keys
|
|
48
|
+
sort = values.keys
|
|
49
|
+
end
|
|
46
50
|
values.delete_if do |k,v|
|
|
47
51
|
oldvalues[k] && oldvalues[k] == v
|
|
48
52
|
end
|
|
49
53
|
end
|
|
50
54
|
payload = {
|
|
51
55
|
:values => oldvalues.merge(values).transform_values{|val| JSON::parse(val) rescue val },
|
|
52
|
-
:attributes => ah.translate(attributes,dataelements,endpoints)
|
|
56
|
+
:attributes => ah.translate(attributes,dataelements,endpoints)
|
|
53
57
|
}
|
|
54
58
|
CPEE::Message::send(
|
|
55
59
|
:event,
|
|
@@ -66,16 +70,21 @@ module CPEE
|
|
|
66
70
|
if delete
|
|
67
71
|
payload[:deleted] = deletions
|
|
68
72
|
end
|
|
69
|
-
|
|
70
|
-
:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
if sort.any?
|
|
74
|
+
payload[:sort] = sort
|
|
75
|
+
end
|
|
76
|
+
if values.any? || deletions.any? || sort.any?
|
|
77
|
+
CPEE::Message::send(
|
|
78
|
+
:event,
|
|
79
|
+
File.join(item,'change'),
|
|
80
|
+
opts[:url],
|
|
81
|
+
id,
|
|
82
|
+
Persistence::extract_item(id,opts,'attributes/uuid'),
|
|
83
|
+
Persistence::extract_item(id,opts,'attributes/info'),
|
|
84
|
+
payload,
|
|
85
|
+
opts[:redis]
|
|
86
|
+
)
|
|
87
|
+
end
|
|
79
88
|
end #}}}
|
|
80
89
|
def self::extract_set(id,opts,item) #{{{
|
|
81
90
|
opts[:redis].smembers(@@obj + ":#{id}/#{item}").map do |e|
|
|
@@ -29,9 +29,12 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
|
|
|
29
29
|
tso + 2 > tsn && count > 100
|
|
30
30
|
end # }}}
|
|
31
31
|
|
|
32
|
-
def self::inform_state_change(arguments,newstate) # {{{
|
|
32
|
+
def self::inform_state_change(arguments,newstate,data) # {{{
|
|
33
33
|
controller = arguments[0]
|
|
34
|
-
controller.notify(
|
|
34
|
+
controller.notify('state/change', :state => newstate)
|
|
35
|
+
if newstate == :stopped || newstate == :finished
|
|
36
|
+
controller.notify('dataelements/modify', :eid => 'ex-post', :values => data)
|
|
37
|
+
end
|
|
35
38
|
end # }}}
|
|
36
39
|
def self::inform_syntax_error(arguments,err,code)# {{{
|
|
37
40
|
# TODO extract spot (code) where error happened for better error handling (ruby 3.1 only)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
../ruby/controller.rb
|
|
@@ -19,21 +19,22 @@ module CPEE
|
|
|
19
19
|
|
|
20
20
|
module ExecutionHandler
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
BACKEND_INSTANCE = 'instance.rb'
|
|
24
|
-
DSL_TO_DSLX_XSL = File.expand_path(File.join(__dir__,'dsl_to_dslx.xsl'))
|
|
25
|
-
BACKEND_RUN = File.expand_path(File.join(__dir__,'backend','run.rb'))
|
|
26
|
-
BACKEND_OPTS = File.expand_path(File.join(__dir__,'backend','opts.yaml'))
|
|
27
|
-
BACKEND_TEMPLATE = File.expand_path(File.join(__dir__,'backend','instance.template'))
|
|
22
|
+
self.const_set File.basename(__dir__).capitalize, Module.new {
|
|
23
|
+
self::BACKEND_INSTANCE = 'instance.rb'
|
|
24
|
+
self::DSL_TO_DSLX_XSL = File.expand_path(File.join(__dir__,'dsl_to_dslx.xsl'))
|
|
25
|
+
self::BACKEND_RUN = File.expand_path(File.join(__dir__,'backend','run.rb'))
|
|
26
|
+
self::BACKEND_OPTS = File.expand_path(File.join(__dir__,'backend','opts.yaml'))
|
|
27
|
+
self::BACKEND_TEMPLATE = File.expand_path(File.join(__dir__,'backend','instance.template'))
|
|
28
28
|
|
|
29
29
|
def self::dslx_to_dsl(dslx,ep) # transpile
|
|
30
|
-
trans = XML::Smart::open_unprotected(
|
|
30
|
+
trans = XML::Smart::open_unprotected(self::DSL_TO_DSLX_XSL)
|
|
31
31
|
dslx.transform_with(trans).to_s
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def self::prepare(id,opts) # write result to disk
|
|
35
|
+
FileUtils.rm_rf(Dir.glob(File.join(opts[:instances],id.to_s,'*')) + Dir.glob(File.join(opts[:instances],id.to_s,'.remote')))
|
|
35
36
|
Dir.mkdir(File.join(opts[:instances],id.to_s)) rescue nil
|
|
36
|
-
FileUtils.copy(
|
|
37
|
+
FileUtils.copy(self::BACKEND_RUN,File.join(opts[:instances],id.to_s))
|
|
37
38
|
dsl = CPEE::Persistence::extract_item(id,opts,'dsl')
|
|
38
39
|
hw = CPEE::Persistence::extract_item(id,opts,'executionhandler')
|
|
39
40
|
endpoints = CPEE::Persistence::extract_list(id,opts,'endpoints')
|
|
@@ -43,7 +44,8 @@ module CPEE
|
|
|
43
44
|
positions.map! do |k, v|
|
|
44
45
|
[ k, v, CPEE::Persistence::extract_item(id,opts,File.join('positions',k,'@passthrough')) ]
|
|
45
46
|
end
|
|
46
|
-
iopts = YAML::load_file(
|
|
47
|
+
iopts = YAML::load_file(self::BACKEND_OPTS)
|
|
48
|
+
iopts[:instance_id] = id
|
|
47
49
|
iopts[:host] = opts[:host]
|
|
48
50
|
iopts[:url] = opts[:url]
|
|
49
51
|
iopts[:redis_url] = opts[:redis_url]
|
|
@@ -57,13 +59,26 @@ module CPEE
|
|
|
57
59
|
iopts[:executionhandlers] = opts[:executionhandlers]
|
|
58
60
|
iopts[:global_executionhandlers] = opts[:global_executionhandlers]
|
|
59
61
|
end
|
|
62
|
+
iopts[:attributes] = attributes
|
|
63
|
+
iopts[:votes] = {}
|
|
64
|
+
CPEE::Persistence::extract_handlers(id,opts).each do |de|
|
|
65
|
+
if de[1] && de[1]&.empty?.!
|
|
66
|
+
CPEE::Persistence::extract_handler(id,opts,de[0]).each do |ele|
|
|
67
|
+
topic, type, name = ele.split('/')
|
|
68
|
+
if type == 'vote'
|
|
69
|
+
iopts[:votes][ele] ||= []
|
|
70
|
+
iopts[:votes][ele] << de[0]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
60
75
|
|
|
61
|
-
File.open(File.join(opts[:instances],id.to_s,File.basename(
|
|
76
|
+
File.open(File.join(opts[:instances],id.to_s,File.basename(self::BACKEND_OPTS)),'w') do |f|
|
|
62
77
|
YAML::dump(iopts,f)
|
|
63
78
|
end
|
|
64
|
-
template = ERB.new(File.read(
|
|
79
|
+
template = ERB.new(File.read(self::BACKEND_TEMPLATE), trim_mode: '-')
|
|
65
80
|
res = template.result_with_hash(dsl: dsl, dataelements: dataelements, endpoints: endpoints, positions: positions)
|
|
66
|
-
File.write(File.join(opts[:instances],id.to_s,
|
|
81
|
+
File.write(File.join(opts[:instances],id.to_s,self::BACKEND_INSTANCE),res)
|
|
67
82
|
if attributes.has_key?('remote')
|
|
68
83
|
uri = URI::parse(attributes['remote'])
|
|
69
84
|
Net::SSH.start(uri.host,uri.user,:keys => [ opts[:ssh_key] ] ) do |ssh|
|
|
@@ -77,12 +92,12 @@ module CPEE
|
|
|
77
92
|
def self::run(id,opts)
|
|
78
93
|
if File.exist? File.join(opts[:instances],id.to_s,'.remote')
|
|
79
94
|
uri = URI::parse(File.read(File.join(opts[:instances],id.to_s,'.remote')))
|
|
80
|
-
exe = File.join(uri.path,id.to_s,File.basename(BACKEND_RUN))
|
|
95
|
+
exe = File.join(uri.path,id.to_s,File.basename(self::BACKEND_RUN))
|
|
81
96
|
Net::SSH.start(uri.host,uri.user,:keys => [ opts[:ssh_key] ] ) do |ssh|
|
|
82
97
|
ssh.exec!("ruby #{exe} >#{exe}.out 2>#{exe}.err &")
|
|
83
98
|
end
|
|
84
99
|
else
|
|
85
|
-
exe = File.join(opts[:instances],id.to_s,File.basename(
|
|
100
|
+
exe = File.join(opts[:instances],id.to_s,File.basename(self::BACKEND_RUN))
|
|
86
101
|
pid = Kernel.spawn(opts[:libs_preloaderrun] + ' ' + exe , :pgroup => true, :in => '/dev/null', :out => exe + '.out', :err => exe + '.err')
|
|
87
102
|
Process.detach pid
|
|
88
103
|
File.write(exe + '.pid',pid)
|
|
@@ -92,7 +107,7 @@ module CPEE
|
|
|
92
107
|
def self::stop(id,opts) ### return: bool to tell if manually changing redis is necessary
|
|
93
108
|
if File.exist? File.join(opts[:instances],id.to_s,'.remote')
|
|
94
109
|
uri = URI::parse(File.read(File.join(opts[:instances],id.to_s,'.remote')))
|
|
95
|
-
exe = File.join(uri.path,id.to_s,File.basename(BACKEND_RUN))
|
|
110
|
+
exe = File.join(uri.path,id.to_s,File.basename(self::BACKEND_RUN))
|
|
96
111
|
Net::SSH.start(uri.host,uri.user,:keys => [ opts[:ssh_key] ] ) do |ssh|
|
|
97
112
|
pid = ssh.exec!("cat #{exe}.pid 2>/dev/null")
|
|
98
113
|
if pid != '' && ssh.exec!("kill -0 #{pid} >/dev/null 2>&1; echo $?").strip == '0'
|
|
@@ -104,7 +119,7 @@ module CPEE
|
|
|
104
119
|
end
|
|
105
120
|
end
|
|
106
121
|
else
|
|
107
|
-
exe = File.join(opts[:instances],id.to_s,File.basename(
|
|
122
|
+
exe = File.join(opts[:instances],id.to_s,File.basename(self::BACKEND_RUN))
|
|
108
123
|
pid = File.read(exe + '.pid') rescue nil
|
|
109
124
|
if pid && (Process.kill(0, pid.to_i) rescue false)
|
|
110
125
|
Process.kill('HUP', pid.to_i) rescue nil
|
|
@@ -115,7 +130,7 @@ module CPEE
|
|
|
115
130
|
end
|
|
116
131
|
end
|
|
117
132
|
end
|
|
118
|
-
|
|
133
|
+
}
|
|
119
134
|
|
|
120
135
|
end
|
|
121
136
|
|
|
@@ -99,7 +99,7 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
|
|
|
99
99
|
}
|
|
100
100
|
end #}}}
|
|
101
101
|
|
|
102
|
-
def proto_curl(parameters) #{{{
|
|
102
|
+
def proto_curl(parameters, dataelements) #{{{
|
|
103
103
|
params = []
|
|
104
104
|
callback = SecureRandom.hex(16)
|
|
105
105
|
(parameters[:arguments] || []).each do |s|
|
|
@@ -203,11 +203,11 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
|
|
|
203
203
|
headers['CPEE_SALVAGE'] = true
|
|
204
204
|
c = result[0]&.value
|
|
205
205
|
c = c.read if c.respond_to? :read
|
|
206
|
-
callback([ Riddl::Parameter::Complex.new('error','application/json',StringIO.new(JSON::generate({ 'status' => status, 'error' => c }))) ], headers)
|
|
206
|
+
callback([ Riddl::Parameter::Complex.new('error','application/json',StringIO.new(JSON::generate({ 'status' => status, 'error' => c }))) ], headers, dataelements)
|
|
207
207
|
else
|
|
208
208
|
if headers['CPEE_CALLBACK'] && headers['CPEE_CALLBACK'] == 'true' && result.any?
|
|
209
209
|
headers['CPEE_UPDATE'] = true
|
|
210
|
-
callback result, headers
|
|
210
|
+
callback result, headers, dataelements
|
|
211
211
|
elsif headers['CPEE_CALLBACK'] && headers['CPEE_CALLBACK'] == 'true' && result.empty?
|
|
212
212
|
if headers['CPEE_INSTANTIATION']
|
|
213
213
|
@controller.notify("task/instantiation", :'activity-uuid' => @handler_activity_uuid, :label => @label, :activity => @handler_position, :endpoint => @handler_endpoint, :received => CPEE::ValueHelper.parse(headers['CPEE_INSTANTIATION']))
|
|
@@ -217,19 +217,19 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
|
|
|
217
217
|
end
|
|
218
218
|
# do nothing, later on things will happend
|
|
219
219
|
else
|
|
220
|
-
callback result, headers
|
|
220
|
+
callback result, headers, dataelements
|
|
221
221
|
end
|
|
222
222
|
end
|
|
223
223
|
end #}}}
|
|
224
224
|
|
|
225
|
-
def activity_handle(passthrough, parameters) # {{{
|
|
225
|
+
def activity_handle(passthrough, parameters, dataelements) # {{{
|
|
226
226
|
raise "Wrong endpoint" if @handler_endpoint.nil? || @handler_endpoint.empty?
|
|
227
227
|
@label = parameters[:label]
|
|
228
228
|
@anno = parameters.delete(:annotations) rescue nil
|
|
229
229
|
@controller.notify("activity/calling", :'activity-uuid' => @handler_activity_uuid, :label => @label, :activity => @handler_position, :passthrough => passthrough, :endpoint => @handler_endpoint, :parameters => parameters)
|
|
230
230
|
@controller.notify("activity/annotation", :'activity-uuid' => @handler_activity_uuid, :label => @label, :activity => @handler_position, :annotations => @anno)
|
|
231
231
|
if passthrough.to_s.empty?
|
|
232
|
-
proto_curl parameters
|
|
232
|
+
proto_curl parameters, dataelements
|
|
233
233
|
else
|
|
234
234
|
@controller.callback(self,passthrough,:'activity-uuid' => @handler_activity_uuid, :label => @label, :activity => @handler_position)
|
|
235
235
|
@handler_passthrough = passthrough
|
|
@@ -274,6 +274,9 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
|
|
|
274
274
|
unless changed_dataelements.nil? || changed_dataelements.empty?
|
|
275
275
|
de = dataelements.slice(*changed_dataelements).transform_values { |v| enc = CPEE::EvalRuby::Translation::detect_encoding(v); (enc == 'OTHER' ? v : (v.encode('UTF-8',enc) rescue CPEE::EvalRuby::Translation::convert_to_base64(v))) }
|
|
276
276
|
@controller.notify("dataelements/change", :'activity-uuid' => @handler_activity_uuid, :endpoint => @handler_endpoint, :label => @label, :activity => @handler_position, :changed => changed_dataelements, :values => de)
|
|
277
|
+
if @anno && @anno[:_context_data_analysis] && @anno[:_context_data_analysis][:probes] && @anno[:_context_data_analysis][:probes].find{ |p| p.dig(:probe,:extractor_type) == 'intrinsic' }
|
|
278
|
+
@controller.notify("task/probe", :'activity-uuid' => @handler_activity_uuid, :endpoint => @handler_endpoint, :label => @label, :activity => @handler_position, :data => dataelements, :probes => @anno[:_context_data_analysis][:probes])
|
|
279
|
+
end
|
|
277
280
|
end
|
|
278
281
|
unless changed_endpoints.nil? || changed_endpoints.empty?
|
|
279
282
|
@controller.notify("endpoints/change", :'activity-uuid' => @handler_activity_uuid, :endpoint => @handler_endpoint, :label => @label, :activity => @handler_position, :changed => changed_endpoints, :values => endpoints.slice(*changed_endpoints))
|
|
@@ -287,7 +290,7 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
|
|
|
287
290
|
@controller.vote("activity/syncing_before", :'activity-uuid' => @handler_activity_uuid, :endpoint => @handler_endpoint, :activity => @handler_position, :label => @label, :parameters => parameters)
|
|
288
291
|
end # }}}
|
|
289
292
|
|
|
290
|
-
def callback(result=nil,options={}) #{{{
|
|
293
|
+
def callback(result=nil,options={}, dataelements) #{{{
|
|
291
294
|
status, ret, headers = Riddl::Client.new(@controller.url_result_transformation).request 'put' => result
|
|
292
295
|
recv = if status >= 200 && status < 300
|
|
293
296
|
JSON::parse(ret[0].value.read)
|
|
@@ -296,6 +299,9 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
|
|
|
296
299
|
end
|
|
297
300
|
|
|
298
301
|
@controller.notify("activity/receiving", :'activity-uuid' => @handler_activity_uuid, :label => @label, :activity => @handler_position, :endpoint => @handler_endpoint, :received => recv)
|
|
302
|
+
if @anno[:_context_data_analysis] && @anno[:_context_data_analysis][:probes] && @anno[:_context_data_analysis][:probes].find{ |p| p.dig(:probe,:extractor_type) == 'extrinsic' }
|
|
303
|
+
@controller.notify("task/probe", :'activity-uuid' => @handler_activity_uuid, :label => @label, :activity => @handler_position, :endpoint => @handler_endpoint, :received => recv, :data => dataelements, :probes => @anno[:_context_data_analysis]&.[](:probes))
|
|
304
|
+
end
|
|
299
305
|
|
|
300
306
|
@guard_files += result
|
|
301
307
|
@guard_files += ret
|
|
@@ -21,7 +21,6 @@ require 'cpee/value_helper'
|
|
|
21
21
|
require 'cpee/attributes_helper'
|
|
22
22
|
require 'cpee/message'
|
|
23
23
|
require 'cpee/redis'
|
|
24
|
-
require 'cpee/persistence'
|
|
25
24
|
require 'get_process_mem'
|
|
26
25
|
|
|
27
26
|
require 'ostruct'
|
|
@@ -42,12 +41,9 @@ class Controller
|
|
|
42
41
|
|
|
43
42
|
@id = id
|
|
44
43
|
|
|
45
|
-
@attributes =
|
|
46
|
-
CPEE::Persistence::extract_list(id,opts,'attributes').each do |de|
|
|
47
|
-
@attributes[de[0]] = de[1]
|
|
48
|
-
end
|
|
49
|
-
|
|
44
|
+
@attributes = opts[:attributes]
|
|
50
45
|
@attributes_helper = AttributesHelper.new
|
|
46
|
+
|
|
51
47
|
@thread = nil
|
|
52
48
|
@opts = opts
|
|
53
49
|
@instance = nil
|
|
@@ -74,7 +70,7 @@ class Controller
|
|
|
74
70
|
resp << Riddl::Parameter::Complex.new(e[0],e[1][1],e[1][2])
|
|
75
71
|
end
|
|
76
72
|
end
|
|
77
|
-
@callback_keys[identifier].send(:callback,resp,m['content']['headers'])
|
|
73
|
+
@callback_keys[identifier].send(:callback,resp,m['content']['headers'],dataelements)
|
|
78
74
|
end
|
|
79
75
|
end
|
|
80
76
|
if pat == 'callback-end:*'
|
|
@@ -183,7 +179,7 @@ class Controller
|
|
|
183
179
|
handler = File.join(topic,'vote',name)
|
|
184
180
|
votes = []
|
|
185
181
|
|
|
186
|
-
|
|
182
|
+
@opts[:votes][handler]&.each do |client|
|
|
187
183
|
voteid = SecureRandom.hex(16)
|
|
188
184
|
content[:key] = voteid
|
|
189
185
|
content[:attributes] = attributes_translated
|
|
@@ -91,9 +91,12 @@
|
|
|
91
91
|
</xsl:if>
|
|
92
92
|
<xsl:if test="name()='manipulate'">
|
|
93
93
|
<xsl:if test="@label">
|
|
94
|
-
<xsl:text>, {
|
|
95
|
-
<xsl:
|
|
96
|
-
|
|
94
|
+
<xsl:text>, { </xsl:text>
|
|
95
|
+
<xsl:text>:label => "</xsl:text>
|
|
96
|
+
<xsl:value-of select="@label"/>
|
|
97
|
+
<xsl:text>", </xsl:text>
|
|
98
|
+
<xsl:apply-templates select="d:annotations" mode="annotations"/>
|
|
99
|
+
<xsl:text> }</xsl:text>
|
|
97
100
|
</xsl:if>
|
|
98
101
|
<xsl:call-template name="print-mcontent">
|
|
99
102
|
<xsl:with-param name="myspace">
|
|
@@ -19,22 +19,22 @@ module CPEE
|
|
|
19
19
|
|
|
20
20
|
module ExecutionHandler
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
BACKEND_INSTANCE = 'instance.rb'
|
|
24
|
-
DSL_TO_DSLX_XSL = File.expand_path(File.join(__dir__,'dsl_to_dslx.xsl'))
|
|
25
|
-
BACKEND_RUN = File.expand_path(File.join(__dir__,'backend','run.rb'))
|
|
26
|
-
BACKEND_OPTS = File.expand_path(File.join(__dir__,'backend','opts.yaml'))
|
|
27
|
-
BACKEND_TEMPLATE = File.expand_path(File.join(__dir__,'backend','instance.template'))
|
|
22
|
+
self.const_set File.basename(__dir__).capitalize, Module.new {
|
|
23
|
+
self::BACKEND_INSTANCE = 'instance.rb'
|
|
24
|
+
self::DSL_TO_DSLX_XSL = File.expand_path(File.join(__dir__,'dsl_to_dslx.xsl'))
|
|
25
|
+
self::BACKEND_RUN = File.expand_path(File.join(__dir__,'backend','run.rb'))
|
|
26
|
+
self::BACKEND_OPTS = File.expand_path(File.join(__dir__,'backend','opts.yaml'))
|
|
27
|
+
self::BACKEND_TEMPLATE = File.expand_path(File.join(__dir__,'backend','instance.template'))
|
|
28
28
|
|
|
29
29
|
def self::dslx_to_dsl(dslx,ep) # transpile
|
|
30
|
-
trans = XML::Smart::open_unprotected(
|
|
30
|
+
trans = XML::Smart::open_unprotected(self::DSL_TO_DSLX_XSL)
|
|
31
31
|
dslx.transform_with(trans).to_s
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def self::prepare(id,opts) # write result to disk
|
|
35
35
|
FileUtils.rm_rf(Dir.glob(File.join(opts[:instances],id.to_s,'*')) + Dir.glob(File.join(opts[:instances],id.to_s,'.remote')))
|
|
36
36
|
Dir.mkdir(File.join(opts[:instances],id.to_s)) rescue nil
|
|
37
|
-
FileUtils.copy(
|
|
37
|
+
FileUtils.copy(self::BACKEND_RUN,File.join(opts[:instances],id.to_s))
|
|
38
38
|
dsl = CPEE::Persistence::extract_item(id,opts,'dsl')
|
|
39
39
|
hw = CPEE::Persistence::extract_item(id,opts,'executionhandler')
|
|
40
40
|
endpoints = CPEE::Persistence::extract_list(id,opts,'endpoints')
|
|
@@ -44,7 +44,8 @@ module CPEE
|
|
|
44
44
|
positions.map! do |k, v|
|
|
45
45
|
[ k, v, CPEE::Persistence::extract_item(id,opts,File.join('positions',k,'@passthrough')) ]
|
|
46
46
|
end
|
|
47
|
-
iopts = YAML::load_file(
|
|
47
|
+
iopts = YAML::load_file(self::BACKEND_OPTS)
|
|
48
|
+
iopts[:instance_id] = id
|
|
48
49
|
iopts[:host] = opts[:host]
|
|
49
50
|
iopts[:url] = opts[:url]
|
|
50
51
|
iopts[:redis_url] = opts[:redis_url]
|
|
@@ -58,13 +59,26 @@ module CPEE
|
|
|
58
59
|
iopts[:executionhandlers] = opts[:executionhandlers]
|
|
59
60
|
iopts[:global_executionhandlers] = opts[:global_executionhandlers]
|
|
60
61
|
end
|
|
62
|
+
iopts[:attributes] = attributes
|
|
63
|
+
iopts[:votes] = {}
|
|
64
|
+
CPEE::Persistence::extract_handlers(id,opts).each do |de|
|
|
65
|
+
if de[1] && de[1]&.empty?.!
|
|
66
|
+
CPEE::Persistence::extract_handler(id,opts,de[0]).each do |ele|
|
|
67
|
+
topic, type, name = ele.split('/')
|
|
68
|
+
if type == 'vote'
|
|
69
|
+
iopts[:votes][ele] ||= []
|
|
70
|
+
iopts[:votes][ele] << de[0]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
61
75
|
|
|
62
|
-
File.open(File.join(opts[:instances],id.to_s,File.basename(
|
|
76
|
+
File.open(File.join(opts[:instances],id.to_s,File.basename(self::BACKEND_OPTS)),'w') do |f|
|
|
63
77
|
YAML::dump(iopts,f)
|
|
64
78
|
end
|
|
65
|
-
template = ERB.new(File.read(
|
|
79
|
+
template = ERB.new(File.read(self::BACKEND_TEMPLATE), trim_mode: '-')
|
|
66
80
|
res = template.result_with_hash(dsl: dsl, dataelements: dataelements, endpoints: endpoints, positions: positions)
|
|
67
|
-
File.write(File.join(opts[:instances],id.to_s,
|
|
81
|
+
File.write(File.join(opts[:instances],id.to_s,self::BACKEND_INSTANCE),res)
|
|
68
82
|
if attributes.has_key?('remote')
|
|
69
83
|
uri = URI::parse(attributes['remote'])
|
|
70
84
|
Net::SSH.start(uri.host,uri.user,:keys => [ opts[:ssh_key] ] ) do |ssh|
|
|
@@ -78,12 +92,12 @@ module CPEE
|
|
|
78
92
|
def self::run(id,opts)
|
|
79
93
|
if File.exist? File.join(opts[:instances],id.to_s,'.remote')
|
|
80
94
|
uri = URI::parse(File.read(File.join(opts[:instances],id.to_s,'.remote')))
|
|
81
|
-
exe = File.join(uri.path,id.to_s,File.basename(BACKEND_RUN))
|
|
95
|
+
exe = File.join(uri.path,id.to_s,File.basename(self::BACKEND_RUN))
|
|
82
96
|
Net::SSH.start(uri.host,uri.user,:keys => [ opts[:ssh_key] ] ) do |ssh|
|
|
83
97
|
ssh.exec!("ruby #{exe} >#{exe}.out 2>#{exe}.err &")
|
|
84
98
|
end
|
|
85
99
|
else
|
|
86
|
-
exe = File.join(opts[:instances],id.to_s,File.basename(
|
|
100
|
+
exe = File.join(opts[:instances],id.to_s,File.basename(self::BACKEND_RUN))
|
|
87
101
|
pid = Kernel.spawn(opts[:libs_preloaderrun] + ' ' + exe , :pgroup => true, :in => '/dev/null', :out => exe + '.out', :err => exe + '.err')
|
|
88
102
|
Process.detach pid
|
|
89
103
|
File.write(exe + '.pid',pid)
|
|
@@ -93,7 +107,7 @@ module CPEE
|
|
|
93
107
|
def self::stop(id,opts) ### return: bool to tell if manually changing redis is necessary
|
|
94
108
|
if File.exist? File.join(opts[:instances],id.to_s,'.remote')
|
|
95
109
|
uri = URI::parse(File.read(File.join(opts[:instances],id.to_s,'.remote')))
|
|
96
|
-
exe = File.join(uri.path,id.to_s,File.basename(BACKEND_RUN))
|
|
110
|
+
exe = File.join(uri.path,id.to_s,File.basename(self::BACKEND_RUN))
|
|
97
111
|
Net::SSH.start(uri.host,uri.user,:keys => [ opts[:ssh_key] ] ) do |ssh|
|
|
98
112
|
pid = ssh.exec!("cat #{exe}.pid 2>/dev/null")
|
|
99
113
|
if pid != '' && ssh.exec!("kill -0 #{pid} >/dev/null 2>&1; echo $?").strip == '0'
|
|
@@ -105,7 +119,7 @@ module CPEE
|
|
|
105
119
|
end
|
|
106
120
|
end
|
|
107
121
|
else
|
|
108
|
-
exe = File.join(opts[:instances],id.to_s,File.basename(
|
|
122
|
+
exe = File.join(opts[:instances],id.to_s,File.basename(self::BACKEND_RUN))
|
|
109
123
|
pid = File.read(exe + '.pid') rescue nil
|
|
110
124
|
if pid && (Process.kill(0, pid.to_i) rescue false)
|
|
111
125
|
Process.kill('HUP', pid.to_i) rescue nil
|
|
@@ -116,7 +130,7 @@ module CPEE
|
|
|
116
130
|
end
|
|
117
131
|
end
|
|
118
132
|
end
|
|
119
|
-
|
|
133
|
+
}
|
|
120
134
|
|
|
121
135
|
end
|
|
122
136
|
|
data/server/routing/end.pid
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1283631
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1283649
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1283643
|
data/server/routing/persist.pid
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1283637
|
data/server/routing/persist.rb
CHANGED
|
@@ -88,10 +88,18 @@ Daemonite.new do |opts|
|
|
|
88
88
|
end
|
|
89
89
|
when /event:\d+:dataelements\/change/, /event:\d+:endpoints\/change/, /event:\d+:attributes\/change/
|
|
90
90
|
topic = mess.dig('topic')
|
|
91
|
+
max = opts[:redis].zrange("instance:#{instance}/#{topic}", -1, -1, :withscores => true)&.dig(0,1).to_i
|
|
92
|
+
if (eles = mess.dig('content','sort'))&.any?
|
|
93
|
+
opts[:redis].multi do |multi|
|
|
94
|
+
eles.each_with_index do |e,i|
|
|
95
|
+
multi.zadd("instance:#{instance}/#{topic}",i,e,xx: true)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
91
99
|
opts[:redis].multi do |multi|
|
|
92
100
|
mess.dig('content','changed')&.each_with_index do |c,i|
|
|
93
101
|
unless what =~ /event:\d+:attributes\/change/ && c == 'uuid'
|
|
94
|
-
multi.zadd("instance:#{instance}/#{topic}",i,c)
|
|
102
|
+
multi.zadd("instance:#{instance}/#{topic}",max + 1 + i,c,nx: true)
|
|
95
103
|
if what =~ /event:\d+:dataelements\/change/
|
|
96
104
|
multi.set("instance:#{instance}/#{topic}/#{c}",CPEE::ValueHelper::generate(mess.dig('content','values',c)))
|
|
97
105
|
else
|
metadata
CHANGED
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
# This file is part of CPEE.
|
|
2
|
-
#
|
|
3
|
-
# CPEE is free software: you can redistribute it and/or modify it under the terms
|
|
4
|
-
# of the GNU General Public License as published by the Free Software Foundation,
|
|
5
|
-
# either version 3 of the License, or (at your option) any later version.
|
|
6
|
-
#
|
|
7
|
-
# CPEE is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
8
|
-
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
9
|
-
# PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
10
|
-
#
|
|
11
|
-
# You should have received a copy of the GNU General Public License along with
|
|
12
|
-
# CPEE (file COPYING in the main directory). If not, see
|
|
13
|
-
# <http://www.gnu.org/licenses/>.
|
|
14
|
-
|
|
15
|
-
require 'weel'
|
|
16
|
-
require 'json'
|
|
17
|
-
require 'redis'
|
|
18
|
-
require 'securerandom'
|
|
19
|
-
require 'riddl/client'
|
|
20
|
-
require 'cpee/value_helper'
|
|
21
|
-
require 'cpee/attributes_helper'
|
|
22
|
-
require 'cpee/message'
|
|
23
|
-
require 'cpee/redis'
|
|
24
|
-
require 'cpee/persistence'
|
|
25
|
-
require 'get_process_mem'
|
|
26
|
-
|
|
27
|
-
require 'ostruct'
|
|
28
|
-
class ParaStruct < OpenStruct
|
|
29
|
-
def to_json(*a)
|
|
30
|
-
table.to_json
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
def ⭐(a); ParaStruct.new(a); end
|
|
34
|
-
|
|
35
|
-
class Controller
|
|
36
|
-
def initialize(id,dir,opts)
|
|
37
|
-
CPEE::redis_connect(opts,"Instance #{id}")
|
|
38
|
-
CPEE::Message::set_workers(opts[:workers])
|
|
39
|
-
|
|
40
|
-
@redis = opts[:redis]
|
|
41
|
-
@votes = []
|
|
42
|
-
|
|
43
|
-
@id = id
|
|
44
|
-
|
|
45
|
-
@attributes = {}
|
|
46
|
-
CPEE::Persistence::extract_list(id,opts,'attributes').each do |de|
|
|
47
|
-
@attributes[de[0]] = de[1]
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
@attributes_helper = AttributesHelper.new
|
|
51
|
-
@thread = nil
|
|
52
|
-
@opts = opts
|
|
53
|
-
@instance = nil
|
|
54
|
-
@loop_guard = {}
|
|
55
|
-
|
|
56
|
-
@callback_keys = {}
|
|
57
|
-
|
|
58
|
-
@subs = Thread.new do
|
|
59
|
-
@psredis = @opts[:redis_dyn].call "Instance #{@id} Callback Response"
|
|
60
|
-
@psredis.psubscribe('callback-response:*','callback-end:*') do |on|
|
|
61
|
-
on.pmessage do |pat, what, message|
|
|
62
|
-
if pat == 'callback-response:*'
|
|
63
|
-
_, worker, identifier = what.split(':')
|
|
64
|
-
if @callback_keys.has_key?(identifier)
|
|
65
|
-
index = message.index(' ')
|
|
66
|
-
mess = message[index+1..-1]
|
|
67
|
-
instance, uuid = message[0...index].split(',')
|
|
68
|
-
m = JSON.parse(mess)
|
|
69
|
-
resp = []
|
|
70
|
-
m['content']['values'].each do |e|
|
|
71
|
-
if e[1][0] == 'simple'
|
|
72
|
-
resp << Riddl::Parameter::Simple.new(e[0],e[1][1])
|
|
73
|
-
elsif e[1][0] == 'complex'
|
|
74
|
-
resp << Riddl::Parameter::Complex.new(e[0],e[1][1],e[1][2])
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
@callback_keys[identifier].send(:callback,resp,m['content']['headers'])
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
if pat == 'callback-end:*'
|
|
81
|
-
_, worker, identifier = what.split(':')
|
|
82
|
-
@callback_keys.delete(identifier)
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
@psredis.close
|
|
87
|
-
rescue => e
|
|
88
|
-
sleep 1
|
|
89
|
-
retry
|
|
90
|
-
end
|
|
91
|
-
Thread.new do
|
|
92
|
-
while true
|
|
93
|
-
notify("status/resource_utilization", :mib => GetProcessMem.new.mb, **Process.times.to_h)
|
|
94
|
-
sleep 3
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
attr_reader :id
|
|
100
|
-
attr_reader :attributes
|
|
101
|
-
attr_reader :loop_guard
|
|
102
|
-
|
|
103
|
-
def attributes_translated
|
|
104
|
-
@attributes_translated || @attributes_translated = @attributes_helper.translate(attributes,dataelements,endpoints)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def uuid
|
|
108
|
-
@attributes['uuid']
|
|
109
|
-
end
|
|
110
|
-
def host
|
|
111
|
-
@opts[:host]
|
|
112
|
-
end
|
|
113
|
-
def base_url
|
|
114
|
-
File.join(@opts[:url],'/')
|
|
115
|
-
end
|
|
116
|
-
def instance_url
|
|
117
|
-
File.join(@opts[:url].to_s,@id.to_s,'/')
|
|
118
|
-
end
|
|
119
|
-
def instance_id
|
|
120
|
-
@id
|
|
121
|
-
end
|
|
122
|
-
def base
|
|
123
|
-
base_url
|
|
124
|
-
end
|
|
125
|
-
def instance=(inst)
|
|
126
|
-
@instance = inst
|
|
127
|
-
end
|
|
128
|
-
def endpoints
|
|
129
|
-
@instance.endpoints
|
|
130
|
-
end
|
|
131
|
-
def dataelements
|
|
132
|
-
@instance.data
|
|
133
|
-
end
|
|
134
|
-
def url_result_transformation
|
|
135
|
-
@opts[:url_result_transformation]
|
|
136
|
-
end
|
|
137
|
-
def url_code
|
|
138
|
-
@opts[:url_code]
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def start
|
|
142
|
-
if vote("state/change", :state => 'running')
|
|
143
|
-
@thread = @instance.start
|
|
144
|
-
@thread.join
|
|
145
|
-
else
|
|
146
|
-
@thread = @instance.stop
|
|
147
|
-
@thread.join
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
def sim
|
|
152
|
-
if vote("state/change", :state => 'simulating')
|
|
153
|
-
@thread = @instance.sim
|
|
154
|
-
@thread.join
|
|
155
|
-
else
|
|
156
|
-
@thread = @instance.stop
|
|
157
|
-
@thread.join
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def stop
|
|
162
|
-
### tell the instance to stop
|
|
163
|
-
@instance.stop
|
|
164
|
-
### end all votes or it will not work
|
|
165
|
-
Thread.new do # doing stuff in trap context is a nono. but in a thread its fine :-)
|
|
166
|
-
@votes.each do |key|
|
|
167
|
-
CPEE::Message::send(:'vote-response',key,base,@id,uuid,info,true,@redis)
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def info
|
|
173
|
-
@attributes['info']
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
def notify(what,content={})
|
|
177
|
-
content[:attributes] = attributes_translated
|
|
178
|
-
CPEE::Message::send(:event,what,base,@id,uuid,info,content,@redis)
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
def vote(what,content={})
|
|
182
|
-
topic, name = what.split('/')
|
|
183
|
-
handler = File.join(topic,'vote',name)
|
|
184
|
-
votes = []
|
|
185
|
-
|
|
186
|
-
CPEE::Persistence::extract_handler(id,@opts,handler).each do |client|
|
|
187
|
-
voteid = SecureRandom.hex(16)
|
|
188
|
-
content[:key] = voteid
|
|
189
|
-
content[:attributes] = attributes_translated
|
|
190
|
-
content[:subscription] = client
|
|
191
|
-
votes << voteid
|
|
192
|
-
CPEE::Message::send(:vote,what,base,@id,uuid,info,content,@redis)
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
if votes.length > 0
|
|
196
|
-
@votes += votes
|
|
197
|
-
psredis = @opts[:redis_dyn].call "Instance #{@id} Vote"
|
|
198
|
-
collect = []
|
|
199
|
-
psredis.subscribe(votes.map{|e| ['vote-response:00:' + e.to_s] }.flatten) do |on|
|
|
200
|
-
on.message do |what, message|
|
|
201
|
-
index = message.index(' ')
|
|
202
|
-
mess = message[index+1..-1]
|
|
203
|
-
m = JSON.parse(mess)
|
|
204
|
-
collect << ((m['content'] == true || m['content'] == 'true') || false)
|
|
205
|
-
@votes.delete m['name']
|
|
206
|
-
cancel_callback m['name']
|
|
207
|
-
if collect.length >= votes.length
|
|
208
|
-
psredis.unsubscribe
|
|
209
|
-
end
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
!collect.include?(false)
|
|
213
|
-
else
|
|
214
|
-
true
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
def callback(hw,key,content)
|
|
219
|
-
CPEE::Message::send(:callback,'activity/content',base,@id,uuid,info,content.merge(:key => key),@redis)
|
|
220
|
-
@callback_keys[key] = hw
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
def cancel_callback(key)
|
|
224
|
-
CPEE::Message::send(:'callback-end',key,base,@id,uuid,info,{},@redis)
|
|
225
|
-
end
|
|
226
|
-
end
|