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