From 6ef095785a44b35ea9d65a91e5d969001723e06d Mon Sep 17 00:00:00 2001 From: Lars Kiesow Date: Sun, 26 Jul 2020 23:38:56 +0200 Subject: [PATCH] URL matching for control commands This patch allows all commands to accept not only an exact ID match but also search patterns for matching URLs. This allows for a much easier control of groups of servers instead of having to find out the servers identifier every time and then handle each server indivifually. For example, you can run the following command to enbale multiple servers: ./bin/rake 'servers:enable[bbb0\[1-5\].lkiesow.io]' You can still use exact identifier matches though and the identifiers will always be checked before checking the URL. Hence, you still can use a command like: ./bin/rake 'servers:disable[a18201ec-f090-4bff-aaac-d0f5ab003f42]' This closes #205 which was trying to solve the same problem by using the host manes as server identifier instead. That shouldn't be necessary any longer when this patch is applied. --- README.md | 19 ++++++++- app/models/server.rb | 27 ++++++++++++ lib/tasks/servers.rake | 93 +++++++++++++++++++++++------------------- 3 files changed, 95 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 11d56186b..115eef53a 100644 --- a/README.md +++ b/README.md @@ -176,7 +176,12 @@ Scalelite comes with a set of commands to Server management is provided using rake tasks which update server information in Redis. -In a Docker deployment, these should be run from in the Docker container. You can enter the Docker container using a command like `docker exec -it scalelite-api /bin/sh` +In a Docker deployment, these should be run from in the Docker container. +You can enter the container using a command like `docker exec -it scalelite-api /bin/sh` +or execute rake directly using `docker exec -it scalelite-api bin/rake …`. + +All server commands can be used with either a specific server ID or a regular expressions matching the URL as argument. + ### Show configured server details @@ -196,6 +201,18 @@ id: 2d2d674a-c6bb-48f3-8ad4-68f33a80a5b7 online ``` +as with all commands, you can search for specific servers using: + +```sh +./bin/rake servers:[bbb.*\\.example\\.com] +``` + +or + +```sh +./bin/rake servers:[bbb0\[1-5\].example.com] +``` + Particular information to note: * `id`: This is the ID value used when updating or removing the server diff --git a/app/models/server.rb b/app/models/server.rb index f3100e784..292cb9c52 100644 --- a/app/models/server.rb +++ b/app/models/server.rb @@ -161,6 +161,33 @@ def self.find(id) end end + # Find a server by ID or URL + def self.find_all(search) + servers = [] + with_connection do |redis| + ids = redis.smembers('servers') + raise RecordNotFound.new('No servers conficured', name, nil) if ids.blank? + + search_regexp = Regexp.new(search) + + ids.each do |id| + hash, enabled, load = redis.pipelined do + redis.hgetall(key(id)) + redis.sismember('server_enabled', id) + redis.zscore('server_load', id) + end + next if hash.blank? || (search != id && !search_regexp.match?(hash['url'])) + + hash['id'] = id + hash['enabled'] = enabled + hash['load'] = load if enabled + hash['online'] = (hash['online'] == 'true') + servers << new.init_with_attributes(hash) + end + end + servers + end + # Find the server with the lowest load (for creating a new meeting) def self.find_available with_connection do |redis| diff --git a/lib/tasks/servers.rake b/lib/tasks/servers.rake index 43a0107a9..a9e9da26f 100644 --- a/lib/tasks/servers.rake +++ b/lib/tasks/servers.rake @@ -1,9 +1,9 @@ # frozen_string_literal: true desc('List configured BigBlueButton servers') -task servers: :environment do - servers = Server.all - puts('No servers are configured') if servers.empty? +task :servers, [:search] => :environment do |_t, args| + servers = args.search.nil? ? Server.all : Server.find_all(args.search) + puts('No servers found') if servers.empty? servers.each do |server| puts("id: #{server.id}") puts("\turl: #{server.url}") @@ -35,75 +35,82 @@ namespace :servers do puts("id: #{server.id}") end - desc 'Remove a BigBlueButton server' - task :remove, [:id] => :environment do |_t, args| - server = Server.find(args.id) - server.destroy! + desc 'Remove BigBlueButton servers' + task :remove, [:search] => :environment do |_t, args| + Server.find_all(args.search).each(&:destroy!) puts('OK') rescue ApplicationRedisRecord::RecordNotFound - puts("ERROR: No server found with id: #{args.id}") + puts("ERROR: No server found matching: #{args.id}") end desc 'Mark a BigBlueButton server as available for scheduling new meetings' - task :enable, [:id] => :environment do |_t, args| - server = Server.find(args.id) - server.enabled = true - server.save! + task :enable, [:search] => :environment do |_t, args| + servers = Server.find_all(args.search) + servers.each do |server| + server.enabled = true + server.save! + end puts('OK') rescue ApplicationRedisRecord::RecordNotFound - puts("ERROR: No server found with id: #{args.id}") + puts("ERROR: No server found matching: #{args.search}") end desc 'Mark a BigBlueButton server as unavailable to stop scheduling new meetings' - task :disable, [:id] => :environment do |_t, args| - server = Server.find(args.id) - server.enabled = false - server.save! + task :disable, [:search] => :environment do |_t, args| + servers = Server.find_all(args.search) + servers.each do |server| + server.enabled = false + server.save! + end puts('OK') rescue ApplicationRedisRecord::RecordNotFound - puts("ERROR: No server found with id: #{args.id}") + puts("ERROR: No server found matching: #{args.search}") end desc 'Mark a BigBlueButton server as unavailable, and clear all meetings from it' - task :panic, [:id, :keep_state] => :environment do |_t, args| + task :panic, [:search, :keep_state] => :environment do |_t, args| args.with_defaults(keep_state: false) include ApiHelper - server = Server.find(args.id) - server.enabled = false unless args.keep_state - server.save! + servers = Server.find_all(args.search) + servers.each do |server| + server.enabled = false unless args.keep_state + server.save! - meetings = Meeting.all.select { |m| m.server_id == server.id } - meetings.each do |meeting| - puts("Clearing Meeting id=#{meeting.id}") - meeting.destroy! + meetings = Meeting.all.select { |m| m.server_id == server.id } + meetings.each do |meeting| + puts("Clearing Meeting id=#{meeting.id}") + meeting.destroy! - get_post_req(encode_bbb_uri('end', server.url, server.secret, meetingID: meeting.id)) - rescue ApplicationRedisRecord::RecordNotDestroyed => e - puts("WARNING: Could not destroy meeting id=#{meeting.id}: #{e}") - rescue StandardError => e - puts("WARNING: Could not end meeting id=#{meeting.id}: #{e}") + get_post_req(encode_bbb_uri('end', server.url, server.secret, meetingID: meeting.id)) + rescue ApplicationRedisRecord::RecordNotDestroyed => e + puts("WARNING: Could not destroy meeting id=#{meeting.id}: #{e}") + rescue StandardError => e + puts("WARNING: Could not end meeting id=#{meeting.id}: #{e}") + end end puts('OK') rescue ApplicationRedisRecord::RecordNotFound - puts("ERROR: No server found with id: #{args.id}") + puts("ERROR: No server found matching: #{args.search}") end desc 'Set the load-multiplier of a BigBlueButton server' - task :loadMultiplier, [:id, :load_multiplier] => :environment do |_t, args| - server = Server.find(args.id) - tmp_load_multiplier = 1.0 - unless args.load_multiplier.nil? - tmp_load_multiplier = args.load_multiplier.to_d - if tmp_load_multiplier.zero? - puts('WARNING! Load-multiplier was not readable or 0, so it is now 1') - tmp_load_multiplier = 1.0 + task :loadMultiplier, [:search, :load_multiplier] => :environment do |_t, args| + servers = Server.find_all(args.search) + servers.each do |server| + tmp_load_multiplier = 1.0 + unless args.load_multiplier.nil? + tmp_load_multiplier = args.load_multiplier.to_d + if tmp_load_multiplier.zero? + puts('WARNING! Load-multiplier was not readable or 0, so it is now 1') + tmp_load_multiplier = 1.0 + end end + server.load_multiplier = tmp_load_multiplier + server.save! end - server.load_multiplier = tmp_load_multiplier - server.save! puts('OK') rescue ApplicationRedisRecord::RecordNotFound - puts("ERROR: No server found with id: #{args.id}") + puts("ERROR: No server found matching: #{args.search}") end end