pedro - r7234 - in flumotion/branches/ticket-2058: . flumotion/monitor/nagios

flumotion-commit at lists.fluendo.com flumotion-commit at lists.fluendo.com
Tue Aug 12 23:27:07 CEST 2008


Author: pedro
Date: Tue Aug 12 23:27:06 2008
New Revision: 7234

Log:
	* flumotion/monitor/nagios/stream.py:
	Playlist detected with gstreamer too.
	Better nagios error messages.
	General code clean.



Modified:
   flumotion/branches/ticket-2058/ChangeLog
   flumotion/branches/ticket-2058/flumotion/monitor/nagios/stream.py

Modified: flumotion/branches/ticket-2058/ChangeLog
==============================================================================
--- flumotion/branches/ticket-2058/ChangeLog	(original)
+++ flumotion/branches/ticket-2058/ChangeLog	Tue Aug 12 23:27:06 2008
@@ -1,6 +1,13 @@
 2008-08-12  Pedro Gracia  <pedro at flumotion.com>
 
 	* flumotion/monitor/nagios/stream.py:
+	Playlist detected with gstreamer too.
+	Better nagios error messages.
+	General code clean.
+
+2008-08-12  Pedro Gracia  <pedro at flumotion.com>
+
+	* flumotion/monitor/nagios/stream.py:
 	  Nagios critical messages in one line.
 	  Simple playlist autodetect.
 

Modified: flumotion/branches/ticket-2058/flumotion/monitor/nagios/stream.py
==============================================================================
--- flumotion/branches/ticket-2058/flumotion/monitor/nagios/stream.py	(original)
+++ flumotion/branches/ticket-2058/flumotion/monitor/nagios/stream.py	Tue Aug 12 23:27:06 2008
@@ -36,37 +36,38 @@
     """Main class to perform the stream checks"""
     description = 'Check stream.'
     usage = 'check [options] url'
-    # variables to check streams and a counter to track the playing state
 
     def __init__(self, parentCommand=None, **kwargs):
         """Initial values and pipeline setup"""
-        self._hasaudio = False
-        self._hasvideo = False
-        self._isaudio = False
-        self._isvideo = False
-        self.options = None
-        self.url = ""
+        self._hasAudio = False
+        self._hasVideo = False
+        self._isAudio = False
+        self._isVideo = False
+        self._isPlaylist = True
+        self._options = None
+        self._url = ''
 
         util.LogCommand.__init__(self, parentCommand, **kwargs)
 
     def addOptions(self):
         """Command line options"""
         # video options
