Skip to content

Commit

Permalink
feat: Alerts management through gazer (#180)
Browse files Browse the repository at this point in the history
* feat: Add alert ls and alert cat commands

* feat: search all alerts, and search disabled alerts

* feat: Add user information to alerts cat

* feat: added alert info to dashboard cat

* feat: moved alerts processing for dashboard cat so it also is included in folder export

* feat: follow and unfollow an alert

* fix: handle parameters for alert ls more deftly

* fix: remove extra debug statement

* feat: Added enable and disable alerts

* feat: Added ability to change threshold

* feat: add rm alert command

* feat: Add alert chown command

* feat: list notification and read them

* feat: alternate field_names function for future use

* feat: make alerts work with `dashboard cat --trim`

* feat: alert create command

* feat: dashboard import will recreate alerts

* doc: Updated copyright notices
  • Loading branch information
drstrangelooker authored Apr 21, 2023
1 parent f808b14 commit 74d0307
Show file tree
Hide file tree
Showing 19 changed files with 1,130 additions and 6 deletions.
5 changes: 4 additions & 1 deletion lib/gzr/cli.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The MIT License (MIT)

# Copyright (c) 2018 Mike DeAngelo Looker Data Sciences, Inc.
# Copyright (c) 2023 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
Expand Down Expand Up @@ -58,6 +58,9 @@ def version
map %w(--version -v) => :version
map space: :folder # Alias space command to folder

require_relative 'commands/alert'
register Gzr::Commands::Alert, 'alert', 'alert [SUBCOMMAND]', 'Command description...'

require_relative 'commands/attribute'
register Gzr::Commands::Attribute, 'attribute', 'attribute [SUBCOMMAND]', 'Command description...'

Expand Down
74 changes: 73 additions & 1 deletion lib/gzr/command.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The MIT icense (MIT)

# Copyright (c) 2018 Mike DeAngelo Looker Data Sciences, Inc.
# Copyright (c) 2023 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
Expand Down Expand Up @@ -52,6 +52,18 @@ def execute(*)
)
end

def get_user_by_id(user_id, req=nil)
user = nil
begin
user = @sdk.user(user_id, req)
rescue LookerSDK::Error => e
say_error "Error querying get_user_by_id(#{user_id})"
say_error e
raise
end
user
end

def query(query_id)
data = nil
begin
Expand Down Expand Up @@ -389,6 +401,66 @@ def field_expression(name)
parts.join('&.')
end


# This version of field names yields an expression that can be evaluated against a hash structure
# like this one...
#
# data&.fetch(:a,nil)
# val1
# data&.fetch(:b,nil)
# val2
# data&.fetch(:c,nil)&.fetch(:d,nil)
# val3
# data&.fetch(:c,nil)&.fetch(:e,nil)&.fetch(:f,nil)
# val4
# data&.fetch(:c,nil)&.fetch(:e,nil)&.fetch(:g,nil)
# val5
# data&.fetch(:h,nil)
# val6
#
# data =
# {
# a: "val",
# b: "val",
# c: {
# d: "val",
# e: {
# f: "val",
# g: "val"
# }
# },
# h: "val"
# }
#
# field_names_hash(fields).each do |field|
# puts "data#{field}"
# puts eval "data#{field}"
# end

def field_names_hash(opt_fields)
fields = []
token_stack = []
last_token = false
tokens = opt_fields.split /(\(|,|\))/
tokens << nil
tokens.each do |t|
if t == '(' then
token_stack.push(last_token)
elsif t.nil? || t == ',' then
fields << "&.fetch(:#{(token_stack + [last_token]).join(',nil)&.fetch(:')},nil)" if last_token
elsif t.empty? then
next
elsif t == ')' then
fields << "&.fetch(:#{(token_stack + [last_token]).join(',nil)&.fetch(:')},nil)" if last_token
token_stack.pop
last_token = false
else
last_token = t
end
end
fields
end

##
# This method will accept two arrays, a and b, and create a third array
# like [ [a[0],b[0]], [a[1],b[1]], [a[2],b[2]], ...].
Expand Down
200 changes: 200 additions & 0 deletions lib/gzr/commands/alert.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
# The MIT License (MIT)

# Copyright (c) 2023 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 'thor'

module Gzr
module Commands
class Alert < Thor

namespace :alert

desc 'ls', 'list alerts'
method_option :help, aliases: '-h', type: :boolean,
desc: 'Display usage information'
method_option :fields, type: :string, default: 'id,field(title,name),comparison_type,threshold,cron,custom_title,dashboard_element_id,description',
desc: 'Fields to display'
method_option :disabled, type: :boolean, default: nil,
desc: 'return disabled alerts'
method_option :all, type: :boolean, default: nil,
desc: 'return alerts from all users (must be admin)'
method_option :plain, type: :boolean, default: false,
desc: 'print without any extra formatting'
method_option :csv, type: :boolean, default: false,
desc: 'output in csv format per RFC4180'
def ls(*)
if options[:help]
invoke :help, ['ls']
else
require_relative 'alert/ls'
Gzr::Commands::Alert::Ls.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'
method_option :dir, type: :string,
desc: 'Directory to store output file'
def cat(alert_id)
if options[:help]
invoke :help, ['cat']
else
require_relative 'alert/cat'
Gzr::Commands::Alert::Cat.new(alert_id,options).execute
end
end

