#! /usr/bin/ruby1.8 # == Synopsis # # mauvesend: send alert(s) to a given alert station # # == Usage # # mauvesend [destination] # [--source | -o <source>] [--replace | -p] [--verbose | -v] # [--id <alert ID> [alert options] ... ] # # <destination>: # where the alert should go, can be one of: # SRV record from DNS (we add _mauvealert._udp to record name) # normal hostname (i.e. A record) # IP address:port number # # if no destination is supplied, reads parameter from file # /etc/mauvealert/mauvesend.destination (otherwise throws an error). # # --source | -o <source>: # identify the source of the alert (defaults to hostname, but you might # want to name your monitoring systems more explicitly). # # --replace | -p: # Send an update replacing all other alerts for this source - any previous # alerts not specified in this update are assumed to be cleared. If you # specify this option, you don't have to supply *any* alerts to raise or # clear (in which case all alerts from that source will be cleared). # # --verbose | -v: # If you specify this option once, it will print the transmission ID # of the packet for debugging. If you specify it twice, it will print # the entire data structure. # # You can specify any number of alerts in an update - every time you specify # --id starts a new alert. # # --id | -i <alert ID>: # alert ID; unique specified for each alert raised. # # --summary | -s <summary>: # text for humans describing the nature of the alert, first 100 characters # are only ones guaranteed to make it to pagers, twitter, SMS etc. # # --detail | -d <detail>: # HTML fragment describing the alert in more detail, no limit on length. # # --subject | -u <subject>: # set the subject of the alert (i.e. the server/entity that this alert # concerns). # # --clear | -c <time>: # mark the alert to be cleared at the given time, or +N where N is a number # of seconds, or 'now'. If not supplied, the alert is deemed to be raised # until explicitly cleared. # # --raise | -r <time>: # mark the alert to be (re)raised at the given time. If not supplied, the # alert will be raised immediately. # require 'getoptlong' require 'mauve/sender' require 'mauve/proto' require 'mauve/mauve_time' require 'pp' NOW = Mauve::MauveTime.now def error(msg) STDERR.print "*** Error: #{msg}\n" STDERR.print "*** For help, type: #{$0} -h\n" exit 1 end def parse_time_spec(spec = "now") now = NOW return now if spec == 'now' case spec[0] when ?+ then multiplier = 1 when ?- then multiplier = -1 else return Mauve::MauveTime.parse(spec) end multiplier *= case spec[-1] when ?m then 60 when ?h then 3600 when ?d then 86400 else 1 end now + spec[1..-1].to_i * multiplier end update = Mauve::Proto::AlertUpdate.new update.replace = false update.alert = [] message = nil verbose = 0 help = false opts = GetoptLong.new( ['-h', '--help', GetoptLong::NO_ARGUMENT], ['-o', '--source', GetoptLong::OPTIONAL_ARGUMENT], ['-p', '--replace', GetoptLong::NO_ARGUMENT], ['-i', '--id', GetoptLong::OPTIONAL_ARGUMENT], ['-s', '--summary', GetoptLong::OPTIONAL_ARGUMENT], ['-u', '--subject', GetoptLong::OPTIONAL_ARGUMENT], ['-c', '--clear', GetoptLong::OPTIONAL_ARGUMENT], ['-r', '--raise', GetoptLong::OPTIONAL_ARGUMENT], ['-d', '--detail', GetoptLong::OPTIONAL_ARGUMENT], ['-v', '--verbose', GetoptLong::NO_ARGUMENT] ).each do |opt,arg| # # Can catch empty arguments better if we set the GetoptLong things to # "optional" rather than "required" and catch the empty arg here. error "#{opt} cannot be empty" if arg.empty? and not %w(-h -p -v -c -r).include?(opt) case opt when '-h' help = true when '-p' update.replace = true when '-i' message = Mauve::Proto::Alert.new message.id = arg update.alert << message when '-o' error "Can only specify one source" if update.source update.source = arg when '-v' verbose += 1 else error "Must specify --id before message" unless message case opt when '-s' then message.summary = arg when '-u' then message.subject = arg when '-d' then message.detail = arg when '-c' then message.clear_time = parse_time_spec(arg).to_i when '-r' then message.raise_time = parse_time_spec(arg).to_i else error "Unknown option #{opt}" end end end # CAUTION! Kwality kode. # if help # Open the file, stripping the shebang line lines = File.open(__FILE__){|fh| fh.readlines}[2..-1] lines.each do |line| line.chomp! break if line.empty? puts line[2..-1].to_s end exit 0 end error "No alerts specified" unless !update.alert.empty? || update.replace update.transmission_id = rand(2**63) begin Mauve::Sender.new(ARGV).send(update, verbose) rescue Protobuf::NotInitializedError => bad error "Alert not initialized fully - you must supply an ID" rescue ArgumentError => ae error ae.message rescue StandardError => ae error ae.message end