diff options
| -rw-r--r-- | lib/custodian/alerter.rb | 267 | ||||
| -rw-r--r-- | lib/custodian/alerts/mauve.rb | 221 | 
2 files changed, 220 insertions, 268 deletions
| diff --git a/lib/custodian/alerter.rb b/lib/custodian/alerter.rb deleted file mode 100644 index ac38da8..0000000 --- a/lib/custodian/alerter.rb +++ /dev/null @@ -1,267 +0,0 @@ - -require 'custodian/util/bytemark' -require 'custodian/util/dns' - - -#### -#### NOTE:  This class will go away, once I've moved the implementation -####       over to alerts/mauve.rb -#### -#### - -# -#  This class encapsulates the raising and clearing of alerts via Mauve. -# -#  There is a helper method to update any alerts with details of whether the -# affected host is inside/outside the Bytemark network. -# -# -module Custodian - -  class Alerter - -    # -    # Details of the test case which we're going to raise/clear. -    # -    attr_reader :test - -    # -    #  Is this alerter available? -    # -    attr_reader :available - - -    # -    # Constructor. -    # -    # Save the details away. -    # -    def initialize( test_class ) -      @test = test_class - - -      @available = true - -      begin -        require 'mauve/sender' -        require 'mauve/proto' -      rescue LoadError -        @available = false -      end - -      puts "ALERTER DISABLED: Steve" -      @available = false -    end - - - - -    # -    # Expand to a message indicating whether a hostname is inside the Bytemark network. -    # or not. -    # -    # -    def expand_inside_bytemark( host ) - -      # -      #  If the host is a URL then we need to work with the hostname component alone. -      # -      #  We'll also make the host a link that can be clicked in the alert we raise. -      # -      target = host -      if ( target =~ /https?:\/\/([^\/]+)/ ) -        target = $1.dup -        host   = "<a href=\"#{host}\">#{host}</a>" -      end - - -      # -      #  Resolved IP of the target -      # -      resolved = nil - -      # -      #  Resolve the target to an IP, unless it is already an address. -      # -      if ( ( target =~ /^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$/ ) || -           ( target =~ /^([0-9a-f:]+)$/ ) ) -        resolved = target -      else -        resolved = Custodian::Util::DNS.hostname_to_ip( target ) -      end - - -      # -      # Did we get an error? -      # -      return "" unless ( !resolved.nil? ) - - -      # -      #  Return the formatted message -      # -      if ( Custodian::Util::Bytemark.inside?( resolved.to_s ) ) -        if ( resolved == target ) -          return "<p>#{host} is inside the Bytemark network.</p>" -        else -          return "<p>#{host} resolves to #{resolved} which is inside the Bytemark network.</p>" -        end -      else -        if ( resolved == target ) -          return "<p>#{host} is OUTSIDE the Bytemark network.</p>" -        else -          return "<p>#{host} resolves to #{resolved} which is OUTSIDE the Bytemark network.</p>" -        end -      end - -    end - - - - - -    # -    # Generate an alert-message which will be raised via mauve. -    # -    def raise( detail ) - -      if ( !@available ) -        puts "Should raise alert for test: #{test}" -        exit(3) -        return -      end - -      # -      #  Get ready to send to mauve. -      # -      update         = Mauve::Proto::AlertUpdate.new -      update.alert   = [] -      update.source  = "custodian" -      update.replace = false - -      # -      # Construct an alert with our test details. -      # -      alert = get_alert(detail) - -      # -      #  We're raising this alert. -      # -      alert.raise_time = Time.now.to_i - -      # -      #  Update it and send it -      # -      update.alert << alert -      Mauve::Sender.new("alert.bytemark.co.uk").send(update) -    end - - - -    # -    # Generate an alert-message which will be cleared via mauve. -    # -    def clear - -      if ( !@available ) -        puts "Should clear alert for test: #{test}" -        return -      end - -      # -      #  Get ready to send to mauve. -      # -      update = Mauve::Proto::AlertUpdate.new -      update.alert   = [] -      update.source  = "custodian" -      update.replace = false - - -      # -      # Construct an alert with our test details. -      # -      alert = get_alert( "" ) - -      # -      #  We're clearing this alert. -      # -      alert.clear_time = Time.now.to_i - -      # -      #  Update it and send it -      # -      update.alert << alert -      Mauve::Sender.new("alert.bytemark.co.uk").send(update) -    end - - - - -    # -    # Using the test-data-hash which was set in the constructor -    # generate a useful alert that can be fired off to mauve. -    # -    # Most of the mess of this method is ensuring there is some -    # "helpful" data in the detail-field of the alert. -    # -    def get_alert( detail ) - -      # -      # Is this alert affecting a machine inside/outside our network? -      # -      inside = expand_inside_bytemark( @details["target_host"] ) - - -      # -      # The subject of an alert should be one of: -      # -      #   1.  Hostname. -      # -      #   2.  IP address -      # -      #   3.  A URL. -      # -      # -      # We attempt to resolve the alert to the hostname, as that is readable. -      # -      # -      subject = @details['target_host'] -      if ( ( subject =~ /^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$/ ) || -           ( subject =~ /^([0-9a-f:]+)$/ ) ) -        res = Custodian::Util::DNS.ip_to_hostname( subject ) -        if ( res ) -          subject = res -        end -      end - -      # -      # Document the hostname if the alert relates to an IP address. -      # -      resolved = "" -      if ( ( @details["target_host"] =~ /^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$/ ) || -           ( @details["target_host"] =~ /^([0-9a-f:]+)$/ ) ) - -        resolved = Custodian::Util::DNS.ip_to_hostname( @details["target_host"] ) -        if ( resolved.nil? ) -          resolved = "" -        else -          resolved = "The IP address #{@details["target_host"]} resolves to #{resolved}." -        end -      end - - -      alert         = Mauve::Proto::Alert.new -      alert.id      = "#{@details['test_type']}-#{@details['target_host']}" -      alert.subject = subject -      alert.summary = "#{@details['test_alert']} to #{subject} failed #{detail}" -      alert.detail  = "#{inside} <p>The #{@details['test_type']} test failed against #{@details['target_host']}: #{detail}</p><p>#{resolved}</p>" - -      # -      # Return the alert to the caller. -      # -      alert -    end - -  end - -end diff --git a/lib/custodian/alerts/mauve.rb b/lib/custodian/alerts/mauve.rb index c3e8a76..64b6982 100644 --- a/lib/custodian/alerts/mauve.rb +++ b/lib/custodian/alerts/mauve.rb @@ -1,8 +1,21 @@ +require 'custodian/util/bytemark' +require 'custodian/util/dns' + + +# +#  This class encapsulates the raising and clearing of alerts via Mauve. +# +#  There is a helper method to update any alerts with details of whether the +# affected host is inside/outside the Bytemark network. +# +#  This is almost Bytemark-specific, although the server it talks to is +# indeed Open Source: +# +#    https://projects.bytemark.co.uk/projects/mauvealert  # -#  The Mauve-alerter.  #  module Custodian @@ -10,20 +23,226 @@ module Custodian      class Mauve < AlertFactory +        #        # The test this alerter cares about        #        attr_reader :test + + +        #        # Constructor        #        def initialize( obj )          @test = obj + +        begin +          require 'mauve/sender' +          require 'mauve/proto' +        rescue LoadError +          puts "ERROR Loading mauvealert libraries" +        end +      end + + + + +      # +      # Generate an alert-message which will be raised via mauve. +      # +      def raise() + + +        # +        # Get ready to send to mauve. +        # +        update         = Mauve::Proto::AlertUpdate.new +        update.alert   = [] +        update.source  = "custodian" +        update.replace = false + +        # +        # Construct a new alert structure. +        # +        alert = _get_alert( true ) + +        # +        #  We're raising this alert. +        # +        alert.raise_time = Time.now.to_i + +        # +        #  Update it and send it +        # +        update.alert << alert +        Mauve::Sender.new( @target ).send(update) +      end + + + +      # +      # Generate an alert-message which will be cleared via mauve. +      # +      def clear + +        # +        # Get ready to send to mauve. +        # +        update = Mauve::Proto::AlertUpdate.new +        update.alert   = [] +        update.source  = "custodian" +        update.replace = false + +        # +        # Construct a new alert structure. +        # +        alert = _get_alert( false ) + +        # +        #  We're clearing this alert. +        # +        alert.clear_time = Time.now.to_i + +        # +        #  Update it and send it +        # +        update.alert << alert +        Mauve::Sender.new( @target ).send(update)        end + + + +      # +      # Using the test object, which was set in the constructor, +      # generate a useful alert that can be fired off to mauve. +      # +      # Most of the mess of this method is ensuring there is some +      # "helpful" data in the detail-field of the alert. +      # +      def _get_alert( failure ) + +        # +        # The subject of an alert MUST be one of: +        # +        #   1.  Hostname. +        #   2.  IP address +        #   3.  A URL. +        # +        # We attempt to resolve the alert to the hostname, as that is more +        # readable, if we have been given an IP address. +        # +        subject = @test.target + +        if ( ( subject =~ /^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$/ ) || +             ( subject =~ /^([0-9a-f:]+)$/ ) ) +          res = Custodian::Util::DNS.ip_to_hostname( subject ) +          if ( res ) +            subject = res +          end +        end + + +        # +        #  The test type +        # +        test_host = test.target +        test_type = test.get_type + + +        alert         = Mauve::Proto::Alert.new +        alert.id      = "#{test_type}-#{test_host}" +        alert.subject = subject +        alert.summary = "#{test_type}-#{test_host}" +        alert.detail  = "<p>The #{test_type} test failed against #{test_host}.</p>" + +        # +        #  If we're raising then add the error +        # +        if ( failure ) +          alert.detail = "#{alert.detail}\n#{test.error()}" +        end + +        # +        #  Determine if this is inside/outside the bytemark network +        # +        location = expand_inside_bytemark( test_host ) +        if ( !location.nil? && location.length ) +          alert.detail = "#{alert.detail}\n#{location}" +        end + +        # +        # Return the alert to the caller. +        # +        alert +      end + + +      # +      # Expand to a message indicating whether a hostname is inside the Bytemark network. +      # or not. +      # +      # +      def expand_inside_bytemark( host ) + +        # +        #  If the host is a URL then we need to work with the hostname component alone. +        # +        #  We'll also make the host a link that can be clicked in the alert we raise. +        # +        target = host +        if ( target =~ /^([a-z]+):\/\/([^\/]+)/ ) +          target = $2.dup +          host   = "<a href=\"#{host}\">#{host}</a>" +        end + + +        # +        #  Resolved IP of the target +        # +        resolved = nil + +        # +        #  Resolve the target to an IP, unless it is already an address. +        # +        if ( ( target =~ /^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$/ ) || +             ( target =~ /^([0-9a-f:]+)$/ ) ) +          resolved = target +        else +          resolved = Custodian::Util::DNS.hostname_to_ip( target ) +        end + + +        # +        # Did we get an error? +        # +        return "" unless ( !resolved.nil? ) + + +        # +        #  Return the formatted message +        # +        if ( Custodian::Util::Bytemark.inside?( resolved.to_s ) ) +          if ( resolved == target ) +            return "<p>#{host} is inside the Bytemark network.</p>" +          else +            return "<p>#{host} resolves to #{resolved} which is inside the Bytemark network.</p>" +          end +        else +          if ( resolved == target ) +            return "<p>#{host} is OUTSIDE the Bytemark network.</p>" +          else +            return "<p>#{host} resolves to #{resolved} which is OUTSIDE the Bytemark network.</p>" +          end +        end + +      end + +        register_alert_type "mauve" | 