desc 'follow ALERT_ID', 'Start following the alert given by ALERT_ID'
method_option :help, aliases: '-h', type: :boolean,
desc: 'Display usage information'
def follow_alert(alert_id)
if options[:help]
invoke :help, ['follow']
else
require_relative 'alert/follow'
Gzr::Commands::Alert::Follow.new(alert_id,options).execute
end
end

desc 'unfollow ALERT_ID', 'Stop following the alert given by ALERT_ID'
method_option :help, aliases: '-h', type: :boolean,
desc: 'Display usage information'
def unfollow_alert(alert_id)
if options[:help]
invoke :help, ['unfollow']
else
require_relative 'alert/unfollow'
Gzr::Commands::Alert::Unfollow.new(alert_id,options).execute
end
end

desc 'enable ALERT_ID', 'Enable the alert given by ALERT_ID'
method_option :help, aliases: '-h', type: :boolean,
desc: 'Display usage information'
def enable(alert_id)
if options[:help]
invoke :help, ['enable']
else
require_relative 'alert/enable'
Gzr::Commands::Alert::Enable.new(alert_id,options).execute
end
end

desc 'disable ALERT_ID REASON', 'Disable the alert given by ALERT_ID'
method_option :help, aliases: '-h', type: :boolean,
desc: 'Display usage information'
def disable(alert_id,reason)
if options[:help]
invoke :help, ['disable']
else
require_relative 'alert/disable'
Gzr::Commands::Alert::Disable.new(alert_id,reason,options).execute
end
end

desc 'threshold ALERT_ID THRESHOLD', 'Change the threshold of the alert given by ALERT_ID'
method_option :help, aliases: '-h', type: :boolean,
desc: 'Display usage information'
def threshold(alert_id,threshold)
if options[:help]
invoke :help, ['threshold']
else
require_relative 'alert/threshold'
Gzr::Commands::Alert::Threshold.new(alert_id,threshold,options).execute
end
end

desc 'rm ALERT_ID', 'Delete the alert given by ALERT_ID'
method_option :help, aliases: '-h', type: :boolean,
desc: 'Display usage information'
def rm(alert_id)
if options[:help]
invoke :help, ['delete']
else
require_relative 'alert/delete'
Gzr::Commands::Alert::Delete.new(alert_id,options).execute
end
end

desc 'chown ALERT_ID OWNER_ID', 'Change the owner of the alert given by ALERT_ID to OWNER_ID'
method_option :help, aliases: '-h', type: :boolean,
desc: 'Display usage information'
def chown(alert_id, owner_id)
if options[:help]
invoke :help, ['chown']
else
require_relative 'alert/chown'
Gzr::Commands::Alert::Chown.new(alert_id,owner_id,options).execute
end
end

desc 'notifications', 'Get notifications'
method_option :help, aliases: '-h', type: :boolean,
desc: 'Display usage information'
method_option :plain, type: :boolean, default: false,
desc: 'print without any extra formatting'
method_option :csv, type: :boolean, default: false,
desc: 'output in csv format per RFC4180'
def notifications(*)
if options[:help]
invoke :help, ['notifications']
else
require_relative 'alert/notifications'
Gzr::Commands::Alert::Notifications.new(options).execute
end
end

desc 'read NOTIFICATION_ID', 'Read notification id'
method_option :help, aliases: '-h', type: :boolean,
desc: 'Display usage information'
method_option :plain, type: :boolean, default: false,
desc: 'print without any extra formatting'
method_option :csv, type: :boolean, default: false,
desc: 'output in csv format per RFC4180'
def read(notification_id)
if options[:help]
invoke :help, ['read']
else
require_relative 'alert/read'
Gzr::Commands::Alert::Read.new(notification_id,options).execute
end
end

desc 'import FILE [DASHBOARD_ELEMENT_ID]', 'Import an alert from a file'
method_option :help, aliases: '-h', type: :boolean,
desc: 'Display usage information'
method_option :plain, type: :boolean,
desc: 'Provide minimal response information'
def import(file,dashboard_element_id=nil)
if options[:help]
invoke :help, ['import']
else
require_relative 'alert/import'
Gzr::Commands::Alert::Import.new(file, dashboard_element_id, options).execute
end
end

end
end
end
52 changes: 52 additions & 0 deletions lib/gzr/commands/alert/cat.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# The MIT License (MIT)

# Copyright (c) 2023 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/filehelper'

module Gzr
module Commands
class Alert
class Cat < Gzr::Command
include Gzr::Alert
include Gzr::FileHelper
def initialize(alert_id,options)
super()
@alert_id = alert_id
@options = options
end

def execute(input: $stdin, output: $stdout)
say_warning(@options) if @options[:debug]
with_session do
alert = get_alert(@alert_id)
write_file(@options[:dir] ? "Alert_#{alert.id}_#{alert.field.name}.json" : nil, @options[:dir],nil, output) do |f|
f.puts JSON.pretty_generate(alert.to_attrs)
end
end
end
end
end
end
end
Loading

0 comments on commit 74d0307

Please sign in to comment.