From 2056db7f3b9bc6442cfeb7019c6b34492545dacf Mon Sep 17 00:00:00 2001 From: Mike DeAngelo Date: Tue, 11 Jun 2024 15:42:29 -0400 Subject: [PATCH] feat: Alert randomization --- lib/gzr/commands/alert.rb | 16 ++++ lib/gzr/commands/alert/randomize.rb | 101 +++++++++++++++++++++++ lib/gzr/modules/alert.rb | 10 +++ spec/integration/alert/randomize_spec.rb | 41 +++++++++ spec/integration/alert_spec.rb | 46 +++++++++++ 5 files changed, 214 insertions(+) create mode 100644 lib/gzr/commands/alert/randomize.rb create mode 100644 spec/integration/alert/randomize_spec.rb create mode 100644 spec/integration/alert_spec.rb diff --git a/lib/gzr/commands/alert.rb b/lib/gzr/commands/alert.rb index 07985b9..9a817e3 100644 --- a/lib/gzr/commands/alert.rb +++ b/lib/gzr/commands/alert.rb @@ -51,6 +51,22 @@ def ls(*) end end + desc 'randomize', 'Randomize the scheduled alerts on a server' + method_option :help, aliases: '-h', type: :boolean, + desc: 'Display usage information' + method_option :window, type: :numeric, default: 60, + desc: 'Length of window' + method_option :all, type: :boolean, + desc: 'Randomize all alerts regardless of owner' + def randomize(*) + if options[:help] + invoke :help, ['randomize'] + else + require_relative 'alert/randomize' + Gzr::Commands::Alert::Randomize.new(options).execute + end + end + desc 'cat ALERT_ID', 'Output json information about an alert to screen or file' method_option :help, aliases: '-h', type: :boolean, desc: 'Display usage information' diff --git a/lib/gzr/commands/alert/randomize.rb b/lib/gzr/commands/alert/randomize.rb new file mode 100644 index 0000000..6e55962 --- /dev/null +++ b/lib/gzr/commands/alert/randomize.rb @@ -0,0 +1,101 @@ +# The MIT License (MIT) + +# Copyright (c) 2024 Mike DeAngelo Google, Inc. + +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +# frozen_string_literal: true + +require_relative '../../command' +require_relative '../../modules/alert' +require_relative '../../modules/user' + +module Gzr + module Commands + class Alert + class Randomize < Gzr::Command + include Gzr::Alert + include Gzr::User + def initialize(options) + super() + @options = options + end + + def execute(input: $stdin, output: $stdout) + say_warning(@options) if @options[:debug] + + window = @options[:window] + if window < 1 or window > 60 + say_error("window must be between 1 and 60") + raise Gzr::CLI::Error.new() + end + + with_session do + @me ||= query_me("id") + + req = {} + req[:disabled] = false + req[:all_owners] = @options[:all] unless @options[:all].nil? + alerts = search_alerts(**req) + begin + say_ok "No alerts found" + return nil + end unless alerts && alerts.length > 0 + + alerts.each do |alert| + crontab = alert[:cron] + if crontab == "" + say_warning("skipping alert #{alert[:id]} with no cron") + next + end + cronfields = crontab.split(%r{\s+}) + minute = cronfields[0].to_i + hour = cronfields[1].to_i + factor = rand(window) - (window/2) + minute = minute + factor + if minute < 0 + hour = hour - 1 + minute = minute + 60 + end + if hour < 0 + hour = 23 + end + if minute > 59 + hour = hour + 1 + minute = minute - 60 + end + if hour > 23 + hour = 0 + end + cronfields[0] = minute + cronfields[1] = hour + crontab = cronfields.join(' ') + begin + alert[:cron] = crontab + update_alert(alert[:id], alert) + rescue LookerSDK::UnprocessableEntity => e + say_warning("Skipping invalid cron") + end + end + + end + end + end + end + end +end diff --git a/lib/gzr/modules/alert.rb b/lib/gzr/modules/alert.rb index 1daad7c..1195904 100644 --- a/lib/gzr/modules/alert.rb +++ b/lib/gzr/modules/alert.rb @@ -178,5 +178,15 @@ def create_alert(req) raise end end + + def update_alert(alert_id,req) + begin + @sdk.update_alert(alert_id,req).to_attrs + rescue LookerSDK::Error => e + say_error "Error calling update_alert(#{alert_id}, #{JSON.pretty_generate(req)})" + say_error e + raise + end + end end end diff --git a/spec/integration/alert/randomize_spec.rb b/spec/integration/alert/randomize_spec.rb new file mode 100644 index 0000000..7b94617 --- /dev/null +++ b/spec/integration/alert/randomize_spec.rb @@ -0,0 +1,41 @@ +# The MIT License (MIT) + +# Copyright (c) 2024 Mike DeAngelo Google, Inc. + +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +RSpec.describe "`gzr alert randomize` command", type: :cli do + it "executes `gzr alert help randomize` command successfully" do + output = `gzr alert help randomize` + expected_output = <<-OUT +Usage: + gzr alert randomize + +Options: + -h, [--help], [--no-help] # Display usage information + [--window=N] # Length of window + # Default: 60 + [--all], [--no-all] # Randomize all alerts regardless of owner + +Randomize the scheduled alerts on a server + OUT + + expect(output).to eq(expected_output) + end +end + diff --git a/spec/integration/alert_spec.rb b/spec/integration/alert_spec.rb new file mode 100644 index 0000000..e60896c --- /dev/null +++ b/spec/integration/alert_spec.rb @@ -0,0 +1,46 @@ +# The MIT License (MIT) + +# Copyright (c) 2024 Mike DeAngelo Google, Inc. + +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +RSpec.describe "`gzr alert` command", type: :cli do + it "executes `gzr help alert` command successfully" do + output = `gzr help alert` + expected_output = <<-OUT +Commands: + gzr alert cat ALERT_ID # Output json information about an alert to screen or file + gzr alert chown ALERT_ID OWNER_ID # Change the owner of the alert given by ALERT_ID to OWNER_ID + gzr alert disable ALERT_ID REASON # Disable the alert given by ALERT_ID + gzr alert enable ALERT_ID # Enable the alert given by ALERT_ID + gzr alert follow ALERT_ID # Start following the alert given by ALERT_ID + gzr alert help [COMMAND] # Describe subcommands or one specific subcommand + gzr alert import FILE [DASHBOARD_ELEMENT_ID] # Import an alert from a file + gzr alert ls # list alerts + gzr alert notifications # Get notifications + gzr alert randomize # Randomize the scheduled alerts on a server + gzr alert read NOTIFICATION_ID # Read notification id + gzr alert rm ALERT_ID # Delete the alert given by ALERT_ID + gzr alert threshold ALERT_ID THRESHOLD # Change the threshold of the alert given by ALERT_ID + gzr alert unfollow ALERT_ID # Stop following the alert given by ALERT_ID + + OUT + + expect(output).to eq(expected_output) + end +end