Skip to content

Commit

Permalink
feat: Plan randomization
Browse files Browse the repository at this point in the history
  • Loading branch information
drstrangelooker committed Jun 12, 2024
1 parent 022f3e9 commit 3176fe0
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 0 deletions.
16 changes: 16 additions & 0 deletions lib/gzr/commands/plan.rb
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,22 @@ def ls(*)
Gzr::Commands::Plan::Ls.new(options).execute
end
end

desc 'randomize', 'Randomize the scheduled plans 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 plans regardless of owner'
def randomize(*)
if options[:help]
invoke :help, ['randomize']
else
require_relative 'plan/randomize'
Gzr::Commands::Plan::Randomize.new(options).execute
end
end
end
end
end
72 changes: 72 additions & 0 deletions lib/gzr/commands/plan/randomize.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# 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/plan'
require_relative '../../modules/user'
require_relative '../../modules/cron'

module Gzr
module Commands
class Plan
class Randomize < Gzr::Command
include Gzr::Plan
include Gzr::User
include Gzr::Cron
def initialize(options)
super()
@options = options
end

def execute(input: $stdin, output: $stdout)
say_warning("options: #{@options.inspect}") 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")

plans = query_all_scheduled_plans( @options[:all]?'all':@me[:id] )
plans.each do |plan|
crontab = plan[:crontab]
if crontab == ""
say_warning("skipping plan #{plan[:id]} with no crontab")
next
end
crontab = randomize_cron(crontab, window)
begin
update_scheduled_plan(plan[:id], { crontab: crontab })
rescue LookerSDK::UnprocessableEntity => e
say_warning("Skipping invalid entry")
end
end
end
end
end
end
end
end
51 changes: 51 additions & 0 deletions lib/gzr/modules/cron.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# 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

module Gzr
module Cron
def randomize_cron(crontab, window=60)
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
return cronfields.join(' ')
end
end
end
40 changes: 40 additions & 0 deletions spec/integration/plan/randomize_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# 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 plan randomize` command", type: :cli do
it "executes `gzr plan help randomize` command successfully" do
output = `gzr plan help randomize`
expected_output = <<-OUT
Usage:
gzr plan randomize
Options:
-h, [--help], [--no-help] # Display usage information
[--window=N] # Length of window
# Default: 60
[--all], [--no-all] # Randomize all plans regardless of owner
Randomize the scheduled plans on a server
OUT

expect(output).to eq(expected_output)
end
end
1 change: 1 addition & 0 deletions spec/integration/plan_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
gzr plan help [COMMAND] # Describe subcommands or one specific subcommand
gzr plan import PLAN_FILE OBJ_TYPE OBJ_ID # Import a plan from a file
gzr plan ls # List the scheduled plans on a server
gzr plan randomize # Randomize the scheduled plans on a server
gzr plan rm PLAN_ID # Delete a scheduled plan
gzr plan runit PLAN_ID # Execute a saved plan immediately
Expand Down

0 comments on commit 3176fe0

Please sign in to comment.