Skip to content

Commit 6e19cd8

Browse files
authored
Merge branch 'master' into dependabot/bundler/puma-6.3.1
2 parents 0208f2f + dd6fb56 commit 6e19cd8

19 files changed

+726
-67
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ To help users who are behind restrictive firewalls to send/receive media (audio,
7171

7272
Again, [bbb-install.sh](https://github.com/bigbluebutton/bbb-install#install-a-turn-server) can automate this process for you.
7373

74+
If you want Scalelite to infer and display the BBB version of your servers, you need to add the following line to `/etc/bigbluebutton/bbb-web.properties` on your BBB servers:
75+
```
76+
allowRevealOfBBBVersion=true
77+
```
78+
7479
### Setup a shared volume for recordings
7580

7681
See [Setting up a shared volume for recordings](docs/sharedvolume-README.md)

app/controllers/api/servers_controller.rb

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ class ServersController < ApplicationController
1818
# "id": String,
1919
# "url": String,
2020
# "secret": String,
21+
# "tag": String,
22+
# "bbb_version": String,
2123
# "state": String,
2224
# "load": String,
2325
# "load_multiplier": String,
@@ -49,6 +51,8 @@ def get_servers
4951
# "id": String,
5052
# "url": String,
5153
# "secret": String,
54+
# "tag": String,
55+
# "bbb_version": String,
5256
# "state": String,
5357
# "load": String,
5458
# "load_multiplier": String,
@@ -71,6 +75,7 @@ def get_server_info
7175
# "url": String, # Required: URL of the BigBlueButton server
7276
# "secret": String, # Required: Secret key of the BigBlueButton server
7377
# "load_multiplier": Float # Optional: A non-zero number, defaults to 1.0 if not provided or zero
78+
# "tag": String # Optional: A special-purpose tag for the server (empty String to not set it)
7479
# }
7580
# }
7681
def add_server
@@ -80,7 +85,8 @@ def add_server
8085
tmp_load_multiplier = server_create_params[:load_multiplier].presence&.to_d || 1.0
8186
tmp_load_multiplier = 1.0 if tmp_load_multiplier.zero?
8287

83-
server = Server.create!(url: server_create_params[:url], secret: server_create_params[:secret], load_multiplier: tmp_load_multiplier)
88+
server = Server.create!(url: server_create_params[:url], secret: server_create_params[:secret],
89+
load_multiplier: tmp_load_multiplier, tag: server_create_params[:tag].presence)
8490
render json: server_to_json(server), status: :created
8591
end
8692
end
@@ -95,6 +101,7 @@ def add_server
95101
# "state": String, # Optional: 'enable', 'cordon', or 'disable'
96102
# "load_multiplier": Float # Optional: A non-zero number
97103
# "secret": String # Optional: Secret key of the BigBlueButton server
104+
# "tag": String # Optional: A special-purpose tag for the server, empty string to remove the tag
98105
# }
99106
# }
100107
def update_server
@@ -166,6 +173,8 @@ def server_to_json(server)
166173
id: server.id,
167174
url: server.url,
168175
secret: server.secret,
176+
tag: server.tag.nil? ? '' : server.tag,
177+
bbb_version: server.bbb_version.nil? ? '' : server.bbb_version,
169178
state: server.state.presence || (server.enabled ? 'enabled' : 'disabled'),
170179
load: server.load.presence || 'unavailable',
171180
load_multiplier: server.load_multiplier.nil? ? 1.0 : server.load_multiplier.to_d,
@@ -174,11 +183,11 @@ def server_to_json(server)
174183
end
175184

176185
def server_create_params
177-
params.require(:server).permit(:url, :secret, :load_multiplier)
186+
params.require(:server).permit(:url, :secret, :load_multiplier, :tag)
178187
end
179188

180189
def server_update_params
181-
params.require(:server).permit(:state, :load_multiplier, :secret)
190+
params.require(:server).permit(:state, :load_multiplier, :secret, :tag)
182191
end
183192

184193
def server_panic_params

app/controllers/bigbluebutton_api_controller.rb

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -160,44 +160,54 @@ def create
160160
params.require(:meetingID)
161161

162162
begin
163-
server = Server.find_available
163+
# Check if meeting is already running
164+
meeting = Meeting.find(params[:meetingID], @tenant&.id)
165+
server = meeting.server
166+
logger.debug("Found existing meeting #{params[:meetingID]} on BigBlueButton server #{server.id}.")
164167
rescue ApplicationRedisRecord::RecordNotFound
165-
raise InternalError, 'Could not find any available servers.'
168+
begin
169+
# Find available server and create meeting on it
170+
server = Server.find_available(params[:'meta_server-tag'])
171+
172+
# Create meeting in database
173+
logger.debug("Creating meeting #{params[:meetingID]} in database.")
174+
moderator_pwd = params[:moderatorPW].presence || SecureRandom.alphanumeric(8)
175+
meeting = Meeting.find_or_create_with_server!(
176+
params[:meetingID],
177+
server,
178+
moderator_pwd,
179+
params[:voiceBridge],
180+
@tenant&.id
181+
)
182+
183+
# Update server if meeting (unexpectedly) already existed on a different server
184+
server = meeting.server
185+
186+
logger.debug("Incrementing server #{server.id} load by 1")
187+
server.increment_load(1)
188+
rescue ApplicationRedisRecord::RecordNotFound => e
189+
raise InternalError, e.message
190+
end
166191
end
167192

168-
# Create meeting in database
169-
logger.debug("Creating meeting #{params[:meetingID]} in database.")
170-
171-
moderator_pwd = params[:moderatorPW].presence || SecureRandom.alphanumeric(8)
172-
params[:moderatorPW] = moderator_pwd
173-
174-
meeting = Meeting.find_or_create_with_server!(
175-
params[:meetingID],
176-
server,
177-
moderator_pwd,
178-
params[:voiceBridge],
179-
@tenant&.id
180-
)
181-
182-
# Update with old server if meeting already existed in database
183-
server = meeting.server
184-
185-
logger.debug("Incrementing server #{server.id} load by 1")
186-
server.increment_load(1)
193+
params[:moderatorPW] = meeting.moderator_pw
194+
params[:voiceBridge] = meeting.voice_bridge
195+
params[:'meta_tenant-id'] = @tenant.id if @tenant.present?
196+
if server.tag.present?
197+
params[:'meta_server-tag'] = server.tag
198+
else
199+
params.delete(:'meta_server-tag')
200+
end
187201

188202
duration = params[:duration].to_i
189203

190-
params[:'meta_tenant-id'] = @tenant.id if @tenant.present?
191-
192204
# Set/Overite duration if MAX_MEETING_DURATION is set and it's greater than params[:duration] (if passed)
193205
if !Rails.configuration.x.max_meeting_duration.zero? &&
194206
(duration.zero? || duration > Rails.configuration.x.max_meeting_duration)
195207
logger.debug("Setting duration to #{Rails.configuration.x.max_meeting_duration}")
196208
params[:duration] = Rails.configuration.x.max_meeting_duration
197209
end
198210

199-
params[:voiceBridge] = meeting.voice_bridge
200-
201211
if @tenant&.lrs_endpoint.present?
202212
lrs_payload = LrsPayloadService.new(tenant: @tenant, secret: server.secret).call
203213
params[:'meta_secret-lrs-payload'] = lrs_payload if lrs_payload.present?
@@ -289,6 +299,9 @@ def join
289299
logger.info("The requested meeting #{params[:meetingID]} does not exist")
290300
raise MeetingNotFoundError
291301
end
302+
logger.debug("Incrementing server #{server.id} load by 1")
303+
server.increment_load(1)
304+
292305
# Get list of params that should not be modified by join API call
293306
excluded_params = Rails.configuration.x.join_exclude_params
294307

app/models/server.rb

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# frozen_string_literal: true
22

33
class Server < ApplicationRedisRecord
4-
define_attribute_methods :id, :url, :secret, :enabled, :load, :online, :load_multiplier, :healthy_counter,
5-
:unhealthy_counter, :state, :meetings, :users, :largest_meeting, :videos
4+
define_attribute_methods :id, :url, :secret, :tag, :enabled, :load, :online, :load_multiplier, :healthy_counter,
5+
:unhealthy_counter, :state, :meetings, :users, :largest_meeting, :videos, :bbb_version
66

77
# Unique ID for this server
88
application_redis_attr :id
@@ -13,6 +13,9 @@ class Server < ApplicationRedisRecord
1313
# Shared secret for making API requests to this server
1414
application_redis_attr :secret
1515

16+
# Special purpose tag for this server
17+
application_redis_attr :tag
18+
1619
# Whether the server is administratively enabled (allowed to create new meetings)
1720
application_redis_attr :enabled
1821

@@ -46,6 +49,9 @@ class Server < ApplicationRedisRecord
4649
# Indicator of total video streams in this server
4750
application_redis_attr :videos
4851

52+
# Indicator of the BBB version of this server
53+
application_redis_attr :bbb_version
54+
4955
def online=(value)
5056
value = !!value
5157
online_will_change! unless @online == value
@@ -91,13 +97,17 @@ def save!
9197
result = redis.multi do |pipeline|
9298
pipeline.hset(server_key, 'url', url) if url_changed?
9399
pipeline.hset(server_key, 'secret', secret) if secret_changed?
100+
if tag_changed?
101+
tag.present? ? pipeline.hset(server_key, 'tag', tag) : pipeline.hdel(server_key, 'tag')
102+
end
94103
pipeline.hset(server_key, 'online', online ? 'true' : 'false') if online_changed?
95104
pipeline.hset(server_key, 'load_multiplier', load_multiplier) if load_multiplier_changed?
96105
pipeline.hset(server_key, 'state', state) if state_changed?
97106
pipeline.hset(server_key, 'meetings', meetings) if meetings_changed?
98107
pipeline.hset(server_key, 'users', users) if users_changed?
99108
pipeline.hset(server_key, 'largest_meeting', largest_meeting) if largest_meeting_changed?
100109
pipeline.hset(server_key, 'videos', videos) if videos_changed?
110+
pipeline.hset(server_key, 'bbb_version', bbb_version) if bbb_version_changed?
101111
pipeline.sadd?('servers', id) if id_changed?
102112
state.present? ? save_with_state(pipeline) : save_without_state(pipeline)
103113
end
@@ -276,17 +286,29 @@ def self.find(id)
276286
end
277287

278288
# Find the server with the lowest load (for creating a new meeting)
279-
def self.find_available
280-
with_connection do |redis|
281-
id, load, hash = 5.times do
282-
ids_loads = redis.zrange('server_load', 0, 0, with_scores: true)
283-
raise RecordNotFound.new("Couldn't find available Server", name, nil) if ids_loads.blank?
289+
def self.find_available(tag_arg = nil)
290+
# Check if tag is required
291+
tag = tag_arg.presence
292+
tag_required = false
293+
if !tag.nil? && tag[-1] == '!'
294+
tag = tag[0..-2].presence # always returns String, if tag is String
295+
tag_required = true
296+
end
284297

285-
id, load = ids_loads.first
298+
# Find available&matching server with the lowest load
299+
with_connection do |redis|
300+
ids_loads = redis.zrange('server_load', 0, -1, with_scores: true)
301+
raise RecordNotFound.new("Could not find any available servers.", name, nil) if ids_loads.blank?
302+
if !tag.nil? && ids_loads.none? { |myid, _| redis.hget(key(myid), 'tag') == tag }
303+
raise RecordNotFound.new("Could not find any available servers with tag=#{tag}.", name, nil) if tag_required
304+
tag = nil # fall back to servers without tag
305+
end
306+
ids_loads = ids_loads.select { |myid, _| redis.hget(key(myid), 'tag') == tag }
307+
id, load, hash = ids_loads.each do |id, load|
286308
hash = redis.hgetall(key(id))
287309
break id, load, hash if hash.present?
288310
end
289-
raise RecordNotFound.new("Couldn't find available Server", name, id) if hash.blank?
311+
raise RecordNotFound.new("Could not find any available servers.", name, id) if hash.blank?
290312

291313
hash['id'] = id
292314
if hash['state'].present?

app/services/server_update_service.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ def call
1313

1414
update_secret if @params[:secret].present?
1515

16+
update_tag unless @params[:tag].nil?
17+
1618
@server.save!
1719
end
1820

@@ -43,4 +45,8 @@ def update_load_multiplier
4345
def update_secret
4446
@server.secret = @params[:secret]
4547
end
48+
49+
def update_tag
50+
@server.tag = @params[:tag].presence
51+
end
4652
end

bigbluebutton/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,7 @@ Finally (after switching back to root), set the `spool_dir` setting in `scalelit
6161
### Other configurations
6262

6363
If you need to customize the rsync command (for example, to pass the `--rsh` option to set up a tunnel), you can add extra rsync command line arguments via the `extra_rsync_opts` array in `scalelite.yml`.
64+
65+
### Recording cleanup cronjob
66+
67+
Copy the script `scalelite_prune_recordings` to `/etc/cron.daily` on the BBB server, to periodically clean up the local files of recordings that have been transferred to Scalelite. You may adjust the variables MAXAGE and EVENTS_MAXAGE to the number of days you would like to keep the local files on the BBB server.

bigbluebutton/scalelite_prune_recordings.sh renamed to bigbluebutton/scalelite_prune_recordings

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
#!/bin/bash
1+
#!/bin/bash
22

3-
# Place this file in /etc/cron.daily
3+
# Place this file in /etc/cron.daily and make sure it is executable
44
#
55

66
# Delete sent recording after 4 days

docs/api-README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ n/a
2222
"id": String,
2323
"url": String,
2424
"secret": String,
25+
"tag": String,
2526
"state": String,
2627
"load": String,
2728
"load_multiplier": String,
@@ -56,6 +57,7 @@ Returns the data associated with a single server
5657
"id": String,
5758
"url": String,
5859
"secret": String,
60+
"tag": String,
5961
"state": String,
6062
"load": String,
6163
"load_multiplier": String,
@@ -83,7 +85,8 @@ Adds a new server
8385
"server": {
8486
"url": String, # Required: URL of the BigBlueButton server
8587
"secret": String, # Required: Secret key of the BigBlueButton server
86-
"load_multiplier": Float # Optional: A non-zero number, defaults to 1.0 if not provided or zero
88+
"load_multiplier": Float, # Optional: A non-zero number, defaults to 1.0 if not provided or zero
89+
"tag": String # Optional: A special-purpose tag for the server (empty string to not set it)
8790
}
8891
}
8992
```
@@ -94,6 +97,7 @@ Adds a new server
9497
"id": String,
9598
"url": String,
9699
"secret": String,
100+
"tag": String,
97101
"state": String,
98102
"load": String,
99103
"load_multiplier": String,
@@ -122,7 +126,8 @@ Updates a server
122126
"server": {
123127
"state": String, # Optional: 'enable', 'cordon', or 'disable'
124128
"load_multiplier": Float # Optional: A non-zero number
125-
"secret": String # Optional: Secret key of the BigBlueButton server
129+
"secret": String, # Optional: Secret key of the BigBlueButton server
130+
"tag": String # Optional: A special-purpose tag for the server (empty string to remove the tag)
126131
}
127132
}
128133
```
@@ -133,6 +138,7 @@ Updates a server
133138
"id": String,
134139
"url": String,
135140
"secret": String,
141+
"tag": String,
136142
"state": String,
137143
"load": String,
138144
"load_multiplier": String,

0 commit comments

Comments
 (0)