-        self.parser.add_option('-w', '--videowidth',
+        self.parser.add_option('-W', '--videowidth',
             action="store", dest="videowidth",
             help='Video width')
         self.parser.add_option('-H', '--videoheight',
             action="store", dest="videoheight",
             help='Video height')
-        self.parser.add_option('-f', '--videoframerate',
+        self.parser.add_option('-F', '--videoframerate',
             action="store", dest="videoframerate",
             help='Video framerate (fraction)')
-        self.parser.add_option('-p', '--videopixelratio',
+        self.parser.add_option('-P', '--videopixelratio',
             action="store", dest="videopixelratio",
             help='Video pixel aspect ratio (fraction)')
-        self.parser.add_option('-m', '--videomimetype',
+        self.parser.add_option('-M', '--videomimetype',
             action="store", dest="videomimetype",
             help='Video mimetype')
+
         # audio options
         self.parser.add_option('-s', '--audiosamplerate',
             action="store", dest="audiosamplerate",
@@ -74,205 +75,233 @@
         self.parser.add_option('-c', '--audiochannels',
             action="store", dest="audiochannels",
             help='Audio channels')
-        self.parser.add_option('-W', '--audiowidth',
+        self.parser.add_option('-w', '--audiowidth',
             action="store", dest="audiowidth",
             help='Audio width')
-        self.parser.add_option('-D', '--audiodepth',
+        self.parser.add_option('-d', '--audiodepth',
             action="store", dest="audiodepth",
             help='Audio depth')
-        self.parser.add_option('-M', '--audiomimetype',
+        self.parser.add_option('-m', '--audiomimetype',
             action="store", dest="audiomimetype",
             help='Audio mimetype')
+
         # general option
-        self.parser.add_option('-d', '--duration',
+        self.parser.add_option('-D', '--duration',
             action="store", dest="duration", default='5',
             help='Check duration (default 5 seconds)')
         self.parser.add_option('-t', '--timeout',
             action="store", dest="timeout", default='10',
             help='Number of tries (default 10 try)')
-        self.parser.add_option('-P', '--playlist',
+        self.parser.add_option('-p', '--playlist',
             action="store_true", dest="playlist",
             help='is a playlist')
 
     def handleOptions(self, options):
-        """Determine if this stream would have audio/video"""
+        #Determine if this stream would have audio/video
         self.options = options
         if options.videowidth or options.videoheight or \
            options.videoframerate or options.videopixelratio or \
            options.videomimetype:
-            self._hasvideo = True
+            self._hasVideo = True
         if options.audiosamplerate or options.audiochannels or \
            options.audiowidth or options.audiodepth or \
            options.audiomimetype:
-            self._hasaudio = True
+            self._hasAudio = True
+
+    def critical(self, message):
+        return util.critical('%s: %s' % (self._url, message))
+
+    def ok(self, message):
+        return util.ok('%s: %s' % (self._url, message))
 
     def do(self, args):
         """Check URL and perfom the stream check"""
         if not args:
-            return util.critical('Please specify the url to check the '\
-                                 'stream/playlist.\n.')
+            return self.critical('Please specify the url to check the '\
+            'stream/playlist.\n.')
 
-        self.url = args[0]
+        self._url = args[0]
         # check url and get path from it
         try:
-            parse = urlparse.urlparse(self.url)
+            parse = urlparse.urlparse(self._url)
         except ValueError:
-            return util.critical("URL isn't valid.\n")
+            return self.critical("URL isn't valid.\n")
         if parse[0] != 'http':
-            return util.critical('URL type is not valid.\n')
+            return self.critical('URL type is not valid.\n')
 
         # Simple playlist detection.
-        # TODO: detect it using the mime-type with gstreamer
-        if self.url.endswith('.m3u') or self.url.endswith('.asx'):
+        if self._url.endswith('.m3u') or self._url.endswith('.asx'):
             self.options.playlist = True
 
         if self.options.playlist:
-            playlist = urllib.urlopen(self.url).read()
-            if playlist.startswith('404'):
-                return util.critical(playlist)
-            urls = re.findall(URLFINDER, playlist)
-            self.url = urls[-1] # new (the last) url to check
+            self._url = self.getURLFromPlaylist(self._url)
 
         result = self.checkStream()
         return result
 
+    def getURLFromPlaylist(self, url):
+        playlist = urllib.urlopen(self._url).read()
+        if playlist.startswith('404'):
+            return util.critical(playlist)
+        urls = re.findall(URLFINDER, playlist)
+        return urls[-1] # new (the last) url to check
+
     def checkStream(self):
         """Launch the pipeline and compare values with the expecteds"""
-        gstinfo = GSTInfo(int(self.options.timeout),
-                          int(self.options.duration), self.url)
-        elements = gstinfo.getElements()
+        while self._isPlaylist: #use gstreamer to detect the playlist
+            gstinfo = GSTInfo(int(self.options.timeout),
+                              int(self.options.duration), self._url)
+            elements = gstinfo.getElements()
+            self._isPlaylist = gstinfo.isPlaylist()
+            if self._isPlaylist:
+                self._url = self.getURLFromPlaylist(self._url) #replace the url
 
         for i in elements['typefinder'].src_pads():
             caps = i.get_caps()
             if caps == 'ANY' or not caps:
                 if gstinfo.getError():
-                    return util.critical(gstinfo.getError())
+                    return self.critical(gstinfo.getError())
                 else:
-                    return util.critical("There aren't caps in this stream.")
+                    return self.critical("There aren't caps in this stream.")
 
         for i in elements['decoder'].src_pads():
             caps = i.get_caps()
             mime = caps.to_string().split(', ')[0]
             # tests for audio
             if 'audio' in caps.to_string():
-                self._isaudio = True
+                self._isAudio = True
                 if self.options.audiomimetype:
                     if self.options.audiomimetype != mime:
-                        return util.critical('Audio mime type fail: '\
-                               '%s [%s]' % (mime, self.url))
+                        return self.critical('Audio mime type fail: ' \
+                        'EXPECTED: %s, ACTUAL: %s' % \
+                        (self.options.audiomimetype, mime))
                 if self.options.audiosamplerate:
                     if int(self.options.audiosamplerate) != caps[0]['rate']:
-                        return util.critical('Audio sample rate fail: '\
-                               '%s [%s]' % (caps[0]['rate'], self.url))
+                        return self.critical('Audio sample rate fail: '\
+                        'EXPECTED: %s, ACTUAL: %s' % \
+                        (self.options.audiosamplerate, caps[0]['rate']))
                 if self.options.audiowidth:
                     if int(self.options.audiowidth) != caps[0]['width']:
-                        return util.critical('Audio width fail: %s [%s]' % \
-                               (caps[0]['width'], self.url))
+                        return self.critical('Audio width fail: ' \
+                        'EXPECTED: %s, ACTUAL: %s' % \
+                        (self.options.audiowidth, caps[0]['width']))
                 if self.options.audiodepth:
                     if int(self.options.audiodepth) != caps[0]['depth']:
-                        return util.critical('Audio depth fail: %s [%s]' % \
-                               (caps[0]['depth'], self.url))
+                        return self.critical('Audio depth fail: ' \
+                        'EXPECTED: %s, ACTUAL: %s' % \
+                        (self.options.audiodepth, caps[0]['depth']))
                 if self.options.audiochannels:
                     if int(self.options.audiochannels) != caps[0]['channels']:
-                        return util.critical('Audio channels fail: %s [%s]' % \
-                               (caps[0]['channels'], self.url))
+                        return self.critical('Audio channels fail: ' \
+                        'EXPECTED: %s, ACTUAL: %s' % \
+                        (self.options.audiochannels, caps[0]['channels']))
             # tests for video
             if 'video' in caps.to_string():
-                self._isvideo = True
+                self._isVideo = True
                 if self.options.videomimetype:
                     if self.options.videomimetype != mime:
-                        return util.critical('Video mime type fail: '\
-                               '%s [%s]' % (mime, self.url))
+                        return self.critical('Video mime type fail: '\
+                        'EXPECTED: %s, ACTUAL: %s' % \
+                        (self.options.videomimetype, mime))
                 if self.options.videowidth:
                     if int(self.options.videowidth) != caps[0]['width']:
-                        return util.critical('Video width fail: %s [%s]' % \
-                               (caps[0]['width'], self.url))
+                        return self.critical('Video width fail: ' \
+                        'EXPECTED: %s, ACTUAL: %s' % \
+                        (self.options.videowidth, caps[0]['width']))
                 if self.options.videoheight:
                     if int(self.options.videoheight) != caps[0]['height']:
-                        return util.critical('Video height fail: %s [%s]' % \
-                               (caps[0]['height'], self.url))
+                        return self.critical('Video height fail: ' \
+                        'EXPECTED: %s, ACTUAL: %s' % \
+                        (self.options.videoheight, caps[0]['height']))
                 if self.options.videoframerate:
                     value = caps[0]['framerate']
                     if self.options.videoframerate != '%i/%i' % \
                         (value.num, value.denom):
-                        return util.critical('Video framerate fail: ' % \
-                               'i/%i [%s]' % (value.num, value.denom,
-                                              self.url))
+                        return self.critical('Video framerate fail: ' \
+                        'EXPECTED: %s, ACTUAL: %i/%i' % \
+                        (self.options.videoframerate, value.num, value.denom))
                 if self.options.videopixelratio:
                     value = caps[0]['pixel-aspect-ratio']
-                    if self.options.videopixelratio != "%i/%i [%s]" % \
+                    if self.options.videopixelratio != '%i/%i' % \
                         (value.num, value.denom):
-                        return util.critical('Video height fail: ' \
-                               '%i/%i [%s]' % (value.num, value.denom,
-                                               self.url))
+                        return self.critical('Video height fail: ' \
+                        'EXPECTED: %s, ACTUAL: %i/%i' % \
+                        (self.options.videopixelratio, value.num, value.denom))
 
         # is audio and/or video missing?
-        if self._hasvideo != self._isvideo or \
-           self._hasaudio != self._isaudio:
-            return util.critical('Stream type mismatch. Please add ' \
-                                 'more parameters to check [%s].' % self.url)
+        if self._hasVideo != self._isVideo or \
+           self._hasAudio != self._isAudio:
+            return self.critical('Stream type mismatch. Please add ' \
+                                 'more parameters to check.')
 
         gstinfo.setState(gst.STATE_NULL)
-        return util.ok('Done! [%s]' % self.url)
+        return self.ok('Done!')
 
 
 class GSTInfo:
     """Get info from stream using a gstreamer pipeline"""
 
     def __init__(self, timeout, duration, url):
-        self.mainloop = gobject.MainLoop()
-        self._counter = 0
+        self._mainloop = gobject.MainLoop()
+        self._counter = 0 # counter to track the playing state
         _pipeline = 'souphttpsrc name=httpsrc ! ' \
                     'typefind name=typefinder ! ' \
                     'decodebin name=decoder ! ' \
                     'fakesink'
-        self.duration = duration
-        self.url = url
-        self.error = ''
-        self.pipeline = gst.parse_launch(_pipeline)
-        self.elements = dict((e.get_name(), e) for e in \
-                                               self.pipeline.elements())
-        bus = self.pipeline.get_bus()
+        self._duration = duration
+        self._url = url
+        self._error = ''
+        self._playlist = False
+        self._pipeline = gst.parse_launch(_pipeline)
+        self._elements = dict((e.get_name(), e) for e in \
+                                              self._pipeline.elements())
+        bus = self._pipeline.get_bus()
         bus.add_watch(self.busWatch)
-        self.elements['httpsrc'].set_property('location', url)
-        self.pipeline.set_state(gst.STATE_PLAYING)
+        self._elements['httpsrc'].set_property('location', url)
+        self._pipeline.set_state(gst.STATE_PLAYING)
         gobject.timeout_add(timeout * 1000, self.endTimeout)
 
-        self.mainloop.run()
+        self._mainloop.run()
 
     def setState(self, state):
-        self.pipeline.set_state(state)
+        self._pipeline.set_state(state)
 
     def getElements(self):
-        return self.elements
+        return self._elements
 
     def getError(self):
-        return self.error
+        return self._error
+
+    def isPlaylist(self):
+        return self._playlist
 
     def busWatch(self, bus, message):
         """Capture messages in pipeline bus"""
-        typus = message.type
-        if typus == gst.MESSAGE_EOS:
-            self.pipeline.set_state(gst.STATE_NULL)
-        elif typus == gst.MESSAGE_ERROR:
-            self.error = message.parse_error()[0].message
-            self.pipeline.set_state(gst.STATE_NULL)
-            self.mainloop.quit()
-        elif typus == gst.MESSAGE_STATE_CHANGED:
+        if message.type == gst.MESSAGE_EOS:
+            self._pipeline.set_state(gst.STATE_NULL)
+        elif message.type == gst.MESSAGE_ERROR:
+            self._error = message.parse_error()[0].message
+            self._pipeline.set_state(gst.STATE_NULL)
+            code = message.parse_error()[0].code
+            if code == gst.STREAM_ERROR_CODEC_NOT_FOUND:
+                if 'text/uri-list' in message.parse_error()[0].message:
+                    self._playlist = True
+            self._mainloop.quit()
+        elif message.type == gst.MESSAGE_STATE_CHANGED:
             new = message.parse_state_changed()[1]
-            if message.src == self.pipeline and new == gst.STATE_PLAYING:
+            if message.src == self._pipeline and new == gst.STATE_PLAYING:
                 gobject.timeout_add(1000, self.isPlaying)
         return True
 
     def isPlaying(self):
         """Check the stream is playing every second"""
-        ret, cur, pen = self.pipeline.get_state()
+        ret, cur, pen = self._pipeline.get_state()
         if ret == gst.STATE_CHANGE_SUCCESS and cur == gst.STATE_PLAYING:
             self._counter += 1
-            if self._counter == self.duration:
-                self.mainloop.quit()
+            if self._counter == self._duration:
+                self._mainloop.quit()
         return True
 
     def endTimeout(self):
         """End of time to do the check"""
-        self.mainloop.quit()
+        self._mainloop.quit()


More information about the flumotion-commit mailing list