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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ef8d250243fa583df69dd09efc6e68d126afa10
|
4
|
+
data.tar.gz: 4e2c7b6e3072bb9ba4568a80bc4382cdae5ac075
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87a92954d832fab00b5668f536cd5a5d578df4a2cb3b7c9f7e6416734ff7888890adeb059a063980b3e67a02f1ea24fc5324dc8c910bfe3aabdf11bed09a0c82
|
7
|
+
data.tar.gz: 5022a425b4574947646acf024c04853a3482d7c8ff6ab6111c7bd0ede5229199cb806d95676ab44e3e0fc6942455591c61d872cb4dcbabdd7efbd2df35715932
|
@@ -3,7 +3,8 @@ module Orchestrator
|
|
3
3
|
module Api
|
4
4
|
class DependenciesController < ApiController
|
5
5
|
respond_to :json
|
6
|
-
before_action :check_admin
|
6
|
+
before_action :check_admin, except: [:index, :show]
|
7
|
+
before_action :check_support, only: [:index, :show]
|
7
8
|
before_action :find_dependency, only: [:show, :update, :destroy, :reload]
|
8
9
|
|
9
10
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
module Orchestrator
|
3
|
+
module Api
|
4
|
+
class LogsController < ApiController
|
5
|
+
respond_to :json
|
6
|
+
before_action :doorkeeper_authorize!
|
7
|
+
before_action :check_admin
|
8
|
+
|
9
|
+
|
10
|
+
# deal with live reload filter
|
11
|
+
@@elastic ||= Elastic.new(::Orchestrator::AccessLog)
|
12
|
+
|
13
|
+
|
14
|
+
def index
|
15
|
+
query = @@elastic.query(params)
|
16
|
+
query.sort = [{
|
17
|
+
created_at: "desc"
|
18
|
+
}]
|
19
|
+
|
20
|
+
# Filter systems via user_id
|
21
|
+
if params.has_key? :user_id
|
22
|
+
user_id = params.permit(:user_id)[:user_id]
|
23
|
+
query.filter({
|
24
|
+
user_id: [user_id]
|
25
|
+
})
|
26
|
+
end
|
27
|
+
|
28
|
+
results = @@elastic.search(query) do |entry|
|
29
|
+
entry.as_json.tap do |json|
|
30
|
+
json[:systems] = ControlSystem.find_by_id(json[:systems]).as_json(only: [:id, :name]) || []
|
31
|
+
end
|
32
|
+
end
|
33
|
+
respond_with results
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -5,7 +5,7 @@ module Orchestrator
|
|
5
5
|
respond_to :json
|
6
6
|
# state, funcs, count and types are available to authenticated users
|
7
7
|
before_action :check_admin, only: [:create, :update, :destroy, :remove, :start, :stop]
|
8
|
-
before_action :check_support, only: [:index, :
|
8
|
+
before_action :check_support, only: [:index, :exec]
|
9
9
|
before_action :find_system, only: [:show, :update, :destroy, :remove, :start, :stop]
|
10
10
|
|
11
11
|
|
@@ -122,8 +122,9 @@ module Orchestrator
|
|
122
122
|
index = para[:index]
|
123
123
|
mod = sys.get(para[:module].to_sym, index.nil? ? 0 : (index.to_i - 1))
|
124
124
|
if mod
|
125
|
+
user = current_user
|
125
126
|
mod.thread.schedule do
|
126
|
-
perform_exec(mod, para)
|
127
|
+
perform_exec(mod, para, user)
|
127
128
|
end
|
128
129
|
throw :async
|
129
130
|
else
|
@@ -251,10 +252,10 @@ module Orchestrator
|
|
251
252
|
end
|
252
253
|
|
253
254
|
# Called on the module thread
|
254
|
-
def perform_exec(mod, para)
|
255
|
+
def perform_exec(mod, para, user)
|
255
256
|
defer = mod.thread.defer
|
256
257
|
|
257
|
-
req = Core::RequestProxy.new(mod.thread, mod)
|
258
|
+
req = Core::RequestProxy.new(mod.thread, mod, user)
|
258
259
|
args = para[:args] || []
|
259
260
|
result = req.send(para[:method].to_sym, *args)
|
260
261
|
|
@@ -268,6 +269,9 @@ module Orchestrator
|
|
268
269
|
defer.resolve(result)
|
269
270
|
end
|
270
271
|
|
272
|
+
respHeaders = {}
|
273
|
+
allow_cors(respHeaders)
|
274
|
+
|
271
275
|
defer.promise.then(proc { |res|
|
272
276
|
output = ''
|
273
277
|
begin
|
@@ -277,16 +281,14 @@ module Orchestrator
|
|
277
281
|
# TODO:: need a better way of dealing with this
|
278
282
|
# ALSO in websocket manager
|
279
283
|
end
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
}, [output]])
|
284
|
+
respHeaders['Content-Length'] = output.bytesize
|
285
|
+
respHeaders['Content-Type'] = 'application/json'
|
286
|
+
env['async.callback'].call([200, respHeaders, [output]])
|
284
287
|
}, proc { |err|
|
285
288
|
output = err.message
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
}, [output]])
|
289
|
+
respHeaders['Content-Length'] = output.bytesize
|
290
|
+
respHeaders['Content-Type'] = 'text/plain'
|
291
|
+
env['async.callback'].call([500, respHeaders, [output]])
|
290
292
|
})
|
291
293
|
end
|
292
294
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
|
2
|
+
module Orchestrator
|
3
|
+
module Api
|
4
|
+
class UsersController < ApiController
|
5
|
+
respond_to :json
|
6
|
+
before_action :check_authorization, only: [:update]
|
7
|
+
before_action :check_admin, only: [:index, :destroy]
|
8
|
+
|
9
|
+
|
10
|
+
before_action :doorkeeper_authorize!
|
11
|
+
|
12
|
+
|
13
|
+
# deal with live reload filter
|
14
|
+
@@elastic ||= Elastic.new(User)
|
15
|
+
|
16
|
+
# Admins can see a little more of the users data
|
17
|
+
ADMIN_DATA = User::PUBLIC_DATA.dup
|
18
|
+
ADMIN_DATA[:only] += [:support, :sys_admin, :email]
|
19
|
+
|
20
|
+
|
21
|
+
def index
|
22
|
+
query = @@elastic.query(params)
|
23
|
+
results = @@elastic.search(query) do |user|
|
24
|
+
user.as_json(ADMIN_DATA)
|
25
|
+
end
|
26
|
+
respond_with results
|
27
|
+
end
|
28
|
+
|
29
|
+
def show
|
30
|
+
user = User.find(id)
|
31
|
+
|
32
|
+
# We only want to provide limited 'public' information
|
33
|
+
respond_with user, User::PUBLIC_DATA
|
34
|
+
end
|
35
|
+
|
36
|
+
def current
|
37
|
+
respond_with current_user
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
##
|
42
|
+
# Requests requiring authorization have already loaded the model
|
43
|
+
def update
|
44
|
+
@user.update_attributes(safe_params)
|
45
|
+
@user.save
|
46
|
+
respond_with @user
|
47
|
+
end
|
48
|
+
|
49
|
+
# TODO:: We should only ever disable users... Need to add this flag
|
50
|
+
#def destroy
|
51
|
+
# respond_with @user.delete
|
52
|
+
#end
|
53
|
+
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
|
58
|
+
def safe_params
|
59
|
+
if current_user.sys_admin
|
60
|
+
params.require(:user).permit(:name, :email, :nickname, :sys_admin, :support)
|
61
|
+
else
|
62
|
+
params.require(:user).permit(:name, :email, :nickname)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def check_authorization
|
67
|
+
# Find will raise a 404 (not found) if there is an error
|
68
|
+
@user = User.find(id)
|
69
|
+
user = current_user
|
70
|
+
|
71
|
+
# Does the current user have permission to perform the current action
|
72
|
+
head(:forbidden) unless @user.id == user.id || user.sys_admin
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -3,7 +3,8 @@ module Orchestrator
|
|
3
3
|
module Api
|
4
4
|
class ZonesController < ApiController
|
5
5
|
respond_to :json
|
6
|
-
before_action :check_admin
|
6
|
+
before_action :check_admin, except: [:index, :show]
|
7
|
+
before_action :check_support, only: [:index, :show]
|
7
8
|
before_action :find_zone, only: [:show, :update, :destroy]
|
8
9
|
|
9
10
|
|
@@ -5,8 +5,8 @@ module Orchestrator
|
|
5
5
|
rescue_from Couchbase::Error::NotFound, with: :entry_not_found
|
6
6
|
|
7
7
|
|
8
|
-
|
9
|
-
before_filter :allow_cors
|
8
|
+
before_action :doorkeeper_authorize!, except: :options
|
9
|
+
before_filter :allow_cors # Add headers to allow for CORS requests to the API
|
10
10
|
|
11
11
|
|
12
12
|
# This is a preflight OPTIONS request
|
@@ -28,11 +28,11 @@ module Orchestrator
|
|
28
28
|
COMMON_HEADERS = 'Origin, Accept, Content-Type, X-Requested-With, Authorization, X-Frame-Options'.freeze
|
29
29
|
ONE_DAY = '1728000'.freeze
|
30
30
|
|
31
|
-
def allow_cors
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
def allow_cors(headerHash = headers)
|
32
|
+
headerHash[ALLOW_ORIGIN] = ANY_ORIGIN
|
33
|
+
headerHash[ALLOW_METHODS] = ANY_METHOD
|
34
|
+
headerHash[ALLOW_HEADERS] = COMMON_HEADERS
|
35
|
+
headerHash[MAX_AGE] = ONE_DAY
|
36
36
|
end
|
37
37
|
|
38
38
|
|
@@ -55,5 +55,22 @@ module Orchestrator
|
|
55
55
|
yield if model.save && block_given?
|
56
56
|
respond_with :api, model
|
57
57
|
end
|
58
|
+
|
59
|
+
# Checking if the user is an administrator
|
60
|
+
def check_admin
|
61
|
+
user = current_user
|
62
|
+
head(:forbidden) unless user && user.sys_admin
|
63
|
+
end
|
64
|
+
|
65
|
+
# Checking if the user is support personnel
|
66
|
+
def check_support
|
67
|
+
user = current_user
|
68
|
+
head(:forbidden) unless user && (user.support || user.sys_admin)
|
69
|
+
end
|
70
|
+
|
71
|
+
# current user using doorkeeper
|
72
|
+
def current_user
|
73
|
+
@current_user ||= User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
|
74
|
+
end
|
58
75
|
end
|
59
76
|
end
|
@@ -16,15 +16,21 @@ module Orchestrator
|
|
16
16
|
attribute :notes
|
17
17
|
|
18
18
|
attribute :created_at
|
19
|
-
attribute :ended_at
|
19
|
+
attribute :ended_at
|
20
|
+
attribute :last_checked_at, default: 0
|
20
21
|
|
21
22
|
|
22
|
-
def initialize
|
23
|
-
super
|
24
|
-
|
23
|
+
def initialize(*args)
|
24
|
+
super(*args)
|
25
|
+
|
26
|
+
if self.created_at.nil?
|
27
|
+
self.created_at = Time.now.to_i
|
28
|
+
end
|
25
29
|
end
|
26
30
|
|
27
31
|
def save
|
32
|
+
self.last_checked_at = Time.now.to_i
|
33
|
+
|
28
34
|
if self.persisted
|
29
35
|
super
|
30
36
|
else
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
module Orchestrator
|
3
|
+
class EdgeControl < Couchbase::Model
|
4
|
+
design_document :edge
|
5
|
+
include ::CouchbaseId::Generator
|
6
|
+
|
7
|
+
|
8
|
+
attribute :name
|
9
|
+
attribute :description
|
10
|
+
attribute :failover
|
11
|
+
attribute :timeout, default: 30
|
12
|
+
attribute :window_start # CRON string
|
13
|
+
attribute :window_length # Time in seconds
|
14
|
+
attribute :settings, default: lambda { {} }
|
15
|
+
attribute :admins, default: lambda { [] }
|
16
|
+
attribute :commit # Current commit
|
17
|
+
|
18
|
+
attribute :created_at, default: lambda { Time.now.to_i }
|
19
|
+
|
20
|
+
|
21
|
+
def online?(id)
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/app/models/user.rb
ADDED
data/config/routes.rb
CHANGED
@@ -33,6 +33,10 @@ Orchestrator::Engine.routes.draw do
|
|
33
33
|
end
|
34
34
|
resources :groups # users define the groups they are in
|
35
35
|
resources :zones # zones define what groups can access them
|
36
|
+
resources :users do
|
37
|
+
get 'current', on: :collection
|
38
|
+
end
|
39
|
+
resources :logs
|
36
40
|
|
37
41
|
concerns :mods
|
38
42
|
end
|
data/lib/orchestrator/control.rb
CHANGED
@@ -30,6 +30,11 @@ module Orchestrator
|
|
30
30
|
@exceptions = method(:log_unhandled_exception)
|
31
31
|
|
32
32
|
@ready = false
|
33
|
+
@ready_defer = @loop.defer
|
34
|
+
@ready_promise = @ready_defer.promise
|
35
|
+
|
36
|
+
# We keep track of unloaded modules so we can optimise loading them again
|
37
|
+
@unloaded = Set.new
|
33
38
|
|
34
39
|
if Rails.env.production?
|
35
40
|
logger = ::Logger.new(::Rails.root.join('log/control.log').to_s, 10, 4194304)
|
@@ -43,7 +48,7 @@ module Orchestrator
|
|
43
48
|
end
|
44
49
|
|
45
50
|
|
46
|
-
attr_reader :logger, :loop, :ready, :zones
|
51
|
+
attr_reader :logger, :loop, :ready, :ready_promise, :zones, :threads
|
47
52
|
|
48
53
|
|
49
54
|
# Start the control reactor
|
@@ -109,6 +114,19 @@ module Orchestrator
|
|
109
114
|
# update the module cache
|
110
115
|
defer.promise.then do |mod_manager|
|
111
116
|
@loaded[mod_id] = mod_manager
|
117
|
+
|
118
|
+
# Transfer any existing observers over to the new thread
|
119
|
+
if @ready && @unloaded.include?(mod_id)
|
120
|
+
@unloaded.delete(mod_id)
|
121
|
+
|
122
|
+
new_thread = thread.observer
|
123
|
+
@threads.each do |thr|
|
124
|
+
thr.observer.move(mod_id, new_thread)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Return the manager
|
129
|
+
mod_manager
|
112
130
|
end
|
113
131
|
defer.promise
|
114
132
|
}, @exceptions)
|
@@ -163,8 +181,10 @@ module Orchestrator
|
|
163
181
|
# Stop the module gracefully
|
164
182
|
# Then remove it from @loaded
|
165
183
|
def unload(mod_id)
|
166
|
-
|
167
|
-
|
184
|
+
mod = mod_id.to_sym
|
185
|
+
stop(mod).then(proc {
|
186
|
+
@unloaded << mod
|
187
|
+
@loaded.delete(mod)
|
168
188
|
true # promise response
|
169
189
|
})
|
170
190
|
end
|
@@ -196,6 +216,7 @@ module Orchestrator
|
|
196
216
|
# Clear the system cache (in case it has been populated at all)
|
197
217
|
System.clear_cache
|
198
218
|
@ready = true
|
219
|
+
@ready_defer.resolve(true)
|
199
220
|
end
|
200
221
|
|
201
222
|
def log_unhandled_exception(*args)
|
@@ -75,8 +75,11 @@ module Orchestrator
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def setting(name)
|
78
|
-
|
79
|
-
|
78
|
+
@__config__.setting(name.to_sym)
|
79
|
+
end
|
80
|
+
|
81
|
+
def thread
|
82
|
+
@__config__.thread
|
80
83
|
end
|
81
84
|
|
82
85
|
# Updates a setting that will effect the local module only
|
@@ -85,8 +88,7 @@ module Orchestrator
|
|
85
88
|
# @param value [String|Symbol|Numeric|Array|Hash] the setting value
|
86
89
|
# @return [::Libuv::Q::Promise] Promise that will resolve once the setting is persisted
|
87
90
|
def define_setting(name, value)
|
88
|
-
|
89
|
-
@__config__.define_setting(set, value)
|
91
|
+
@__config__.define_setting(name.to_sym, value)
|
90
92
|
end
|
91
93
|
|
92
94
|
def wake_device(mac, ip = '<broadcast>')
|
@@ -95,6 +97,10 @@ module Orchestrator
|
|
95
97
|
end
|
96
98
|
end
|
97
99
|
|
100
|
+
def current_user
|
101
|
+
@__config__.current_user
|
102
|
+
end
|
103
|
+
|
98
104
|
# Outputs any statistics collected on the module
|
99
105
|
def __STATS__
|
100
106
|
stats = {}
|
@@ -17,6 +17,7 @@ module Orchestrator
|
|
17
17
|
|
18
18
|
attr_reader :thread, :settings, :instance
|
19
19
|
attr_reader :status, :stattrak, :logger
|
20
|
+
attr_accessor :current_user
|
20
21
|
|
21
22
|
|
22
23
|
# Should always be called on the module thread
|
@@ -83,9 +84,8 @@ module Orchestrator
|
|
83
84
|
# NOTE:: Couchbase does support non-blocking gets although I think this is simpler
|
84
85
|
#
|
85
86
|
# @return [::Orchestrator::Core::SystemProxy]
|
86
|
-
# @raise [Couchbase::Error::NotFound] if unable to find the system in the DB
|
87
87
|
def get_system(name)
|
88
|
-
id = ::Orchestrator::ControlSystem.bucket.get("sysname-#{name}")
|
88
|
+
id = ::Orchestrator::ControlSystem.bucket.get("sysname-#{name.downcase}", {quiet: true}) || name
|
89
89
|
::Orchestrator::Core::SystemProxy.new(@thread, id.to_sym, self)
|
90
90
|
end
|
91
91
|
|
@@ -144,7 +144,7 @@ module Orchestrator
|
|
144
144
|
def setting(name)
|
145
145
|
res = @settings.settings[name]
|
146
146
|
if res.nil?
|
147
|
-
if
|
147
|
+
if @settings.control_system_id
|
148
148
|
sys = System.get(@settings.control_system_id)
|
149
149
|
res = sys.settings[name]
|
150
150
|
|