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   
 23  """ 
 24  RRD monitor configuration parser. 
 25   
 26  The format of the configuration file is as follows. *, +, and ? have 
 27  their normal meanings: 0 or more, 1 or more, and 0 or 1, respectively. 
 28   
 29  <rrdmon> 
 30   
 31    <!-- normal --> 
 32    <debug>*:4</debug> ? 
 33   
 34    <!-- implementation note: the name of the source is used as the DS 
 35         name in the RRD file --> 
 36    <source name="http-streamer"> + 
 37   
 38      <!-- how we connect to the manager; parsed with 
 39           L{flumotion.common.connection.parsePBConnectionInfo} --> 
 40      <manager>user:test@localhost:7531</manager> 
 41   
 42      <!-- the L{flumotion.common.common.componentId} of the component we 
 43           will poll --> 
 44      <component-id>/default/http-audio-video</component-id> 
 45   
 46      <!-- the key of the L{flumotion.common.componentui} UIState that we 
 47           will poll; should be numeric in value --> 
 48      <ui-state-key>stream-totalbytes-raw</ui-state-key> 
 49   
 50      <!-- boolean; examples of gauge values would be number of users, 
 51           temperature, signal strength, precomputed bitrate. The most 
 52           common non-gauge values are bitrate values, where you poll e.g. 
 53           the number of bytes sent, not the rate itself --> 
 54      <is-gauge>False</is-gauge> ? 
 55   
 56      <!-- sample frequency in seconds, defaults to 5 minutes --> 
 57      <sample-frequency>300</sample-frequency> ? 
 58   
 59      <!-- Normally we generate the RRD DS spec from the answers above, 
 60           but if you want to you can specify one directly here. The DS 
 61           name should be the source name --> 
 62      <rrd-ds-spec>DS-SPEC</rrd-ds-spec> ? 
 63   
 64      <!-- file will be created if necessary --> 
 65      <rrd-file>/tmp/stream-bitrate.rrd</rrd-file> 
 66   
 67      <!-- set of archives to store in the rrd file 
 68      <archive> + 
 69        <!-- Would be nice to break this down as we did above for the DS 
 70             spec, but for now you have to specify the RRA specs manually. 
 71             Bummer dude! In this example, the meaning is that we should 
 72             archive a sample every 1*stepsize=1*300s=5 minutes, for 1200 
 73             samples = 5 min*1200=100h.--> 
 74        <rra-spec>AVERAGE:0.5:1:1200</rra-spec> 
 75      </archive> 
 76    </source> 
 77   
 78  </rrdmon> 
 79  """ 
 80   
 81  import os 
 82   
 83  from flumotion.common import common 
 84  from flumotion.common.connection import parsePBConnectionInfo 
 85  from flumotion.common.errors import ConfigError 
 86  from flumotion.common.fxml import Parser 
 87   
 88  __version__ = "$Rev: 6961 $" 
 89   
 90   
91 -class ConfigParser(Parser):
92 """ 93 RRD monitor configuration file parser. 94 95 Create a parser via passing the name of the file to parse to 96 __init__. Parse into a dict of properly-typed options by calling 97 parse() on the parser. 98 """ 99 parserError = ConfigError 100 logCategory = 'rrdmon-config' 101
102 - def __init__(self, file):
103 """ 104 @param file: The path to the config file to parse, or a file object 105 @type file: str or file 106 """ 107 self.doc = self.getRoot(file)
108
109 - def _parseArchive(self, node):
110 def strparser(parser): 111 def parsestr(node): 112 return self.parseTextNode(node, parser)
113 return parsestr
114 def ressetter(k): 115 def setter(v): 116 res[k] = v 117 return setter 118 119 res = {} 120 table = {} 121 basicOptions = (('rra-spec', True, str, None),) 122 for k, required, parser, default in basicOptions: 123 table[k] = strparser(parser), ressetter(k) 124 if not required: 125 res[k] = default 126 127 self.parseFromTable(node, table) 128 129 for k, required, parser, default in basicOptions: 130 if required and k not in res: 131 raise ConfigError('missing required node %s' % k) 132 return res 133
134 - def _parseSource(self, node):
135 def strparser(parser): 136 def parsestr(node): 137 return self.parseTextNode(node, parser)
138 return parsestr 139 def ressetter(k): 140 def setter(v): 141 res[k] = v 142 return setter 143 def filename(v): 144 if v[0] != os.sep: 145 raise ConfigError('rrdfile paths should be absolute') 146 return str(v) 147 148 name, = self.parseAttributes(node, ('name',)) 149 150 res = {'name': name} 151 table = {} 152 153 basicOptions = (('manager', True, 154 parsePBConnectionInfo, None), 155 ('component-id', True, str, None), 156 ('ui-state-key', True, str, None), 157 ('sample-frequency', False, int, 300), 158 ('is-gauge', False, common.strToBool, True), 159 ('rrd-ds-spec', False, str, None), 160 ('rrd-file', True, filename, None)) 161 for k, required, parser, default in basicOptions: 162 table[k] = strparser(parser), ressetter(k) 163 if not required: 164 res[k] = default 165 166 res['archives'] = [] 167 table['archive'] = (self._parseArchive, res['archives'].append) 168 169 self.parseFromTable(node, table) 170 171 for k, required, parser, default in basicOptions: 172 if required and k not in res: 173 raise ConfigError('missing required node %s' % k) 174 if not res['archives']: 175 raise ConfigError('must specify at least one ' 176 '<archive> per <source>') 177 178 return res 179
180 - def parse(self):
181 # <rrdmon> 182 # <propName>propValue</propName> 183 184 root = self.doc.documentElement 185 if not root.nodeName == 'rrdmon': 186 raise ConfigError("unexpected root node: %s" % root.nodeName) 187 188 def strparser(parser): 189 def parsestr(node): 190 return self.parseTextNode(node, parser)
191 return parsestr 192 def ressetter(k): 193 def setter(v): 194 res[k] = v 195 return setter 196 197 res = {'debug': None, 198 'sources': []} 199 table = {'debug': (strparser(str), ressetter('debug')), 200 'source': (self._parseSource, res['sources'].append)} 201 202 self.parseFromTable(root, table) 203 204 if not res['sources']: 205 raise ConfigError('must specify at least one <source>') 206 207 return res 208