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
@@ -45,11 +45,17 @@ module Orchestrator
|
|
45
45
|
|
46
46
|
|
47
47
|
class RequestProxy
|
48
|
-
def initialize(thread, mod)
|
48
|
+
def initialize(thread, mod, user = nil)
|
49
49
|
@mod = mod
|
50
50
|
@thread = thread
|
51
|
+
@user = user
|
52
|
+
@trace = []
|
51
53
|
end
|
52
54
|
|
55
|
+
|
56
|
+
attr_reader :trace
|
57
|
+
|
58
|
+
|
53
59
|
# Simplify access to status variables as they are thread safe
|
54
60
|
def [](name)
|
55
61
|
@mod.instance[name]
|
@@ -77,6 +83,11 @@ module Orchestrator
|
|
77
83
|
end
|
78
84
|
end
|
79
85
|
|
86
|
+
# Looks up the arity of a method
|
87
|
+
def arity(method)
|
88
|
+
@mod.instance.method(method.to_sym).arity
|
89
|
+
end
|
90
|
+
|
80
91
|
# All other method calls are wrapped in a promise
|
81
92
|
def method_missing(name, *args, &block)
|
82
93
|
defer = @thread.defer
|
@@ -90,14 +101,25 @@ module Orchestrator
|
|
90
101
|
defer.reject(err)
|
91
102
|
@mod.logger.warn(err.message)
|
92
103
|
else
|
104
|
+
@trace = caller
|
105
|
+
|
93
106
|
@mod.thread.schedule do
|
107
|
+
# Keep track of previous in case of recursion
|
108
|
+
previous = nil
|
94
109
|
begin
|
110
|
+
if @user
|
111
|
+
previous = @mod.current_user
|
112
|
+
@mod.current_user = @user
|
113
|
+
end
|
114
|
+
|
95
115
|
defer.resolve(
|
96
116
|
@mod.instance.public_send(name, *args, &block)
|
97
117
|
)
|
98
118
|
rescue => e
|
99
|
-
@mod.logger.print_error(e)
|
119
|
+
@mod.logger.print_error(e, '', @trace)
|
100
120
|
defer.reject(e)
|
121
|
+
ensure
|
122
|
+
@mod.current_user = previous if @user
|
101
123
|
end
|
102
124
|
end
|
103
125
|
end
|
@@ -1,22 +1,65 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
1
3
|
module Orchestrator
|
2
4
|
module Core
|
3
5
|
class RequestsProxy
|
4
|
-
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
|
9
|
+
def initialize(thread, modules, user = nil)
|
5
10
|
if modules.nil?
|
6
11
|
@modules = []
|
7
12
|
else
|
8
13
|
@modules = modules.is_a?(Array) ? modules : [modules]
|
9
14
|
end
|
10
15
|
@thread = thread
|
16
|
+
@user = user
|
17
|
+
@trace = []
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
attr_reader :trace
|
22
|
+
|
23
|
+
|
24
|
+
# Provide Enumerable support
|
25
|
+
def each
|
26
|
+
return enum_for(:each) unless block_given?
|
27
|
+
|
28
|
+
@modules.each do |mod|
|
29
|
+
yield RequestProxy.new(@thread, mod, @user)
|
30
|
+
end
|
11
31
|
end
|
12
32
|
|
33
|
+
# Provide some helper methods
|
34
|
+
def_delegators :@modules, :count, :length, :empty?, :each_index
|
35
|
+
|
36
|
+
def last
|
37
|
+
mod = @modules.last
|
38
|
+
return nil unless mod
|
39
|
+
return RequestProxy.new(@thread, mod, @user)
|
40
|
+
end
|
41
|
+
|
42
|
+
def first
|
43
|
+
mod = @modules.first
|
44
|
+
return nil unless mod
|
45
|
+
return RequestProxy.new(@thread, mod, @user)
|
46
|
+
end
|
47
|
+
|
48
|
+
def [](index)
|
49
|
+
mod = @modules[index]
|
50
|
+
return nil unless mod
|
51
|
+
return RequestProxy.new(@thread, mod, @user)
|
52
|
+
end
|
53
|
+
alias_method :at, :[]
|
54
|
+
|
13
55
|
# Returns true if there is no object to proxy
|
56
|
+
# Allows RequestProxy and RequestsProxy to be used interchangably
|
14
57
|
#
|
15
58
|
# @return [true|false]
|
16
59
|
def nil?
|
17
60
|
@modules.empty?
|
18
61
|
end
|
19
|
-
|
62
|
+
|
20
63
|
|
21
64
|
def method_missing(name, *args, &block)
|
22
65
|
if ::Orchestrator::Core::PROTECTED[name]
|
@@ -24,16 +67,27 @@ module Orchestrator
|
|
24
67
|
::Libuv::Q.reject(@thread, err)
|
25
68
|
# TODO:: log warning err.message
|
26
69
|
else
|
70
|
+
@trace = caller
|
71
|
+
|
27
72
|
promises = @modules.map do |mod|
|
28
73
|
defer = mod.thread.defer
|
29
74
|
mod.thread.schedule do
|
75
|
+
# Keep track of previous in case of recursion
|
76
|
+
previous = nil
|
30
77
|
begin
|
78
|
+
if @user
|
79
|
+
previous = mod.current_user
|
80
|
+
mod.current_user = @user
|
81
|
+
end
|
82
|
+
|
31
83
|
defer.resolve(
|
32
84
|
mod.instance.public_send(name, *args, &block)
|
33
85
|
)
|
34
86
|
rescue => e
|
35
|
-
mod.logger.print_error(e)
|
87
|
+
mod.logger.print_error(e, '', @trace)
|
36
88
|
defer.reject(e)
|
89
|
+
ensure
|
90
|
+
mod.current_user = previous if @user
|
37
91
|
end
|
38
92
|
end
|
39
93
|
defer.promise
|
@@ -4,10 +4,11 @@ require 'set'
|
|
4
4
|
module Orchestrator
|
5
5
|
module Core
|
6
6
|
class SystemProxy
|
7
|
-
def initialize(thread, sys_id, origin = nil)
|
7
|
+
def initialize(thread, sys_id, origin = nil, user = nil)
|
8
8
|
@system = sys_id.to_sym
|
9
9
|
@thread = thread
|
10
10
|
@origin = origin # This is the module that requested the proxy
|
11
|
+
@user = user
|
11
12
|
end
|
12
13
|
|
13
14
|
# Alias for get
|
@@ -24,7 +25,7 @@ module Orchestrator
|
|
24
25
|
index -= 1 # Get the real index
|
25
26
|
name = mod.to_sym
|
26
27
|
|
27
|
-
RequestProxy.new(@thread, system.get(name, index))
|
28
|
+
RequestProxy.new(@thread, system.get(name, index), @user)
|
28
29
|
end
|
29
30
|
|
30
31
|
# Checks for the existence of a particular module
|
@@ -44,8 +45,7 @@ module Orchestrator
|
|
44
45
|
# @param module [String, Symbol] the name of the module in the system
|
45
46
|
# @return [::Orchestrator::Core::RequestsProxy] proxies requests to multiple modules
|
46
47
|
def all(mod)
|
47
|
-
|
48
|
-
RequestsProxy.new(@thread, system.all(name))
|
48
|
+
RequestsProxy.new(@thread, system.all(mod.to_sym), @user)
|
49
49
|
end
|
50
50
|
|
51
51
|
# Iterates over the modules in the system. Can also specify module types.
|
@@ -67,8 +67,7 @@ module Orchestrator
|
|
67
67
|
# @param module [String, Symbol] the name of the module in the system
|
68
68
|
# @return [Integer] the number of modules with a shared name
|
69
69
|
def count(mod)
|
70
|
-
|
71
|
-
system.count(name)
|
70
|
+
system.count(mod.to_sym)
|
72
71
|
end
|
73
72
|
|
74
73
|
# Returns a list of all the module names in the system
|
@@ -85,6 +84,13 @@ module Orchestrator
|
|
85
84
|
system.config.name
|
86
85
|
end
|
87
86
|
|
87
|
+
# Returns the system id as defined in the database
|
88
|
+
#
|
89
|
+
# @return [Symbol] the id of the system
|
90
|
+
def id
|
91
|
+
@system
|
92
|
+
end
|
93
|
+
|
88
94
|
# Used to be notified when an update to a status value occurs
|
89
95
|
#
|
90
96
|
# @param module [String, Symbol] the name of the module in the system
|
@@ -34,6 +34,7 @@ module Orchestrator
|
|
34
34
|
# Other options include:
|
35
35
|
# * emit callback to occur once command complete (may be discarded if a named command)
|
36
36
|
# * on_receive (alternative to received function)
|
37
|
+
# * clear_queue (clear further commands once this has run)
|
37
38
|
}
|
38
39
|
|
39
40
|
CONFIG_DEFAULTS = {
|
@@ -425,6 +426,12 @@ module Orchestrator
|
|
425
426
|
command[:defer].resolve(:no_wait)
|
426
427
|
call_emit command # the command has been sent
|
427
428
|
end
|
429
|
+
|
430
|
+
# Useful for emergency stops etc
|
431
|
+
if command[:clear_queue]
|
432
|
+
@queue.cancel_all("Command #{command[:name]} cleared the queue")
|
433
|
+
end
|
434
|
+
|
428
435
|
nil # ensure promise chain is not propagated
|
429
436
|
end
|
430
437
|
|
data/lib/orchestrator/engine.rb
CHANGED
@@ -36,6 +36,7 @@ module Orchestrator
|
|
36
36
|
# Discover the possible module location paths after initialization is complete
|
37
37
|
#
|
38
38
|
config.after_initialize do |app|
|
39
|
+
require File.expand_path(File.join(File.expand_path("../", __FILE__), '../../app/models/user'))
|
39
40
|
|
40
41
|
ActiveSupport::Dependencies.autoload_paths.each do |path|
|
41
42
|
Pathname.new(path).ascend do |v|
|
data/lib/orchestrator/logger.rb
CHANGED
@@ -87,9 +87,10 @@ module Orchestrator
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
-
def print_error(e, msg = '')
|
90
|
+
def print_error(e, msg = '', trace = nil)
|
91
91
|
msg << "\n#{e.message}"
|
92
92
|
msg << "\n#{e.backtrace.join("\n")}" if e.respond_to?(:backtrace) && e.backtrace
|
93
|
+
msg << "\nCaller backtrace:\n#{trace.join("\n")}" if trace
|
93
94
|
error(msg)
|
94
95
|
end
|
95
96
|
|
@@ -10,8 +10,8 @@ module Orchestrator
|
|
10
10
|
end
|
11
11
|
|
12
12
|
# Access to other modules in the same control system
|
13
|
-
def system
|
14
|
-
|
13
|
+
def system(user = nil)
|
14
|
+
::Orchestrator::Core::SystemProxy.new(@thread, @settings.control_system_id, nil, user)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
|
4
|
+
module Orchestrator
|
5
|
+
|
6
|
+
class Edge
|
7
|
+
def initialize(edge_ip, thread)
|
8
|
+
@thread = thread
|
9
|
+
@ip = edge_ip
|
10
|
+
|
11
|
+
reconnect
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
attr_reader :thread
|
16
|
+
|
17
|
+
|
18
|
+
def exec()
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
|
26
|
+
def reconnect
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
|
5
|
+
module Orchestrator
|
6
|
+
|
7
|
+
class Master
|
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
|
+
@requests = {} # req_id => defer
|
18
|
+
@req_map = {} # connection => ::Set.new (req_id)
|
19
|
+
|
20
|
+
@signal_bind = @thread.async method(:bind_actual)
|
21
|
+
@signal_unbind = @thread.async method(:unbind_actual)
|
22
|
+
|
23
|
+
@request_id = 0
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
attr_reader :thread
|
28
|
+
|
29
|
+
|
30
|
+
# ping
|
31
|
+
# pong
|
32
|
+
# exec
|
33
|
+
# bind
|
34
|
+
# unbind
|
35
|
+
# notify
|
36
|
+
# status
|
37
|
+
# success
|
38
|
+
# failure
|
39
|
+
|
40
|
+
|
41
|
+
def request(edge_id, details)
|
42
|
+
defer = @thread.defer
|
43
|
+
|
44
|
+
# Lookup node
|
45
|
+
connection = online? id
|
46
|
+
if connection
|
47
|
+
@thread.schedule do
|
48
|
+
if connection.connected
|
49
|
+
@request_id += 1
|
50
|
+
@requests[@request_id] = defer
|
51
|
+
@req_map[connection] ||= ::Set.new
|
52
|
+
@req_map[connection] << @request_id
|
53
|
+
|
54
|
+
# Send the request
|
55
|
+
connection.write(::JSON.fast_generate({
|
56
|
+
id: @request_id,
|
57
|
+
|
58
|
+
})).catch do |reason|
|
59
|
+
on_failure(defer, edge_id, details)
|
60
|
+
end
|
61
|
+
else
|
62
|
+
on_failure(defer, edge_id, details)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
else
|
66
|
+
on_failure(defer, edge_id, details)
|
67
|
+
end
|
68
|
+
|
69
|
+
defer.promise
|
70
|
+
end
|
71
|
+
|
72
|
+
def online?(id)
|
73
|
+
edge = @edge_nodes[id]
|
74
|
+
edge && edge.connected ? edge : false
|
75
|
+
end
|
76
|
+
|
77
|
+
def unbind
|
78
|
+
@signal_unbind.call
|
79
|
+
end
|
80
|
+
|
81
|
+
def bind
|
82
|
+
@signal_bind.call
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
|
89
|
+
def on_failure(defer, edge_id, details)
|
90
|
+
# Failed...
|
91
|
+
# Are we loading this device locally or remotely?
|
92
|
+
# Do we wait a small amount of time before trying again?
|
93
|
+
# When should we fail the request?
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
# These are async methods.. They could be called more than once
|
98
|
+
def unbind_actual(*args)
|
99
|
+
return if @shutdown
|
100
|
+
@shutdown = true
|
101
|
+
|
102
|
+
@tcp.close unless @tcp.nil?
|
103
|
+
@tcp = nil
|
104
|
+
end
|
105
|
+
|
106
|
+
def bind_actual(*args)
|
107
|
+
return unless @shutdown
|
108
|
+
@shutdown = false
|
109
|
+
|
110
|
+
# Bind the socket
|
111
|
+
@tcp = @thread.tcp
|
112
|
+
@tcp.bind '0.0.0.0', 17838, @new_connection
|
113
|
+
@tcp.listen 100 # smallish backlog is all we need
|
114
|
+
|
115
|
+
# Delegate errors
|
116
|
+
@tcp.catch @bind_error
|
117
|
+
@tcp
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
# There is a new connection pending. We accept it
|
122
|
+
def new_connection(server)
|
123
|
+
server.accept @accept_connection
|
124
|
+
end
|
125
|
+
|
126
|
+
# Once the connection is accepted we disable Nagles Algorithm
|
127
|
+
# This improves performance as we are using vectored or scatter/gather IO
|
128
|
+
# Then the spider delegates to the gazelle loops
|
129
|
+
def accept_connection(client)
|
130
|
+
client.enable_nodelay
|
131
|
+
# TODO:: auth client and then signal the interested parties
|
132
|
+
end
|
133
|
+
|
134
|
+
# Called when binding is closed due to an error
|
135
|
+
def bind_error(err)
|
136
|
+
return if @shutdown
|
137
|
+
|
138
|
+
# TODO:: log the error
|
139
|
+
|
140
|
+
# Attempt to recover!
|
141
|
+
@thread.scheduler.in(1000) do
|
142
|
+
bind
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def process_request(defer, node, request)
|
147
|
+
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|