orchestrator 1.0.2 → 1.0.3
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/app/controllers/orchestrator/api/dependencies_controller.rb +2 -1
- data/app/controllers/orchestrator/api/logs_controller.rb +37 -0
- data/app/controllers/orchestrator/api/systems_controller.rb +14 -12
- data/app/controllers/orchestrator/api/users_controller.rb +76 -0
- data/app/controllers/orchestrator/api/zones_controller.rb +2 -1
- data/app/controllers/orchestrator/api_controller.rb +2 -1
- data/app/controllers/orchestrator/base.rb +24 -7
- data/app/models/orchestrator/access_log.rb +10 -4
- data/app/models/orchestrator/edge_control.rb +25 -0
- data/app/models/user.rb +8 -0
- data/config/routes.rb +4 -0
- data/lib/orchestrator/control.rb +24 -3
- data/lib/orchestrator/core/mixin.rb +10 -4
- data/lib/orchestrator/core/module_manager.rb +3 -3
- data/lib/orchestrator/core/request_proxy.rb +24 -2
- data/lib/orchestrator/core/requests_proxy.rb +57 -3
- data/lib/orchestrator/core/system_proxy.rb +12 -6
- data/lib/orchestrator/device/processor.rb +7 -0
- data/lib/orchestrator/engine.rb +1 -0
- data/lib/orchestrator/logger.rb +2 -1
- data/lib/orchestrator/logic/manager.rb +2 -2
- data/lib/orchestrator/logic/mixin.rb +1 -1
- data/lib/orchestrator/remote/edge.rb +30 -0
- data/lib/orchestrator/remote/master.rb +150 -0
- data/lib/orchestrator/remote/proxy.rb +24 -0
- data/lib/orchestrator/status.rb +39 -4
- data/lib/orchestrator/system.rb +8 -0
- data/lib/orchestrator/utilities/constants.rb +4 -2
- data/lib/orchestrator/utilities/transcoder.rb +6 -2
- data/lib/orchestrator/version.rb +1 -1
- data/lib/orchestrator/websocket_manager.rb +121 -31
- metadata +10 -3
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
|
4
|
+
module Orchestrator
|
5
|
+
class Proxy
|
6
|
+
COMMANDS = Set.new([:exec, :bind, :unbind, :debug, :ignore])
|
7
|
+
|
8
|
+
def initialize(thread)
|
9
|
+
@thread = thread
|
10
|
+
|
11
|
+
@accept_connection = method :accept_connection
|
12
|
+
@new_connection = method :new_connection
|
13
|
+
@bind_error = method :bind_error
|
14
|
+
|
15
|
+
@shutdown = true
|
16
|
+
@edge_nodes = ::ThreadSafe::Cache.new # id => connection
|
17
|
+
@req_map = {} # connection => ::Set.new (defers)
|
18
|
+
@req_map = {}
|
19
|
+
|
20
|
+
@signal_bind = @thread.async method(:bind_actual)
|
21
|
+
@signal_unbind = @thread.async method(:unbind_actual)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/orchestrator/status.rb
CHANGED
@@ -97,12 +97,42 @@ module Orchestrator
|
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
|
-
#
|
101
|
-
|
100
|
+
# Used to maintain subscriptions where module is moved to another thread
|
101
|
+
# or even another server.
|
102
|
+
def move(mod_id, to_thread)
|
103
|
+
return if to_thread == self
|
104
|
+
|
105
|
+
@thread.schedule do
|
106
|
+
subs = @subscriptions.delete(mod_id)
|
107
|
+
if subs
|
108
|
+
# Remove the system references
|
109
|
+
subs.each do |sub|
|
110
|
+
@systems[sub.sys_id].delete(sub) if sub.sys_id
|
111
|
+
end
|
112
|
+
|
113
|
+
# Transfer the subscriptions
|
114
|
+
to_thread.transfer(mod_id, subs)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def transfer(mod_id, subs)
|
120
|
+
@thread.schedule do
|
121
|
+
@subscriptions[mod_id] = subs
|
122
|
+
|
123
|
+
subs.each do |sub|
|
124
|
+
if sub.sys_id
|
125
|
+
@systems[sub.sys_id] ||= Set.new
|
126
|
+
@systems[sub.sys_id] << sub
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# The System class contacts each of the threads to let them know of an update
|
133
|
+
def reloaded_system(sys_id, sys)
|
102
134
|
subscriptions = @systems[sys_id]
|
103
135
|
if subscriptions
|
104
|
-
sys = ::Orchestrator::System.get(@system)
|
105
|
-
|
106
136
|
subscriptions.each do |sub|
|
107
137
|
old_id = sub.mod_id
|
108
138
|
|
@@ -125,6 +155,11 @@ module Orchestrator
|
|
125
155
|
sub.notify(value) unless value.nil?
|
126
156
|
end
|
127
157
|
|
158
|
+
# Transfer the subscription if on a different thread
|
159
|
+
if mod.thread != @thread
|
160
|
+
move(sub.mod_id.to_sym, mod.thread)
|
161
|
+
end
|
162
|
+
|
128
163
|
# Perform any required cleanup
|
129
164
|
if @subscriptions[old_id][sub.status].empty?
|
130
165
|
@subscriptions[old_id].delete(sub.status)
|
data/lib/orchestrator/system.rb
CHANGED
@@ -43,6 +43,14 @@ module Orchestrator
|
|
43
43
|
zone = zones[zone_id]
|
44
44
|
@zones << zone unless zone.nil?
|
45
45
|
end
|
46
|
+
|
47
|
+
# Inform status tracker that that the system has reloaded
|
48
|
+
# There may have been a change in module order etc
|
49
|
+
@controller.threads.each do |thread|
|
50
|
+
thread.next_tick do
|
51
|
+
thread.observer.reloaded_system(@config.id, self)
|
52
|
+
end
|
53
|
+
end
|
46
54
|
end
|
47
55
|
|
48
56
|
def get(mod, index)
|
@@ -15,13 +15,15 @@ module Orchestrator
|
|
15
15
|
:on, :On, 'on', 'On',
|
16
16
|
:yes, :Yes, 'yes', 'Yes',
|
17
17
|
'down', 'Down', :down, :Down,
|
18
|
-
'open', 'Open', :open, :Open
|
18
|
+
'open', 'Open', :open, :Open,
|
19
|
+
'active', 'Active', :active, :Active])
|
19
20
|
Off_vars = Set.new([0, false, 'false', 'False',
|
20
21
|
:off, :Off, 'off', 'Off',
|
21
22
|
:no, :No, 'no', 'No',
|
22
23
|
'up', 'Up', :up, :Up,
|
23
24
|
'close', 'Close', :close, :Close,
|
24
|
-
'short', 'Short', :short, :Short
|
25
|
+
'short', 'Short', :short, :Short,
|
26
|
+
'inactive', 'Inactive', :inactive, :Inactive])
|
25
27
|
|
26
28
|
|
27
29
|
def in_range(num, max, min = 0)
|
@@ -12,9 +12,9 @@ module Orchestrator
|
|
12
12
|
data.prepend('0') if data.length % 2 > 0
|
13
13
|
|
14
14
|
# Breaks string into an array of characters
|
15
|
-
output =
|
15
|
+
output = []
|
16
16
|
data.scan(/.{2}/) { |byte| output << byte.hex}
|
17
|
-
|
17
|
+
output.pack('c*')
|
18
18
|
end
|
19
19
|
|
20
20
|
# Converts a binary string into a hex encoded string
|
@@ -22,6 +22,8 @@ module Orchestrator
|
|
22
22
|
# @param data [String] a binary string
|
23
23
|
# @return [String]
|
24
24
|
def byte_to_hex(data)
|
25
|
+
data = array_to_str(data) if data.is_a? Array
|
26
|
+
|
25
27
|
output = ""
|
26
28
|
data.each_byte { |c|
|
27
29
|
s = c.to_s(16)
|
@@ -36,6 +38,7 @@ module Orchestrator
|
|
36
38
|
# @param data [String] data to be converted to bytes
|
37
39
|
# @return [Array]
|
38
40
|
def str_to_array(data)
|
41
|
+
return data if data.is_a? Array
|
39
42
|
data.bytes.to_a
|
40
43
|
end
|
41
44
|
|
@@ -44,6 +47,7 @@ module Orchestrator
|
|
44
47
|
# @param data [Array] an array of bytes
|
45
48
|
# @return [String]
|
46
49
|
def array_to_str(data)
|
50
|
+
return data if data.is_a? String
|
47
51
|
data.pack('c*')
|
48
52
|
end
|
49
53
|
|
data/lib/orchestrator/version.rb
CHANGED
@@ -83,6 +83,9 @@ module Orchestrator
|
|
83
83
|
if COMMANDS.include?(cmd)
|
84
84
|
@accessed << params[:sys] # Log the access
|
85
85
|
self.__send__(cmd, params) # Execute the request
|
86
|
+
|
87
|
+
# Start logging
|
88
|
+
periodicly_update_logs if @accessTimer.nil?
|
86
89
|
else
|
87
90
|
@access_log.suspected = true
|
88
91
|
@logger.warn("websocket requested unknown command '#{params[:cmd]}'")
|
@@ -95,7 +98,7 @@ module Orchestrator
|
|
95
98
|
end
|
96
99
|
|
97
100
|
# Raise an error if access is not granted
|
98
|
-
result.catch do |
|
101
|
+
result.catch do |e|
|
99
102
|
@access_log.suspected = true
|
100
103
|
@logger.print_error(e, 'security check failed for websocket request')
|
101
104
|
error_response(params[:id], ERRORS[:access_denied], e.message)
|
@@ -111,7 +114,7 @@ module Orchestrator
|
|
111
114
|
|
112
115
|
def check_requirements(params)
|
113
116
|
REQUIRED.each do |key|
|
114
|
-
return false
|
117
|
+
return false unless params.has_key?(key)
|
115
118
|
end
|
116
119
|
true
|
117
120
|
end
|
@@ -138,7 +141,7 @@ module Orchestrator
|
|
138
141
|
if system
|
139
142
|
mod_man = system.get(mod, index - 1)
|
140
143
|
if mod_man
|
141
|
-
req = Core::RequestProxy.new(@loop, mod_man)
|
144
|
+
req = Core::RequestProxy.new(@loop, mod_man, @user)
|
142
145
|
result = req.send(name, *args)
|
143
146
|
result.then(proc { |res|
|
144
147
|
output = nil
|
@@ -310,8 +313,10 @@ module Orchestrator
|
|
310
313
|
def debug(params)
|
311
314
|
id = params[:id]
|
312
315
|
sys = params[:sys]
|
313
|
-
|
314
|
-
|
316
|
+
mod = params[:mod].to_sym
|
317
|
+
index_s = params[:index]
|
318
|
+
index = nil
|
319
|
+
index = index_s.to_i if index_s
|
315
320
|
|
316
321
|
if @debug.nil?
|
317
322
|
@debug = @loop.defer
|
@@ -319,35 +324,82 @@ module Orchestrator
|
|
319
324
|
@debug.promise.progress method(:debug_update)
|
320
325
|
end
|
321
326
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
@
|
335
|
-
@inspecting.add :self
|
327
|
+
if index
|
328
|
+
# Look up the module ID on the thread pool
|
329
|
+
@loop.work(proc {
|
330
|
+
system = ::Orchestrator::System.get(sys)
|
331
|
+
if system
|
332
|
+
mod_man = system.get(mod, index - 1)
|
333
|
+
if mod_man
|
334
|
+
mod_man.settings.id
|
335
|
+
else
|
336
|
+
::Libuv::Q.reject(@loop, 'debug failed: module #{sys}->#{mod}_#{index} not found')
|
337
|
+
end
|
338
|
+
else
|
339
|
+
::Libuv::Q.reject(@loop, 'debug failed: system #{sys} lookup failed')
|
336
340
|
end
|
341
|
+
}).then(proc { |mod_id|
|
342
|
+
do_debug(id, mod_id, sys, mod, index)
|
343
|
+
}).catch do |err|
|
344
|
+
if err.is_a? String
|
345
|
+
@logger.info(err)
|
346
|
+
error_response(id, ERRORS[:module_not_found], err)
|
347
|
+
else
|
348
|
+
@logger.print_error(err, "debug request failed: #{params}")
|
349
|
+
error_response(id, ERRORS[:module_not_found], "debug request failed for: #{sys}->#{mod}_#{index}")
|
350
|
+
end
|
351
|
+
end
|
352
|
+
else
|
353
|
+
do_debug(id, mod)
|
354
|
+
end
|
355
|
+
end
|
337
356
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
357
|
+
def do_debug(id, mod, sys_id = nil, mod_name = nil, mod_index = nil)
|
358
|
+
resp = {
|
359
|
+
id: id,
|
360
|
+
type: :success,
|
361
|
+
mod_id: mod
|
362
|
+
}
|
363
|
+
|
364
|
+
if mod_name
|
365
|
+
# Provide meta information for convenience
|
366
|
+
# Actual debug messages do not contain this info
|
367
|
+
# The library must use the mod_id returned in the response to route responses as desired
|
368
|
+
resp[:meta] = {
|
369
|
+
sys: sys_id,
|
370
|
+
mod: mod_name,
|
371
|
+
index: mod_index
|
372
|
+
}
|
373
|
+
end
|
374
|
+
|
375
|
+
# Set mod to get module level errors
|
376
|
+
begin
|
377
|
+
if @inspecting.include?(mod)
|
378
|
+
@ws.text(::JSON.generate(resp))
|
342
379
|
else
|
343
|
-
|
344
|
-
|
380
|
+
mod_man = ::Orchestrator::Control.instance.loaded?(mod)
|
381
|
+
if mod_man
|
382
|
+
log = mod_man.logger
|
383
|
+
log.add @debug
|
384
|
+
log.level = :debug
|
385
|
+
@inspecting.add mod
|
386
|
+
|
387
|
+
# Set sys to get errors occurring outside of the modules
|
388
|
+
if !@inspecting.include?(:self)
|
389
|
+
@logger.add @debug
|
390
|
+
@logger.level = :debug
|
391
|
+
@inspecting.add :self
|
392
|
+
end
|
393
|
+
|
394
|
+
@ws.text(::JSON.generate(resp))
|
395
|
+
else
|
396
|
+
@logger.info("websocket debug could not find module: #{mod}")
|
397
|
+
error_response(id, ERRORS[:module_not_found], "could not find module: #{mod}")
|
398
|
+
end
|
345
399
|
end
|
346
|
-
|
347
|
-
@
|
348
|
-
|
349
|
-
type: :success
|
350
|
-
}))
|
400
|
+
rescue => e
|
401
|
+
@logger.print_error(e, "websocket debug request failed")
|
402
|
+
error_response(id, ERRORS[:request_failed], e.message)
|
351
403
|
end
|
352
404
|
end
|
353
405
|
|
@@ -418,8 +470,46 @@ module Orchestrator
|
|
418
470
|
@bindings = nil
|
419
471
|
@debug.resolve(true) if @debug # detach debug listeners
|
420
472
|
|
473
|
+
@accessTimer.cancel
|
474
|
+
@loop.work(proc {
|
475
|
+
@accesslock.synchronize {
|
476
|
+
@access_log.systems = @accessed.to_a
|
477
|
+
@access_log.ended_at = Time.now.to_i
|
478
|
+
@access_log.save
|
479
|
+
}
|
480
|
+
})
|
481
|
+
end
|
482
|
+
|
483
|
+
|
484
|
+
protected
|
485
|
+
|
486
|
+
|
487
|
+
def update_accessed(*args)
|
488
|
+
if @accesslock.try_lock # No blocking!
|
489
|
+
begin
|
490
|
+
@access_log.systems = @accessed.to_a
|
491
|
+
|
492
|
+
@loop.work(proc {
|
493
|
+
@access_log.save
|
494
|
+
}).finally do
|
495
|
+
@accesslock.unlock
|
496
|
+
end
|
497
|
+
rescue => e
|
498
|
+
@accesslock.unlock if @accesslock.locked?
|
499
|
+
@logger.print_error(e, "unknown error writing access log")
|
500
|
+
end
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
def periodicly_update_logs
|
505
|
+
@accessTimer = @loop.scheduler.every(60000 + Random.rand(1000), method(:update_accessed))
|
506
|
+
@accesslock = Mutex.new
|
421
507
|
@access_log.systems = @accessed.to_a
|
422
|
-
@
|
508
|
+
@loop.work(proc {
|
509
|
+
@accesslock.synchronize {
|
510
|
+
@access_log.save
|
511
|
+
}
|
512
|
+
})
|
423
513
|
end
|
424
514
|
end
|
425
515
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: orchestrator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen von Takach
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -190,8 +190,10 @@ files:
|
|
190
190
|
- README.md
|
191
191
|
- Rakefile
|
192
192
|
- app/controllers/orchestrator/api/dependencies_controller.rb
|
193
|
+
- app/controllers/orchestrator/api/logs_controller.rb
|
193
194
|
- app/controllers/orchestrator/api/modules_controller.rb
|
194
195
|
- app/controllers/orchestrator/api/systems_controller.rb
|
196
|
+
- app/controllers/orchestrator/api/users_controller.rb
|
195
197
|
- app/controllers/orchestrator/api/zones_controller.rb
|
196
198
|
- app/controllers/orchestrator/api_controller.rb
|
197
199
|
- app/controllers/orchestrator/base.rb
|
@@ -199,6 +201,7 @@ files:
|
|
199
201
|
- app/models/orchestrator/access_log.rb
|
200
202
|
- app/models/orchestrator/control_system.rb
|
201
203
|
- app/models/orchestrator/dependency.rb
|
204
|
+
- app/models/orchestrator/edge_control.rb
|
202
205
|
- app/models/orchestrator/mod/by_dependency/map.js
|
203
206
|
- app/models/orchestrator/mod/by_module_type/map.js
|
204
207
|
- app/models/orchestrator/module.rb
|
@@ -206,6 +209,7 @@ files:
|
|
206
209
|
- app/models/orchestrator/sys/by_zones/map.js
|
207
210
|
- app/models/orchestrator/zone.rb
|
208
211
|
- app/models/orchestrator/zone/all/map.js
|
212
|
+
- app/models/user.rb
|
209
213
|
- config/routes.rb
|
210
214
|
- lib/generators/module/USAGE
|
211
215
|
- lib/generators/module/module_generator.rb
|
@@ -231,6 +235,9 @@ files:
|
|
231
235
|
- lib/orchestrator/logger.rb
|
232
236
|
- lib/orchestrator/logic/manager.rb
|
233
237
|
- lib/orchestrator/logic/mixin.rb
|
238
|
+
- lib/orchestrator/remote/edge.rb
|
239
|
+
- lib/orchestrator/remote/master.rb
|
240
|
+
- lib/orchestrator/remote/proxy.rb
|
234
241
|
- lib/orchestrator/service/manager.rb
|
235
242
|
- lib/orchestrator/service/mixin.rb
|
236
243
|
- lib/orchestrator/service/transport_http.rb
|
@@ -262,7 +269,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
262
269
|
version: '0'
|
263
270
|
requirements: []
|
264
271
|
rubyforge_project:
|
265
|
-
rubygems_version: 2.
|
272
|
+
rubygems_version: 2.4.5
|
266
273
|
signing_key:
|
267
274
|
specification_version: 4
|
268
275
|
summary: A distributed system for building automation
|