orchestrator 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|