Package flumotion :: Package admin :: Package rrdmon :: Module config
[hide private]

Source Code for Module flumotion.admin.rrdmon.config

  1  # -*- Mode: Python -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3  # 
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007 Fluendo, S.L. (www.fluendo.com). 
  6  # All rights reserved. 
  7   
  8  # This file may be distributed and/or modified under the terms of 
  9  # the GNU General Public License version 2 as published by 
 10  # the Free Software Foundation. 
 11  # This file is distributed without any warranty; without even the implied 
 12  # warranty of merchantability or fitness for a particular purpose. 
 13  # See "LICENSE.GPL" in the source distribution for more information. 
 14   
 15  # Licensees having purchased or holding a valid Flumotion Advanced 
 16  # Streaming Server license may use this file in accordance with the 
 17  # Flumotion Advanced Streaming Server Commercial License Agreement. 
 18  # See "LICENSE.Flumotion" in the source distribution for more information. 
 19   
 20  # Headers in this file shall remain intact. 
 21   
 22  import os 
 23   
 24  from xml.dom import Node 
 25   
 26  from flumotion.configure import configure 
 27  from flumotion.common import common, config, connection 
 28  from flumotion.common.errors import ConfigError 
 29   
 30   
 31  """ 
 32  RRD monitor configuration 
 33   
 34  The format of the configuration file is as follows. *, +, and ? have 
 35  their normal meanings: 0 or more, 1 or more, and 0 or 1, respectively. 
 36   
 37  <rrdmon> 
 38   
 39    <!-- normal --> 
 40    <debug>*:4</debug> ? 
 41   
 42    <!-- implementation note: the name of the source is used as the DS 
 43         name in the RRD file --> 
 44    <source name="http-streamer"> + 
 45   
 46      <!-- how we connect to the manager; parsed with 
 47           L{flumotion.common.connection.parsePBConnectionInfo} --> 
 48      <manager>user:test@localhost:7531</manager> 
 49   
 50      <!-- the L{flumotion.common.common.componentId} of the component we 
 51           will poll --> 
 52      <component-id>/default/http-audio-video</component-id> 
 53   
 54      <!-- the key of the L{flumotion.common.componentui} UIState that we 
 55           will poll; should be numeric in value --> 
 56      <ui-state-key>stream-totalbytes-raw</ui-state-key> 
 57   
 58      <!-- boolean; examples of gauge values would be number of users, 
 59           temperature, signal strength, precomputed bitrate. The most 
 60           common non-gauge values are bitrate values, where you poll e.g. 
 61           the number of bytes sent, not the rate itself --> 
 62      <is-gauge>False</is-gauge> ? 
 63   
 64      <!-- sample frequency in seconds, defaults to 5 minutes --> 
 65      <sample-frequency>300</sample-frequency> ? 
 66   
 67      <!-- Normally we generate the RRD DS spec from the answers above, 
 68           but if you want to you can specify one directly here. The DS 
 69           name should be the source name --> 
 70      <rrd-ds-spec>DS-SPEC</rrd-ds-spec> ? 
 71   
 72      <!-- file will be created if necessary --> 
 73      <rrd-file>/tmp/stream-bitrate.rrd</rrd-file> 
 74   
 75      <!-- set of archives to store in the rrd file 
 76      <archive> + 
 77        <!-- Would be nice to break this down as we did above for the DS 
 78             spec, but for now you have to specify the RRA specs manually. 
 79             Bummer dude! In this example, the meaning is that we should 
 80             archive a sample every 1*stepsize=1*300s=5 minutes, for 1200 
 81             samples = 5 min*1200=100h.--> 
 82        <rra-spec>AVERAGE:0.5:1:1200</rra-spec> 
 83      </archive> 
 84    </source> 
 85   
 86  </rrdmon> 
 87  """ 
 88   
 89   
90 -class ConfigParser(config.BaseConfigParser):
91 """ 92 RRD monitor configuration file parser. 93 94 Create a parser via passing the name of the file to parse to 95 __init__. Parse into a dict of properly-typed options by calling 96 parse() on the parser. 97 """ 98 logCategory = 'rrdmon-config' 99
100 - def __init__(self, file):
101 """ 102 @param file: The path to the config file to parse, or a file object 103 @type file: str or file 104 """ 105 config.BaseConfigParser.__init__(self, file)
106
107 - def _parseArchive(self, node):
108 def strparser(parser): 109 def parsestr(node): 110 return self.parseTextNode(node, parser)
111 return parsestr
112 def ressetter(k): 113 def setter(v): 114 res[k] = v 115 return setter 116 117 res = {} 118 table = {} 119 basicOptions = (('rra-spec', True, str, None),) 120 for k, required, parser, default in basicOptions: 121 table[k] = strparser(parser), ressetter(k) 122 if not required: 123 res[k] = default 124 125 self.parseFromTable(node, table) 126 127 for k, required, parser, default in basicOptions: 128 if required and k not in res: 129 raise config.ConfigError('missing required node %s' % k) 130 return res 131
132 - def _parseSource(self, node):
133 def strparser(parser): 134 def parsestr(node): 135 return self.parseTextNode(node, parser)
136 return parsestr 137 def ressetter(k): 138 def setter(v): 139 res[k] = v 140 return setter 141 def filename(v): 142 if v[0] != os.sep: 143 raise config.ConfigError('rrdfile paths should be absolute') 144 return str(v) 145 146 name, = self.parseAttributes(node, ('name',)) 147 148 res = {'name': name} 149 table = {} 150 151 basicOptions = (('manager', True, 152 connection.parsePBConnectionInfo, None), 153 ('component-id', True, str, None), 154 ('ui-state-key', True, str, None), 155 ('sample-frequency', False, int, 300), 156 ('is-gauge', False, common.strToBool, True), 157 ('rrd-ds-spec', False, str, None), 158 ('rrd-file', True, filename, None)) 159 for k, required, parser, default in basicOptions: 160 table[k] = strparser(parser), ressetter(k) 161 if not required: 162 res[k] = default 163 164 res['archives'] = [] 165 table['archive'] = (self._parseArchive, res['archives'].append) 166 167 self.parseFromTable(node, table) 168 169 for k, required, parser, default in basicOptions: 170 if required and k not in res: 171 raise config.ConfigError('missing required node %s' % k) 172 if not res['archives']: 173 raise config.ConfigError('must specify at least one ' 174 '<archive> per <source>') 175 176 return res 177
178 - def parse(self):
179 # <rrdmon> 180 # <propName>propValue</propName> 181 root = self.doc.documentElement 182 if not root.nodeName == 'rrdmon': 183 raise ConfigError("unexpected root node: %s" % root.nodeName) 184 185 def strparser(parser): 186 def parsestr(node): 187 return self.parseTextNode(node, parser)
188 return parsestr 189 def ressetter(k): 190 def setter(v): 191 res[k] = v 192 return setter 193 194 res = {'debug': None, 195 'sources': []} 196 table = {'debug': (strparser(str), ressetter('debug')), 197 'source': (self._parseSource, res['sources'].append)} 198 199 self.parseFromTable(root, table) 200 201 if not res['sources']: 202 raise config.ConfigError('must specify at least one ' 203 '<source>') 204 205 return res 206