3 # Copyright (C) 2012 GRNET S.A.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 from scapy.all import sniff
31 PROGNAME = os.path.basename(sys.argv[0])
34 MSG_TYPE = 'image-helper'
37 'TASK_START': ('task-start', 'task'),
38 'TASK_END': ('task-end', 'task'),
39 'WARNING': ('warning', 'messages'),
40 'STDERR': ('error', 'stderr'),
41 'ERROR': ('error', 'messages')}
44 def parse_options(input_args):
45 usage = "Usage: %prog [options] <file-sescriptor>"
46 parser = optparse.OptionParser(usage=usage)
48 parser.add_option("-i", "--interface", type="string", dest="ifname",
49 default=None, metavar="IFNAME",
50 help="listen on interface IFNAME for monitoring data")
53 "-f", "--filter", type="string", dest="filter",
54 help="add FILTER to incomint traffice when working on an interface",
55 default=None, metavar="FILTER")
57 options, args = parser.parse_args(input_args)
60 parser.error('Wrong number of argumets')
64 if options.filter is not None and options.ifname is None:
65 parser.error('You need to define an interface since filters are'
72 sys.stderr.write("HELPER-MONITOR ERROR: %s\n" % msg)
76 class HelperMonitor(object):
77 def __init__(self, fd):
84 def process(self, data):
92 split = data.split('\n', 1)
95 if len(self.line) > LINESIZE:
96 error("Line size exceeded the maximum allowed size")
102 if self.line_count >= MAXLINES + 1:
103 error("Exceeded maximum allowed number of lines: %d." %
106 if self.lines_left > 0:
107 self.stderr += "%s\n" % self.line
109 if self.lines_left == 0:
110 self.send("STDERR", self.stderr)
115 self.line = self.line.strip()
116 if len(self.line) == 0:
119 if self.line.startswith("STDERR:"):
120 m = re.match("STDERR:(\d+):(.*)", self.line)
122 error("Invalid syntax for STDERR line")
124 self.lines_left = int(m.group(1))
126 error("Second field in STDERR line must be an integer")
128 if self.lines_left > STDERR_MAXLINES:
129 error("Too many lines in the STDERR output")
130 elif self.lines_left < 0:
131 error("Second field of STDERR: %d is invalid" %
134 if self.lines_left > 0:
135 self.stderr = m.group(2) + "\n"
138 if self.lines_left == 0:
139 self.send("STDERR", self.stderr)
141 elif self.line.startswith("TASK_START:") \
142 or self.line.startswith("TASK_END:") \
143 or self.line.startswith("WARNING:") \
144 or self.line.startswith("ERROR:"):
145 (msg_type, _, value) = self.line.partition(':')
147 if self.line.startswith("WARNING:") or \
148 self.line.startswith("ERROR:"):
150 self.send(msg_type, value)
152 error("Unknown command!")
154 # Remove the processed line
157 def send(self, msg_type, value):
158 subtype, value_name = PROTOCOL[msg_type]
161 msg['type'] = MSG_TYPE
162 msg['subtype'] = subtype
163 msg[value_name] = value
164 msg['timestamp'] = time.time()
165 os.write(self.fd, "%s\n" % json.dumps(msg))
168 if __name__ == "__main__":
169 options = parse_options(sys.argv[1:])
174 error("File descriptor is not an integer")
179 error("File descriptor is not valid")
181 monitor = HelperMonitor(fd)
183 if options.ifname is not None:
185 sniff(filter=options.filter, iface=options.ifname,
186 prn=lambda x: monitor.process(x.payload.getfieldval("load")))
187 except socket.error as e:
190 monitor.process(None)
195 data = os.read(sys.stdin.fileno(), BUFSIZE)
196 monitor.process(data)
200 # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :