From dd6fb56ca5a8c1e03715c49f75e9995cf1419cad Mon Sep 17 00:00:00 2001 From: Jan Kessler Date: Mon, 22 Apr 2024 22:09:23 +0200 Subject: [PATCH] Poll & list BBB server version (if revealed) (#1058) * initial implementation of version poll task * add server bbb_version to Redis model and adapt poll/servers/status rake tasks * add bbb_version to verbose output of rake server:yaml * add bbb_version to output of servers / getServerInfo API * mention BBB configuration to reveal version in README --- README.md | 5 ++++ app/controllers/api/servers_controller.rb | 3 +++ app/models/server.rb | 6 ++++- lib/server_sync.rb | 3 ++- lib/tasks/poll.rake | 32 ++++++++++++++++++++++- lib/tasks/servers.rake | 1 + lib/tasks/status.rake | 5 ++-- 7 files changed, 50 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 559dfb1e..b156b7ca 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,11 @@ To help users who are behind restrictive firewalls to send/receive media (audio, Again, [bbb-install.sh](https://github.com/bigbluebutton/bbb-install#install-a-turn-server) can automate this process for you. +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: +``` +allowRevealOfBBBVersion=true +``` + ### Setup a shared volume for recordings See [Setting up a shared volume for recordings](docs/sharedvolume-README.md) diff --git a/app/controllers/api/servers_controller.rb b/app/controllers/api/servers_controller.rb index 3e2d29da..45bac1b3 100644 --- a/app/controllers/api/servers_controller.rb +++ b/app/controllers/api/servers_controller.rb @@ -19,6 +19,7 @@ class ServersController < ApplicationController # "url": String, # "secret": String, # "tag": String, + # "bbb_version": String, # "state": String, # "load": String, # "load_multiplier": String, @@ -51,6 +52,7 @@ def get_servers # "url": String, # "secret": String, # "tag": String, + # "bbb_version": String, # "state": String, # "load": String, # "load_multiplier": String, @@ -172,6 +174,7 @@ def server_to_json(server) url: server.url, secret: server.secret, tag: server.tag.nil? ? '' : server.tag, + bbb_version: server.bbb_version.nil? ? '' : server.bbb_version, state: server.state.presence || (server.enabled ? 'enabled' : 'disabled'), load: server.load.presence || 'unavailable', load_multiplier: server.load_multiplier.nil? ? 1.0 : server.load_multiplier.to_d, diff --git a/app/models/server.rb b/app/models/server.rb index 2e80d503..75ba0ab2 100644 --- a/app/models/server.rb +++ b/app/models/server.rb @@ -2,7 +2,7 @@ class Server < ApplicationRedisRecord define_attribute_methods :id, :url, :secret, :tag, :enabled, :load, :online, :load_multiplier, :healthy_counter, - :unhealthy_counter, :state, :meetings, :users, :largest_meeting, :videos + :unhealthy_counter, :state, :meetings, :users, :largest_meeting, :videos, :bbb_version # Unique ID for this server application_redis_attr :id @@ -49,6 +49,9 @@ class Server < ApplicationRedisRecord # Indicator of total video streams in this server application_redis_attr :videos + # Indicator of the BBB version of this server + application_redis_attr :bbb_version + def online=(value) value = !!value online_will_change! unless @online == value @@ -104,6 +107,7 @@ def save! pipeline.hset(server_key, 'users', users) if users_changed? pipeline.hset(server_key, 'largest_meeting', largest_meeting) if largest_meeting_changed? pipeline.hset(server_key, 'videos', videos) if videos_changed? + pipeline.hset(server_key, 'bbb_version', bbb_version) if bbb_version_changed? pipeline.sadd?('servers', id) if id_changed? state.present? ? save_with_state(pipeline) : save_without_state(pipeline) end diff --git a/lib/server_sync.rb b/lib/server_sync.rb index 3adf1684..3648603b 100644 --- a/lib/server_sync.rb +++ b/lib/server_sync.rb @@ -4,7 +4,7 @@ # servers:sync an servers:yaml tasks. class ServerSync SERVER_PARAMS = %w[url secret enabled load_multiplier tag].freeze - PARAMS_IGNORE = %w[load state online].freeze + PARAMS_IGNORE = %w[load state bbb_version online].freeze SYNC_MODES = %w[keep cordon force].freeze class SyncError < StandardError @@ -186,6 +186,7 @@ def self.dump(verbose) if verbose info["state"] = server.state.presence || (server.enabled? ? 'enabled' : 'disabled') info["load"] = server.load.presence || -1.0 + info["bbb_version"] = server.bbb_version.nil? ? '' : server.bbb_version info["online"] = server.online end [server.id, info] diff --git a/lib/tasks/poll.rake b/lib/tasks/poll.rake index 1a0ad16a..41e4d74a 100644 --- a/lib/tasks/poll.rake +++ b/lib/tasks/poll.rake @@ -174,6 +174,36 @@ namespace :poll do pool.wait_for_termination(5) || pool.kill end + desc 'Check the BBB version of all servers' + task versions: :environment do + include ApiHelper + + Rails.logger.debug('Checking versions') + pool = Concurrent::FixedThreadPool.new(Rails.configuration.x.poller_threads.to_i - 1, name: 'sync-version-data') + tasks = Server.all.map do |server| + Concurrent::Promises.future_on(pool) do + Rails.logger.debug { "Checking Version of id=#{server.id}" } + bbb_version = get_post_req(encode_bbb_uri('', server.url, server.secret)).xpath('/response/bbbVersion').text + server.bbb_version = bbb_version + rescue StandardError => e + Rails.logger.warn("Unexpected error when checking version of server id=#{server.id}: #{e}") + ensure + begin + server.save! + rescue ApplicationRedisRecord::RecordNotSaved => e + Rails.logger.warn("Unable to update Server id=#{server.id}: #{e}") + end + end + end + begin + Concurrent::Promises.zip_futures_on(pool, *tasks).wait!(Rails.configuration.x.poller_wait_timeout) + rescue StandardError => e + Rails.logger.warn("Error #{e}") + end + pool.shutdown + pool.wait_for_termination(5) || pool.kill + end + desc 'Run all pollers once' - multitask all: [:servers, :meetings] + multitask all: [:servers, :meetings, :versions] end diff --git a/lib/tasks/servers.rake b/lib/tasks/servers.rake index 949de4ca..f5f34098 100644 --- a/lib/tasks/servers.rake +++ b/lib/tasks/servers.rake @@ -15,6 +15,7 @@ task servers: :environment do end puts("\tload: #{server.load.presence || 'unavailable'}") puts("\tload multiplier: #{server.load_multiplier.nil? ? 1.0 : server.load_multiplier.to_d}") + puts("\tbbb version: #{server.bbb_version.nil? ? '' : server.bbb_version}") puts("\ttag: #{server.tag.nil? ? '' : server.tag}") puts("\t#{server.online ? 'online' : 'offline'}") end diff --git a/lib/tasks/status.rake b/lib/tasks/status.rake index 046ebdd1..98328dea 100644 --- a/lib/tasks/status.rake +++ b/lib/tasks/status.rake @@ -7,7 +7,7 @@ task status: :environment do include ApiHelper servers_info = [] - ServerInfo = Struct.new(:hostname, :state, :status, :meetings, :users, :largest, :videos, :load, :tag) + ServerInfo = Struct.new(:hostname, :state, :status, :meetings, :users, :largest, :videos, :load, :bbb_version, :tag) Server.all.each do |server| state = server.state @@ -15,7 +15,7 @@ task status: :environment do state = server.state.present? ? status_with_state(state) : status_without_state(enabled) info = ServerInfo.new(URI.parse(server.url).host, state, server.online ? 'online' : 'offline', server.meetings, server.users, -server.largest_meeting, server.videos, server.load, server.tag) +server.largest_meeting, server.videos, server.load, server.bbb_version, server.tag) # Convert to openstruct to allow dot syntax usage servers_info.push(info) @@ -33,6 +33,7 @@ server.largest_meeting, server.videos, server.load, server.tag) t.add_column('LARGEST MEETING', &:largest) t.add_column('VIDEOS', &:videos) t.add_column('LOAD', &:load) + t.add_column('BBB VERSION', &:bbb_version) t.add_column('TAG', &:tag) end