diff options
author | Patrick J Cherry <patrick@bytemark.co.uk> | 2012-04-25 17:15:49 +0100 |
---|---|---|
committer | Patrick J Cherry <patrick@bytemark.co.uk> | 2012-04-25 17:15:49 +0100 |
commit | e959c0fe4c887154bbe28c31324fef2975cbe467 (patch) | |
tree | 3088c7a1f389944d613e57b551b452f7ec83181d /lib | |
parent | 5fff12fc11cb8b02a44fd40ed78fa9d196f269d7 (diff) |
Big update.
* Max acknowledgement time is now specified in the config
* Calendar interface improved.
* holiday_url no longer used -- replaced by notify_when_on_holiday!
* added notify_when_off_sick!
* Added ability for the calendar to be queried for a list of bank holdays.
* Added ability for Time to be given a list of bank holidays to check against.
* PeopleLists can now be a Proc, allowing downloading of lists
* Person is no longer a struct
* Moved the method_missing bit into ObjectBuilder from various sub classes.
* Added tests for the calendar interface
* Updated tests in other bits.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/mauve/alert.rb | 2 | ||||
-rw-r--r-- | lib/mauve/authentication.rb | 10 | ||||
-rw-r--r-- | lib/mauve/calendar_interface.rb | 100 | ||||
-rw-r--r-- | lib/mauve/configuration.rb | 113 | ||||
-rw-r--r-- | lib/mauve/configuration_builder.rb | 12 | ||||
-rw-r--r-- | lib/mauve/configuration_builders/notification_method.rb | 12 | ||||
-rw-r--r-- | lib/mauve/configuration_builders/person.rb | 6 | ||||
-rw-r--r-- | lib/mauve/configuration_builders/server.rb | 25 | ||||
-rw-r--r-- | lib/mauve/mauve_time.rb | 28 | ||||
-rw-r--r-- | lib/mauve/notification.rb | 3 | ||||
-rw-r--r-- | lib/mauve/notifiers/xmpp.rb | 5 | ||||
-rw-r--r-- | lib/mauve/people_list.rb | 10 | ||||
-rw-r--r-- | lib/mauve/person.rb | 124 | ||||
-rw-r--r-- | lib/mauve/processor.rb | 14 | ||||
-rw-r--r-- | lib/mauve/server.rb | 112 | ||||
-rw-r--r-- | lib/mauve/web_interface.rb | 19 | ||||
-rw-r--r-- | lib/object_builder.rb | 14 |
17 files changed, 381 insertions, 228 deletions
diff --git a/lib/mauve/alert.rb b/lib/mauve/alert.rb index f249913..6b08f82 100644 --- a/lib/mauve/alert.rb +++ b/lib/mauve/alert.rb @@ -420,7 +420,7 @@ module Mauve # # Limit acknowledgment time. # - limit = Time.now + 15.days + limit = Time.now + Configuration.current.max_acknowledgement_time ack_until = limit if ack_until > limit self.acknowledged_by = person.username diff --git a/lib/mauve/authentication.rb b/lib/mauve/authentication.rb index c467a1d..24c6bd3 100644 --- a/lib/mauve/authentication.rb +++ b/lib/mauve/authentication.rb @@ -70,7 +70,7 @@ module Mauve unless true == result logger.info "Authentication for #{login} failed" # Rate limit - sleep Server.instance.failed_login_delay + sleep Configuration.current.failed_login_delay end result @@ -97,15 +97,15 @@ module Mauve # # Don't bother checking if no auth_url has been set. # - return false unless Server.instance.bytemark_auth_url.is_a?(URI) + return false unless Configuration.current.bytemark_auth_url.is_a?(URI) # # Don't bother checking if the person doesn't exist. # return false unless Mauve::Configuration.current.people.has_key?(login) - uri = Server.instance.bytemark_auth_url - timeout = Server.instance.remote_http_timeout + uri = Configuration.current.bytemark_auth_url + timeout = Configuration.current.remote_http_timeout # host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil, user=nil, password=nil, use_ssl=nil, timeout=nil) client = XMLRPC::Client.new(uri.host, uri.path, uri.port, nil, nil, uri.user, uri.password, uri.scheme == "https", timeout) @@ -114,7 +114,7 @@ module Mauve # if client.http.use_ssl? client.http.ca_path = "/etc/ssl/certs/" - client.http.verify_mode = Server.instance.remote_https_verify_mode + client.http.verify_mode = Configuration.current.remote_https_verify_mode end begin diff --git a/lib/mauve/calendar_interface.rb b/lib/mauve/calendar_interface.rb index cf515d1..692981d 100644 --- a/lib/mauve/calendar_interface.rb +++ b/lib/mauve/calendar_interface.rb @@ -17,52 +17,58 @@ module Mauve @logger ||= Log4r::Logger.new(self.to_s) end - # Gets a list of ssologin on support. + def get_attendees(klass, at=Time.now) + # + # Returns nil if no calendar_url has been set. + # + return [] unless Configuration.current.bytemark_calendar_url + + url = Configuration.current.bytemark_calendar_url.dup + + url.merge!(File.join(url.path, "/api/attendees/#{klass}/#{at.strftime("%Y-%m-%dT%H:%M:00")}")) + ans = do_get(url) + + return [] unless ans.is_a?(Array) + + ans.select{|x| x.is_a?(String)} + end + # - # @param [String] url A Calendar API url. + # This should return a list of dates of forthcoming bank holidays # - # @return [Array] A list of all the usernames on support. - def get_users_on_support(url) - result = do_get_with_cache(url) - - if result.is_a?(String) - result = result.split("\n") - else - result = [] - end + def get_bank_holiday_list(at = Time.now) + return [] unless Configuration.current.bytemark_calendar_url - return result + url = Configuration.current.bytemark_calendar_url.dup + url.merge!(File.join(url.path, "/api/bank_holidays/#{at.strftime("%Y-%m-%d")}")) + ans = do_get(url) + + return [] unless ans.is_a?(Array) + ans.select{|x| x.is_a?(Date)} end - # Check to see if the user is on support. + # Check to see if the user is on holiday. # - # @param [String] url A Calendar API url. - # @param [String] usr User single sign on. + # Class method. # - # @return [Boolean] True if on support, false otherwise. - def is_user_on_support?(url, usr) - return get_users_on_support(url).include?(usr) + # @param [String] usr User single sign on. + # + # @return [Boolean] True if on holiday, false otherwise. + def is_user_on_holiday?(usr, at=Time.now) + get_attendees("staff_holiday").include?(usr) end # Check to see if the user is on holiday. # # Class method. # - # @param [String] url A Calendar API url. # @param [String] usr User single sign on. # # @return [Boolean] True if on holiday, false otherwise. - def is_user_on_holiday?(url) - result = do_get_with_cache(url) - - if result.is_a?(String) and result =~ /^\d{4}(-\d\d){2}[ T](\d\d:){2}\d\d/ - return true - else - return false - end + def is_user_off_sick?(usr, at=Time.now) + get_attendees("sick_period", at).include?(usr) end - private # Grab a URL from the wide web. @@ -74,7 +80,7 @@ module Mauve # def do_get (uri, limit = 11) - if 0 == limit + if 0 > limit logger.warn("HTTP redirect too deep for #{uri}.") return nil end @@ -99,8 +105,22 @@ module Mauve response = http.start { http.get(uri.request_uri()) } if response.is_a?(Net::HTTPOK) - return response.body + # + # Parse the string as YAML. + # + result = if response.body.is_a?(String) + begin + YAML.load(response.body) + rescue YAML::Error => err + logger.error "Caught #{ex.class.to_s} (#{ex.to_s}) whilst querying #{url.to_s}." + logger.debug err.backtrace.join("\n") + nil + end + else + nil + end + return result elsif response.is_a?(Net::HTTPRedirection) and response.key?('Location') location = response['Location'] @@ -123,6 +143,7 @@ module Mauve logger.error("Timeout caught during fetch of #{uri.to_s}.") rescue StandardError => ex + pp ex.backtrace logger.error("#{ex.class} caught during fetch of #{uri.to_s}: #{ex.to_s}.") logger.debug(ex.backtrace.join("\n")) @@ -140,10 +161,10 @@ module Mauve def do_get_with_cache(url, cache_until = Time.now + 5.minutes) @cache ||= {} - if @cache.has_key?(url.to_s) - result, cache_until = @cache[url.to_s] + if @cache.has_key?(url) + result, cached_until = @cache[url] - return result if cache_until >= Time.now and not result.nil? + return result if cached_until > Time.now and not result.nil? end result = do_get(url) @@ -152,6 +173,19 @@ module Mauve return result end + # + # This should get called periodically. + # + def clean_cache + + @cache.keys.select do |url| + result, cached_until = @cache[url] + @cache.delete(url) if !cached_until.is_a?(Time) or cached_until <= Time.now + end + + @cache + end + end end diff --git a/lib/mauve/configuration.rb b/lib/mauve/configuration.rb index 65f5f71..3a8f9cc 100644 --- a/lib/mauve/configuration.rb +++ b/lib/mauve/configuration.rb @@ -40,6 +40,12 @@ module Mauve # @return [Hash] attr_reader :source_lists + # Various further configuration items + # + attr_reader :bytemark_auth_url, :bytemark_calendar_url, :remote_http_timeout, :remote_https_verify_mode, :failed_login_delay + attr_reader :max_acknowledgement_time + + # # Set up a base config. # @@ -50,7 +56,114 @@ module Mauve @people_lists = {} @source_lists = Hash.new{|h,k| h[k] = Mauve::SourceList.new(k)} @alert_groups = [] + + # + # Set the auth/calendar URLs + # + @bytemark_auth_url = nil + @bytemark_calendar_url = nil + + # + # Set a couple of params for remote HTTP requests. + # + @remote_http_timeout = 5 + @remote_https_verify_mode = OpenSSL::SSL::VERIFY_PEER + + # + # Rate limit login attempts to limit the success of brute-forcing. + # + @failed_login_delay = 1 + + # + # Maximum amount of time to acknowledge for + # + @max_acknowledgement_time = 15.days + end + + # Set the calendar URL. + # + # @param [String] arg + # @return [URI] + def bytemark_calendar_url=(arg) + raise ArgumentError, "bytemark_calendar_url must be a string" unless arg.is_a?(String) + + @bytemark_calendar_url = URI.parse(arg) + + # + # Make sure we get an HTTP URL. + # + raise ArgumentError, "bytemark_calendar_url must be an HTTP(S) URL." unless %w(http https).include?(@bytemark_calendar_url.scheme) + + # + # Set a default request path, if none was given + # + @bytemark_calendar_url.normalize! + + @bytemark_calendar_url + end + + # Set the Bytemark Authentication URL + # + # @param [String] arg + # @return [URI] + def bytemark_auth_url=(arg) + raise ArgumentError, "bytemark_auth_url must be a string" unless arg.is_a?(String) + + @bytemark_auth_url = URI.parse(arg) + # + # Make sure we get an HTTP URL. + # + raise ArgumentError, "bytemark_auth_url must be an HTTP(S) URL." unless %w(http https).include?(@bytemark_auth_url.scheme) + + # + # Set a default request path, if none was given + # + @bytemark_auth_url.normalize! + + @bytemark_auth_url + end + + # Sets the timeout when making remote HTTP requests + # + # @param [Integer] arg + # @return [Integer] + def remote_http_timeout=(arg) + raise ArgumentError, "remote_http_timeout must be an integer" unless s.is_a?(Integer) + @remote_http_timeout = arg + end + + # Sets the SSL verification mode when makeing remote HTTPS requests + # + # @param [String] arg must be one of "none" or "peer" + # @return [Constant] + def remote_https_verify_mode=(arg) + @remote_https_verify_mode = case arg + when "peer" + OpenSSL::SSL::VERIFY_PEER + when "none" + OpenSSL::SSL::VERIFY_NONE + else + raise ArgumentError, "remote_https_verify_mode must be either 'peer' or 'none'" + end + end + + # Set the delay added following a failed login attempt. + # + # @param [Numeric] arg Number of seconds to delay following a failed login attempt + # @return [Numeric] + # + def failed_login_delay=(arg) + raise ArgumentError, "failed_login_delay must be numeric" unless arg.is_a?(Numeric) + @failed_login_delay = arg end + # Set the maximum amount of time alerts can be ack'd for + # + # + def max_acknowledgement_time=(arg) + raise ArgumentError, "max_acknowledgement_time must be numeric" unless arg.is_a?(Numeric) + @max_acknowledgement_time = arg + end + end end diff --git a/lib/mauve/configuration_builder.rb b/lib/mauve/configuration_builder.rb index 3f7138e..c689c1b 100644 --- a/lib/mauve/configuration_builder.rb +++ b/lib/mauve/configuration_builder.rb @@ -29,18 +29,6 @@ module Mauve @result.source_lists[label] += list end - # Adds a people list - # - # @param [String] label - # @param [Array] list - # - # @return [Array] the whole people list for label - # ef people_list(label, *list) - # _logger.warn("Duplicate people_list '#{label}'") if @result.people_lists.has_key?(label) - # @result.people_lists[label] += list - # end - - # Have to use the method _logger here, cos logger is defined as a builder elsewhere. # # @return [Log4r::Logger] diff --git a/lib/mauve/configuration_builders/notification_method.rb b/lib/mauve/configuration_builders/notification_method.rb index 3f9283e..7951dee 100644 --- a/lib/mauve/configuration_builders/notification_method.rb +++ b/lib/mauve/configuration_builders/notification_method.rb @@ -40,18 +40,6 @@ module Mauve result.extend(Mauve::Notifiers::Debug) end - # This catches all methods available for a provider, as needed. - # - # Missing methods / bad arguments etc. are caught in the - # ObjectBuilder#parse method, via NoMethodError. - # - def method_missing(name, value=nil) - if value - result.send("#{name}=".to_sym, value) - else - result.send(name.to_sym) - end - end end end diff --git a/lib/mauve/configuration_builders/person.rb b/lib/mauve/configuration_builders/person.rb index dff6f85..7a20491 100644 --- a/lib/mauve/configuration_builders/person.rb +++ b/lib/mauve/configuration_builders/person.rb @@ -18,12 +18,14 @@ module Mauve is_block_attribute "urgent" is_block_attribute "normal" is_block_attribute "low" + is_attribute "password" is_attribute "sms" - is_attribute "holiday_url" is_attribute "email" is_attribute "xmpp" - is_attribute "sms" + + is_flag_attribute "notify_when_on_holiday!" + is_flag_attribute "notify_when_off_sick!" # Sets the block for all levels of alert # diff --git a/lib/mauve/configuration_builders/server.rb b/lib/mauve/configuration_builders/server.rb index d22ed87..734fb3b 100644 --- a/lib/mauve/configuration_builders/server.rb +++ b/lib/mauve/configuration_builders/server.rb @@ -171,31 +171,6 @@ module Mauve is_attribute "use_packet_buffer" is_attribute "use_notification_buffer" - # - # This is where the calendar is located. The request paths are hard-coded. - # - is_attribute "bytemark_calendar_url" - - # - # This is where the Bytemark authentication server is located. - # - is_attribute "bytemark_auth_url" - - # - # This is the level of SSL verification used when making external HTTPS connections. - # - is_attribute "remote_https_verify_mode" - - # - # This is the default timeout when making remote HTTP requests - # - is_attribute "remote_http_timeout" - - # - # This is the default sleep time after an authentication attempt has failed. - # - is_attribute "failed_login_delay" - def builder_setup @result = Mauve::Server.instance end diff --git a/lib/mauve/mauve_time.rb b/lib/mauve/mauve_time.rb index f564fdb..dfbf99b 100644 --- a/lib/mauve/mauve_time.rb +++ b/lib/mauve/mauve_time.rb @@ -98,12 +98,37 @@ class Time t end + # Returns the bank_holidays array, or an empty array if bank_holidays hasn't + # been set. + # + # + def bank_holidays + @bank_holidays ||= [] + end + + # This sets the bank holiday dates for the bank_holiday? check. + # + # @param [Array] arg An array of Date of bank holidays + # @returns [Array] + # + def bank_holidays=(arg) + raise ArgumentError unless arg.is_a?(Array) and arg.all?{|a| a.is_a?(Date)} + @bank_holidays = arg + end + + # This relies on bank_holidays being set. + # + def bank_holiday? + today = Date.new(self.year, self.month, self.day) + self.bank_holidays.any?{|bh| bh == today} + end + # Test to see if we're in working hours. The working day is from 8.30am until # 17:00 # # @return [Boolean] def working_hours? - (1..5).include?(self.wday) and ((9..16).include?(self.hour) or (self.hour == 8 && self.min >= 30)) + !bank_holiday? and (1..5).include?(self.wday) and ((9..16).include?(self.hour) or (self.hour == 8 && self.min >= 30)) end # Test to see if it is currently daytime. The daytime day is 14 hours long @@ -113,7 +138,6 @@ class Time (8..21).include?(self.hour) end - # We're always in wallclock hours # # @return [true] diff --git a/lib/mauve/notification.rb b/lib/mauve/notification.rb index d06e03a..5877e0f 100644 --- a/lib/mauve/notification.rb +++ b/lib/mauve/notification.rb @@ -163,8 +163,9 @@ module Mauve # Test to see if we're in working hours. See Time#working_hours? # # @return [Boolean] - def working_hours? + def working_hours? @test_time = @time if @test_time.nil? + @test_time.bank_holidays = Server.instance.bank_holidays @test_time.working_hours? end diff --git a/lib/mauve/notifiers/xmpp.rb b/lib/mauve/notifiers/xmpp.rb index a0ad86e..b291442 100644 --- a/lib/mauve/notifiers/xmpp.rb +++ b/lib/mauve/notifiers/xmpp.rb @@ -604,7 +604,10 @@ EOF end begin - ack_until = Time.now.in_x_hours(n_hours, type_hours) + now = Time.now + now.bank_holidays = Server.instance.bank_holidays + + ack_until = now.in_x_hours(n_hours, type_hours) rescue RangeError return "I'm sorry, you tried to acknowedge for far too long, and my buffers overflowed!" end diff --git a/lib/mauve/people_list.rb b/lib/mauve/people_list.rb index eab4ae3..0433034 100644 --- a/lib/mauve/people_list.rb +++ b/lib/mauve/people_list.rb @@ -35,6 +35,8 @@ module Mauve arr = arr.flatten when String arr = [arr] + when Proc + arr = [arr] else logger.warn "Not sure what to do with #{arr.inspect} -- converting to string, and continuing" arr = [arr.to_s] @@ -62,10 +64,12 @@ module Mauve # # @return [Array] def people - l = list.collect do |name| - Configuration.current.people.has_key?(name) ? Configuration.current.people[name] : nil - end.reject{|person| person.nil?} + name.is_a?(Proc) ? name.call : name + end.flatten.compact.uniq.collect do |name| + Configuration.current.people[name] + end.compact + # # Hmm.. no-one in the list?! # diff --git a/lib/mauve/person.rb b/lib/mauve/person.rb index 1cf4ea0..929f511 100644 --- a/lib/mauve/person.rb +++ b/lib/mauve/person.rb @@ -3,23 +3,15 @@ require 'timeout' require 'log4r' module Mauve - class Person < Struct.new(:username, :password, :urgent, :normal, :low, :email, :xmpp, :sms) + class Person + attr_reader :username, :password, :urgent, :normal, :low, :email, :xmpp, :sms attr_reader :notification_thresholds, :last_pop3_login, :suppressed, :notifications - + attr_reader :notify_when_off_sick, :notify_when_on_holiday + # Set up a new Person # - # @param [Hash] args The options for setting up the person - # @option args [String] :username The person's username - # @option args [String] :password The SHA1 sum of the person's password - # @option args [String] :holiday_url The URL that can be checked by Mauve::CalendarInterface#is_user_on_holiday? - # @option args [Proc] :urgent The block to execute when an urgent-level notification is issued - # @option args [Proc] :normal The block to execute when an normal-level notification is issued - # @option args [Proc] :low The block to execute when an low-level notification is issued - # @option args [String] :email The person's email address - # @option args [String] :sms The person's mobile number - # - def initialize(*args) + def initialize(username) @notification_thresholds = nil @suppressed = false # @@ -28,9 +20,85 @@ module Mauve @last_pop3_login = {:from => nil, :at => nil} @notifications = [] - super(*args) - end + @username = username + @password = nil + @urgent = lambda { false } + @normal = lambda { false } + @low = lambda { false } + @email = @sms = @xmpp = nil + @notify_when_on_holiday = @notify_when_off_sick = false + end + + # Determines if a user should be notified if they're ill. + # + # @return [Boolean] + # + def notify_when_off_sick! + @notify_when_off_sick = true + end + + # Determines if a user should be notified if they're on their holdiays. + # + # @return [Boolean] + # + def notify_when_on_holiday! + @notify_when_on_holiday = true + end + + # Sets the Proc to call for urgent notifications + # + def urgent=(block) + raise ArgumentError unless block.is_a?(Proc) + @urgent = block + end + + # Sets the Proc to call for normal notifications + # + def normal=(block) + raise ArgumentError unless block.is_a?(Proc) + @normal = block + end + + # Sets the Proc to call for low notifications + # + def low=(block) + raise ArgumentError unless block.is_a?(Proc) + @low = block + end + + # Sets the email parameter + # + # + def email=(arg) + raise ArgumentError unless arg.is_a?(String) + @email = arg + end + + # Sets the sms parameter + # + # + def sms=(arg) + raise ArgumentError unless arg.is_a?(String) + @sms = arg + end + + # Sets the xmpp parameter + # + # + def xmpp=(arg) + raise ArgumentError unless arg.is_a?(String) + @xmpp = arg + end + + # Sets the password parameter + # + # + def password=(arg) + raise ArgumentError unless arg.is_a?(String) + @password=arg + end + # @return Log4r::Logger def logger ; @logger ||= Log4r::Logger.new self.class.to_s ; end @@ -39,8 +107,6 @@ module Mauve # @return [Boolean] def suppressed? ; @suppressed ; end - def holiday_url ; nil ; end - # Works out if a notification should be suppressed. If no parameters are supplied, it will # # @param [Time] Theoretical time of notification @@ -155,8 +221,7 @@ module Mauve # @param [Mauve::Alert] alert Alert we're notifiying about # # @return [Boolean] if the notification was successful - def send_alert(level, alert) - now = Time.now + def send_alert(level, alert, now=Time.now) was_suppressed = @suppressed @suppressed = self.should_suppress? @@ -168,7 +233,7 @@ module Mauve # We only suppress notifications if we were suppressed before we started, # and are still suppressed. # - if @suppressed or self.is_on_holiday? + if @suppressed or self.is_on_holiday?(now) or self.is_off_sick?(now) note = "#{alert.update_type.capitalize} notification to #{self.username} suppressed" logger.info note + " about #{alert}." History.create(:alerts => [alert], :type => "notification", :event => note) @@ -217,20 +282,19 @@ module Mauve end end - # - # - # - def alert_during - - end - # Whether the person is on holiday or not. # # @return [Boolean] True if person on holiday, false otherwise. - def is_on_holiday? () - return false if holiday_url.nil? or holiday_url.empty? + def is_on_holiday?(at=Time.now) + return false if self.notify_when_on_holiday + + return CalendarInterface.is_user_on_holiday?(self.username, at) + end + + def is_off_sick?(at=Time.now) + return false if self.notify_when_off_sick - return CalendarInterface.is_user_on_holiday?(holiday_url) + return CalendarInterface.is_user_off_sick?(self.username, at) end end diff --git a/lib/mauve/processor.rb b/lib/mauve/processor.rb index 0ac7b59..acf72b3 100644 --- a/lib/mauve/processor.rb +++ b/lib/mauve/processor.rb @@ -57,14 +57,11 @@ module Mauve to_delete = [] - @transmission_id_cache.each do |tid, received_at| - to_delete << tid if (now - received_at) > @transmission_cache_expire_time + @transmission_id_cache = @transmission_id_cache.delete_if do |cache_data| + tid, received_at = cache_data + (now - received_at) > @transmission_cache_expire_time end - to_delete.each do |tid| - @transmission_id_cache.delete(tid) - end - @transmission_cache_checked_at = now end @@ -197,6 +194,11 @@ module Mauve sz.times do process_packet(*Server.packet_pop) end + + # + # Now expire the cache. This will only get processed at most once every minute. + # + expire_transmission_id_cache end def timer_should_stop? diff --git a/lib/mauve/server.rb b/lib/mauve/server.rb index 2b0e101..366191c 100644 --- a/lib/mauve/server.rb +++ b/lib/mauve/server.rb @@ -50,21 +50,10 @@ module Mauve @notification_buffer = [] # - # Set the auth/calendar URLs + # Bank Holidays -- this list is kept here, because I can't think of + # anywhere else to put it. # - @bytemark_auth_url = nil - @bytemark_calendar_url = nil - - # - # Set a couple of params for remote HTTP requests. - # - @remote_http_timeout = 5 - @remote_https_verify_mode = OpenSSL::SSL::VERIFY_PEER - - # - # Rate limit login attempts to limit the success of brute-forcing. - # - @failed_login_delay = 1 + @bank_holidays = nil # # Set up a blank config. @@ -114,83 +103,6 @@ module Mauve @notification_buffer end - # Set the calendar URL. - # - # @param [String] arg - # @return [URI] - def bytemark_calendar_url=(arg) - raise ArgumentError, "bytemark_calendar_url must be a string" unless arg.is_a?(String) - - @bytemark_calendar_url = URI.parse(arg) - - # - # Make sure we get an HTTP URL. - # - raise ArgumentError, "bytemark_calendar_url must be an HTTP(S) URL." unless %w(http https).include?(@bytemark_calendar_url.scheme) - - # - # Set a default request path, if none was given - # - @bytemark_calendar_url.path="/" if @bytemark_calendar_url.path.empty? - - @bytemark_calendar_url - end - - # Set the Bytemark Authentication URL - # - # @param [String] arg - # @return [URI] - def bytemark_auth_url=(arg) - raise ArgumentError, "bytemark_auth_url must be a string" unless arg.is_a?(String) - - @bytemark_auth_url = URI.parse(arg) - # - # Make sure we get an HTTP URL. - # - raise ArgumentError, "bytemark_auth_url must be an HTTP(S) URL." unless %w(http https).include?(@bytemark_auth_url.scheme) - - # - # Set a default request path, if none was given - # - @bytemark_auth_url.path="/" if @bytemark_auth_url.path.empty? - - @bytemark_auth_url - end - - # Sets the timeout when making remote HTTP requests - # - # @param [Integer] arg - # @return [Integer] - def remote_http_timeout=(arg) - raise ArgumentError, "initial_sleep must be an integer" unless s.is_a?(Integer) - @remote_http_timeout = arg - end - - # Sets the SSL verification mode when makeing remote HTTPS requests - # - # @param [String] arg must be one of "none" or "peer" - # @return [Constant] - def remote_https_verify_mode=(arg) - @remote_https_verify_mode = case arg - when "peer" - OpenSSL::SSL::VERIFY_PEER - when "none" - OpenSSL::SSL::VERIFY_NONE - else - raise ArgumentError, "remote_https_verify_mode must be either 'peer' or 'none'" - end - end - - # Set the delay added following a failed login attempt. - # - # @param [Numeric] arg Number of seconds to delay following a failed login attempt - # @return [Numeric] - # - def failed_login_delay=(arg) - raise ArgumentError, "initial_sleep must be numeric" unless arg.is_a?(Numeric) - @failed_login_delay = arg - end - # Set the sleep period during which notifications about old alerts are # suppressed. # @@ -207,6 +119,24 @@ module Mauve Time.now < self.started_at + self.initial_sleep end + # Check with the calendar for the list of bank holidays + # + # + def bank_holidays + # + # Update the bank holidays list hourly. + # + if @bank_holidays.nil? or + @bank_holidays_last_checked_at.nil? or + @bank_holidays_last_checked_at < (Time.now - 1.hour) + + @bank_holidays = CalendarInterface.get_bank_holiday_list(Time.now) + @bank_holidays_last_checked_at = Time.now + end + + @bank_holidays + end + # return [Log4r::Logger] def logger @logger ||= Log4r::Logger.new(self.class.to_s) diff --git a/lib/mauve/web_interface.rb b/lib/mauve/web_interface.rb index 16e7da2..a8e1ece 100644 --- a/lib/mauve/web_interface.rb +++ b/lib/mauve/web_interface.rb @@ -218,9 +218,13 @@ EOF note = params[:note] || nil n_hours = (n_hours.to_f > 188 ? 188 : n_hours.to_f) + type_hours = "daytime" unless %w(daytime working wallclock).include?(type_hours) if ack_until.to_s.empty? - ack_until = Time.now.in_x_hours(n_hours, type_hours.to_s) + now = Time.now + now.bank_holidays = Server.instance.bank_holidays + + ack_until = now.in_x_hours(n_hours, type_hours.to_s) else ack_until = Time.at(ack_until.to_i) end @@ -275,12 +279,14 @@ EOF # n_hours = ( n_hours > 300 ? 300 : n_hours ) type_hours = "daytime" unless %w(daytime working wallclock).include?(type_hours) - ack_until = Time.now.in_x_hours(n_hours, type_hours) + now = Time.now + now.bank_holidays = Server.instance.bank_holidays + ack_until = now.in_x_hours(n_hours, type_hours) # # Make sure we can't ack longer than a week. # - max_ack = (Time.now + 86400*8) + max_ack = (Time.now + Configuration.current.max_acknowledgement_time) ack_until = max_ack if ack_until > max_ack # @@ -359,8 +365,13 @@ EOF type_hours = params[:type_hours].to_s note = params[:note] || nil + type_hours = "daytime" unless %w(daytime working wallclock).include?(type_hours) + if ack_until == 0 - ack_until = Time.now.in_x_hours(n_hours, type_hours) + now = Time.now + now.bank_holidays = Server.instance.bank_holidays + + ack_until = now.in_x_hours(n_hours, type_hours) else ack_until = Time.at(ack_until) end diff --git a/lib/object_builder.rb b/lib/object_builder.rb index ebd655b..ccb2c63 100644 --- a/lib/object_builder.rb +++ b/lib/object_builder.rb @@ -181,6 +181,20 @@ class ObjectBuilder end end + # This catches all methods available for a provider, as needed. + # + # Missing methods / bad arguments etc. are caught in the + # ObjectBuilder#parse method, via NoMethodError. + # + def method_missing(name, value=nil) + if value + result.send("#{name}=".to_sym, value) + else + result.send(name.to_sym) + end + end + + class << self # Defines a new builder |