diff options
-rw-r--r-- | debian/control | 1 | ||||
-rw-r--r-- | debian/mauvealert-server.postinst | 8 | ||||
-rw-r--r-- | lib/mauve/configuration.rb | 107 | ||||
-rw-r--r-- | lib/mauve/http_server.rb | 2 | ||||
-rw-r--r-- | lib/mauve/mauve_time.rb | 43 | ||||
-rw-r--r-- | lib/mauve/notification.rb | 32 | ||||
-rw-r--r-- | lib/mauve/sender.rb | 4 | ||||
-rw-r--r-- | lib/mauve/server.rb | 2 | ||||
-rw-r--r-- | static/stylesheets/mauve.css | 21 | ||||
-rw-r--r-- | test/tc_mauve_configuration.rb | 38 | ||||
-rw-r--r-- | test/tc_mauve_configuration_builders_logger.rb | 7 | ||||
-rw-r--r-- | test/tc_mauve_notification.rb | 10 | ||||
-rw-r--r-- | test/tc_mauve_time.rb | 23 | ||||
-rw-r--r-- | views/_alerts_table.haml | 9 | ||||
-rw-r--r-- | views/_history.haml | 9 | ||||
-rw-r--r-- | views/alerts.haml | 12 |
16 files changed, 280 insertions, 48 deletions
diff --git a/debian/control b/debian/control index 798f058..a1c5cb1 100644 --- a/debian/control +++ b/debian/control @@ -43,6 +43,7 @@ Depends: mauvealert-common (>= 3.8.0), libxmpp4r-ruby1.8, ${misc:Depends} Suggests: mauvealert-client +Recommends: liblocale-ruby1.8 | ruby-locale Description: Mauve network alert system -- server Mauve is a network alert system for system and network administrators. You can use it to quickly set up ad-hoc monitoring for a variety of services, and to diff --git a/debian/mauvealert-server.postinst b/debian/mauvealert-server.postinst index 3d1c09a..967aa8d 100644 --- a/debian/mauvealert-server.postinst +++ b/debian/mauvealert-server.postinst @@ -17,4 +17,12 @@ for i in log lib ; do chown -R $RUNASUSER:nogroup /var/$i/mauvealert done +# +# Symlink jquery libraries in. +# +if [ -e /usr/share/javascript/jquery -a ! -e /usr/share/mauvealert/static/javascript/jquery ] ; then + ln -s /usr/share/javascript/jquery /usr/share/mauvealert/static/javascript/ +fi + + #DEBHELPER# diff --git a/lib/mauve/configuration.rb b/lib/mauve/configuration.rb index 8a0b982..55bdd9f 100644 --- a/lib/mauve/configuration.rb +++ b/lib/mauve/configuration.rb @@ -27,7 +27,7 @@ module Mauve # People # @return [Hash] attr_reader :people - + # Alert groups # @return [Array] attr_reader :alert_groups @@ -43,7 +43,7 @@ module Mauve # 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 + attr_reader :max_acknowledgement_time, :working_hours, :dead_zone, :daytime_hours # @@ -66,23 +66,30 @@ module Mauve # # Set a couple of params for remote HTTP requests. # - @remote_http_timeout = 5 - @remote_https_verify_mode = OpenSSL::SSL::VERIFY_PEER + self.remote_http_timeout = 5 + self.remote_https_verify_mode = "peer" # # Rate limit login attempts to limit the success of brute-forcing. # - @failed_login_delay = 1 + self.failed_login_delay = 1 # # Maximum amount of time to acknowledge for # - @max_acknowledgement_time = 15.days + self.max_acknowledgement_time = 15.days + + # + # Working hours + # + self.dead_zone = 3...6 + self.daytime_hours = 8...20 + self.working_hours = 9...17 end # Set the calendar URL. # - # @param [String] arg + # @param [String] arg # @return [URI] def bytemark_calendar_url=(arg) raise ArgumentError, "bytemark_calendar_url must be a string" unless arg.is_a?(String) @@ -104,7 +111,7 @@ module Mauve # Set the Bytemark Authentication URL # - # @param [String] arg + # @param [String] arg # @return [URI] def bytemark_auth_url=(arg) raise ArgumentError, "bytemark_auth_url must be a string" unless arg.is_a?(String) @@ -128,7 +135,7 @@ module Mauve # @param [Integer] arg # @return [Integer] def remote_http_timeout=(arg) - raise ArgumentError, "remote_http_timeout must be an integer" unless s.is_a?(Integer) + raise ArgumentError, "remote_http_timeout must be an integer" unless arg.is_a?(Integer) @remote_http_timeout = arg end @@ -156,7 +163,7 @@ module Mauve 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 # # @@ -169,5 +176,85 @@ module Mauve lambda{|at| CalendarInterface.get_attendees(x,at)} end + def working_hours=(arg) + @working_hours = do_parse_range(arg) + end + + def daytime_hours=(arg) + @daytime_hours = do_parse_range(arg) + end + + def dead_zone=(arg) + @dead_zone = do_parse_range(arg) + end + + private + + # This method takes a range, and wraps it within the specs defined by + # allowed_range. + # + # It can take an array of Numerics, Strings, Ranges etc + # + # @param + # + def do_parse_range(arg, allowed_range = (0...24)) + args = [arg].flatten + + # + # Tidy up our allowed ranges + # + min = allowed_range.first + max = allowed_range.last + + # + # If we've been given a numeric range, make sure they're all floats. + # + min = min.to_f if min.is_a?(Numeric) + max = max.to_f if max.is_a?(Numeric) + + ranges = [] + + args.each do |arg| + case arg + when Range + from = arg.first + to = arg.last + exclude_end = arg.exclude_end? + else + from = arg + to = arg + end + + from = min unless allowed_range.include?(from) + + # + # In the case of integers, we want to match up until, but not including + # the next integer. + # + if to.is_a?(Integer) + to = (exclude_end ? to : to.succ) + exclude_end = true + end + + to = max unless allowed_range.include?(to) + + from = from.to_f if from.is_a?(Numeric) + to = to.to_f if to.is_a?(Numeric) + + if from > to or (from >= to and exclude_end) + ranges << Range.new(from, max, allowed_range.exclude_end?) + ranges << Range.new(min, to, exclude_end) + else + ranges << Range.new(from, to, exclude_end) + end + + end + + ranges + end + + end + + end diff --git a/lib/mauve/http_server.rb b/lib/mauve/http_server.rb index 583e6b5..9250b2e 100644 --- a/lib/mauve/http_server.rb +++ b/lib/mauve/http_server.rb @@ -187,7 +187,7 @@ module Mauve # # @return [String] def base_url - @base_url ||= "http://"+Server.instance.hostname + @base_url ||= "http://"+Server.instance.hostname+(self.port == "80" ? "" : ":#{self.port}") end # Stop the server diff --git a/lib/mauve/mauve_time.rb b/lib/mauve/mauve_time.rb index dfbf99b..ab0734a 100644 --- a/lib/mauve/mauve_time.rb +++ b/lib/mauve/mauve_time.rb @@ -103,17 +103,38 @@ class Time # # def bank_holidays - @bank_holidays ||= [] + @bank_holidays = if defined? Server and Server.instance + Server.instance.bank_holidays + else + @bank_holidays || [] + end end - # This sets the bank holiday dates for the bank_holiday? check. + # Returns an array of ranges of working hours # - # @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 + def working_hours + if defined? Configuration and Configuration.current + Configuration.current.working_hours + else + [9.0...17.0] + end + end + + def dead_zone + if defined? Configuration and Configuration.current + Configuration.current.working_hours + else + [3.0...7.0] + end + end + + def daytime_hours + if defined? Configuration and Configuration.current + Configuration.current.working_hours + else + [8.0...20.0] + end end # This relies on bank_holidays being set. @@ -128,14 +149,16 @@ class Time # # @return [Boolean] def working_hours? - !bank_holiday? and (1..5).include?(self.wday) and ((9..16).include?(self.hour) or (self.hour == 8 && self.min >= 30)) + (1..5).include?(self.wday) and + self.working_hours.any?{|r| r.include?(self.hour.to_f + self.min.to_f/60.0)} and + !self.bank_holiday? end # Test to see if it is currently daytime. The daytime day is 14 hours long # # @return [Boolean] def daytime_hours? - (8..21).include?(self.hour) + self.daytime_hours.any?{|r| r.include?(self.hour.to_f + self.min.to_f/60.0)} end # We're always in wallclock hours @@ -149,7 +172,7 @@ class Time # # @return [Boolean] def dead_zone? - (3..6).include?(self.hour) + self.dead_zone.any?{|r| r.include?(self.hour.to_f + self.min.to_f/60.0)} end # Format the time as a string, relative to +now+ diff --git a/lib/mauve/notification.rb b/lib/mauve/notification.rb index 899972b..fcefcbc 100644 --- a/lib/mauve/notification.rb +++ b/lib/mauve/notification.rb @@ -157,6 +157,18 @@ module Mauve (@test_time - @alert.raised_at) >= seconds end + # Tests if the alert has raised for a certain time. + # + # @param [Integer] seconds Number of seconds + # @return [Boolean] + def raised_for(seconds) + @test_time = @time if @test_time.nil? + @alert && + @alert.raised? && + (@test_time - @alert.raised_at) >= seconds + end + + # Checks to see if x is contained in y # # @param [Array] y Array to search for +x+ @@ -177,10 +189,17 @@ module Mauve # @return [Boolean] def working_hours? @test_time = @time if @test_time.nil? - @test_time.bank_holidays = Server.instance.bank_holidays @test_time.working_hours? end + # + # Return true if today is a bank holiday + # + def bank_holiday? + @test_time = @time if @test_time.nil? + @test_time.bank_holiday? + end + # Test to see if we're in the dead zone. See Time#dead_zone? # # @return [Boolean] @@ -189,6 +208,13 @@ module Mauve @test_time.dead_zone? end + # + # Return true if we're in daytime_hours. See Time#daytime_hours? + # + def daytime_hours? + @test_time = @time if @test_time.nil? + @test_time.daytime_hours? + end end # A Notification is an instruction to notify a person, or a list of people, @@ -249,7 +275,7 @@ module Mauve end # Set up a during_runner - during_runner ||= DuringRunner.new(Time.now, self.alert, &self.during) + during_runner ||= DuringRunner.new(Time.now, alert, &self.during) # Should we notify at all? return already_sent_to unless during_runner.now? @@ -287,7 +313,7 @@ module Mauve return nil unless alert.raised? # Set up a during_runner - during_runner ||= DuringRunner.new(Time.now, self.alert, &self.during) + during_runner ||= DuringRunner.new(Time.now, alert, &self.during) if during_runner.now? return during_runner.find_next(every) diff --git a/lib/mauve/sender.rb b/lib/mauve/sender.rb index 054313e..fc12a99 100644 --- a/lib/mauve/sender.rb +++ b/lib/mauve/sender.rb @@ -153,7 +153,7 @@ module Mauve # # Check the locale charset. This is to maximise the amout of information - # mauve receives, rather than provide proper sanitised data for the server. + # mauve receives, rather than provide proper sanitized data for the server. # from_charset = (Locale.current.charset || Locale.charset) if defined?(Locale) from_charset ||= "UTF-8" @@ -201,7 +201,7 @@ module Mauve # # Clean up the update, and set any missing fields. # - update = sanitise(update) + update = sanitize(update) data = sanitize(update).serialize_to_string diff --git a/lib/mauve/server.rb b/lib/mauve/server.rb index 0bbfdfb..52933ea 100644 --- a/lib/mauve/server.rb +++ b/lib/mauve/server.rb @@ -36,7 +36,7 @@ module Mauve # def initialize super - @hostname = "localhost" + @hostname = Socket.gethostname @database = "sqlite3::memory:" @started_at = Time.now diff --git a/static/stylesheets/mauve.css b/static/stylesheets/mauve.css index 4649775..cac6833 100644 --- a/static/stylesheets/mauve.css +++ b/static/stylesheets/mauve.css @@ -52,27 +52,38 @@ tr.detail { /** Flash notices **/ -div.error { +.error { background-color: #ffe; border: solid 2px #ffc; background-image: url('/images/error.png'); } -div.notice { +.notice { background-color: #eef; border: solid 2px #ccf; background-image: url('/images/information.png'); } -div.flash { +tr.error, tr.notice { margin: 5px 5px 0px; padding: 0px; - padding-left: 20px; + padding-left: 25px; color: black; font-size: large; background-position: 5px; background-repeat: no-repeat; - min-height: 20px; + min-height: 25px; +} + +div.error, div.notice { + margin: 5px 5px 0px; + padding: 0px; + padding-left: 25px; + color: black; + font-size: large; + background-position: 5px; + background-repeat: no-repeat; + min-height: 25px; } div.flash p { diff --git a/test/tc_mauve_configuration.rb b/test/tc_mauve_configuration.rb new file mode 100644 index 0000000..bbc1901 --- /dev/null +++ b/test/tc_mauve_configuration.rb @@ -0,0 +1,38 @@ +$:.unshift "../lib/" + +require 'th_mauve' +require 'mauve/configuration' + +class TcMauveConfiguration < Mauve::UnitTest + include Mauve + + def setup + setup_logger + end + + def teardown + teardown_logger + end + + def test_do_parse_range + [ + [[1.0...2.0], 1], + [[1.0...3.0], 1..2], + [[1.0...2.0], 1...2], + [[1.0...2.0, 4.0...7.0], [1, 4..6]], + [[1.0..1.0], 1.0], + [[1.0..2.0], 1.0..2.0], + [[1.0...2.0], 1.0...2.0], + [[1.0..1.0, 4.0..6.0], [1.0, 4.0..6.0]], + [[7.0...24.0, 0.0...7.0], 7..6], + [[6.0...7.0, 0.0...1.0], 6..0, 0...7], + [["x".."z", "a".."c"], "x".."c", "a".."z"] + ].each do |output, *input| + c = Configuration.new + assert_equal(output, c.__send__("do_parse_range",*input)) + end + end + +end + + diff --git a/test/tc_mauve_configuration_builders_logger.rb b/test/tc_mauve_configuration_builders_logger.rb index 2d2bb80..14df0d8 100644 --- a/test/tc_mauve_configuration_builders_logger.rb +++ b/test/tc_mauve_configuration_builders_logger.rb @@ -2,6 +2,7 @@ $:.unshift "../lib/" require 'th_mauve' require 'mauve/configuration_builders/logger' +require 'tempfile' class TcMauveConfigurationBuildersLogger < Mauve::UnitTest @@ -10,6 +11,8 @@ class TcMauveConfigurationBuildersLogger < Mauve::UnitTest def test_load + test_log = Tempfile.new(self.class.to_s) + config=<<EOF logger { default_format "%d [ %l ] [ %12.12c ] %m" @@ -19,7 +22,7 @@ logger { outputter ("file") { trunc false - filename "test.conf" + filename "#{test_log.path}" level DEBUG } @@ -46,7 +49,7 @@ EOF assert_equal("%d [ %l ] [ %12.12c ] %m", outputter.formatter.pattern ) assert_equal(Log4r::DEBUG, outputter.level ) assert_equal(false, outputter.trunc ) - assert_equal("test.conf", outputter.filename ) + assert_equal(test_log.path, outputter.filename ) end def test_levels diff --git a/test/tc_mauve_notification.rb b/test/tc_mauve_notification.rb index 21ff41e..df8fa9b 100644 --- a/test/tc_mauve_notification.rb +++ b/test/tc_mauve_notification.rb @@ -224,6 +224,16 @@ EOF logger_pop end + def test_bank_holiday + time = Time.now + + dr = DuringRunner.new(time) + assert(!dr.send(:bank_holiday?)) + + time.bank_holidays << Date.new(Time.now.year, Time.now.month, Time.now.day) + assert(dr.send(:bank_holiday?)) + end + end class TcMauveNotification < Mauve::UnitTest diff --git a/test/tc_mauve_time.rb b/test/tc_mauve_time.rb index 6e5989b..66cb4f7 100644 --- a/test/tc_mauve_time.rb +++ b/test/tc_mauve_time.rb @@ -16,8 +16,8 @@ class TestMauveTime < Mauve::UnitTest # # Working hours.. # - hour_0 = Time.local(2011,6,6,8,30,0) - hour_1 = Time.local(2011,6,6,9,30,0) + hour_0 = Time.local(2011,6,6,9,0,0) + hour_1 = Time.local(2011,6,6,10,0,0) assert_equal(hour_1, t.in_x_hours(1,"working")) assert_equal(hour_0, t.in_x_hours(0,"working")) @@ -31,7 +31,7 @@ class TestMauveTime < Mauve::UnitTest # Working hours.. # hour_0 = Time.local(2011,6,3,16,45,32) - hour_1 = Time.local(2011,6,6,9,15,32) + hour_1 = Time.local(2011,6,6,9,45,32) assert_equal(hour_1, t.in_x_hours(1,"working")) assert_equal(hour_0, t.in_x_hours(0,"working")) @@ -41,10 +41,25 @@ class TestMauveTime < Mauve::UnitTest x = Time.now assert(!x.bank_holiday?) - x.bank_holidays << Date.new(x.year, x.month, x.day) assert(x.bank_holiday?) end + def test_dead_zone? + x = Time.local(2012,5,2,4,30,0) + assert(x.dead_zone?) + + x = Time.local(2012,5,2,9,30,0) + assert(!x.dead_zone?) + end + + def test_daytime_hours + x = Time.local(2012,5,2,4,30,0) + assert(!x.daytime_hours?) + + x = Time.local(2012,5,2,9,30,0) + assert(x.daytime_hours?) + end + end diff --git a/views/_alerts_table.haml b/views/_alerts_table.haml index 40b2b1c..ed759be 100644 --- a/views/_alerts_table.haml +++ b/views/_alerts_table.haml @@ -11,7 +11,14 @@ }); %th#summary Summary %th#time At - = partial("alerts_table_group", :collection => @grouped_alerts) + - if @grouped_alerts.length > 0 + = partial("alerts_table_group", :collection => @grouped_alerts) + - else + %tr{:class => %w(notice)} + %td + %td{:style => "text-align: center;"} + = "No #{@alert_type} alerts found!" + %td %tr %td{ :colspan => 3} %address diff --git a/views/_history.haml b/views/_history.haml index 61bcf59..cfeec51 100644 --- a/views/_history.haml +++ b/views/_history.haml @@ -4,7 +4,14 @@ %p = history.created_at.strftime("%R") - history.alerts.each do |alert| - = alert.subject + %a{ :href => self.class.url_for(alert) } + = alert.id + %strong + = alert.subject = alert.summary + - if alert.source != alert.subject + = "(from #{alert.source})" = history.event + - if history.user + = "by #{history.user}" - @today = history.created_at diff --git a/views/alerts.haml b/views/alerts.haml index 896b5a3..88cb82c 100644 --- a/views/alerts.haml +++ b/views/alerts.haml @@ -1,11 +1,7 @@ -- if @grouped_alerts.length > 0 - %form#alerts{:method => :post, :action => '/alerts/acknowledge'} - = partial('alerts_table') - %h2 Actions - %p= partial('acknowledge_input') -- else - .notice#alerts_table - %p No alerts to display. +%form#alerts{:method => :post, :action => '/alerts/acknowledge'} + = partial('alerts_table') + %h2 Actions + %p= partial('acknowledge_input') :javascript // Do the magic updates.. setTimeout("updateAlertsTable('#{@alert_type}','#{@group_by}');", 120000) |