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")
52 parser.add_option("-f", "--filter", type="string", dest="filter",
53 help="add FILTER to incomint traffice when working on an interface",
54 default=None, metavar="FILTER")
56 options, args = parser.parse_args(input_args)
59 parser.error('Wrong number of argumets')
63 if options.filter is not None and options.ifname is None:
64 parser.error('You need to define an interface since filters are' \
71 sys.stderr.write("HELPER-MONITOR ERROR: %s\n" % msg)
75 class HelperMonitor(object):
76 def __init__(self, fd):
83 def process(self, data):
91 split = data.split('\n', 1)
94 if len(self.line) > LINESIZE:
95 error("Line size exceeded the maximum allowed size")
101 if self.line_count >= MAXLINES + 1:
102 error("Exceeded maximum allowed number of lines: %d." %
105 if self.lines_left > 0:
106 self.stderr += "%s\n" % line
108 if self.lines_left == 0:
109 self.send("STDERR", stderr)
114 self.line = self.line.strip()
115 if len(self.line) == 0:
118 if self.line.startswith("STDERR:"):
119 m = re.match("STDERR:(\d+):(.*)", line)
121 error("Invalid syntax for STDERR line")
123 self.lines_left = int(m.group(1))
125 error("Second field in STDERR line must be an integer")
127 if self.lines_left > STDERR_MAXLINES:
128 error("Too many lines in the STDERR output")
129 elif self.lines_left < 0:
130 error("Second field of STDERR: %d is invalid" % lines_left)
132 if self.lines_left > 0:
133 self.stderr = m.group(2) + "\n"
136 if self.lines_left == 0:
137 self.send("STDERR", stderr)
139 elif self.line.startswith("TASK_START:") \
140 or self.line.startswith("TASK_END:") \
141 or self.line.startswith("WARNING:") \
142 or self.line.startswith("ERROR:"):
143 (msg_type, _, value) = self.line.partition(':')
145 if self.line.startswith("WARNING:") or \
146 self.line.startswith("ERROR:"):
148 self.send(msg_type, value)
150 error("Unknown command!")
152 # Remove the processed line
155 def send(self, msg_type, value):
156 subtype, value_name = PROTOCOL[msg_type]
159 msg['type'] = MSG_TYPE
160 msg['subtype'] = subtype
161 msg[value_name] = value
162 msg['timestamp'] = time.time()
163 os.write(self.fd, "%s\n" % json.dumps(msg))
166 if __name__ == "__main__":
167 options = parse_options(sys.argv[1:])
172 error("File descriptor is not an integer")
177 error("File descriptor is not valid")
179 monitor = HelperMonitor(fd)
181 if options.ifname is not None:
183 sniff(filter=options.filter, iface=options.ifname,
184 prn=lambda x: monitor.process(x.payload.getfieldval("load")))
185 except socket.error as e:
188 monitor.process(None)
192 for data in os.read(sys.stdin.fileno(), BUFSIZE):
193 monitor.process(data)
195 # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :