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
@@ -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
|