1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
#! /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'
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 = Mauve::MauveTime.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).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 ArgumentError => ae
error ae.message
rescue Protobuf::NotInitializedError => bad
error "Alert not initialized fully - you must supply an ID"
end
|