Package flumotion :: Package manager :: Module main
[hide private]

Source Code for Module flumotion.manager.main

  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  manager main function 
 24  """ 
 25   
 26  import optparse 
 27  import os 
 28  import sys 
 29  import traceback 
 30   
 31  from twisted.internet import reactor, error 
 32   
 33  from flumotion.manager import manager 
 34  from flumotion.common import log, config, common, errors, setup 
 35  from flumotion.configure import configure 
 36  from flumotion.common import server 
 37   
 38  defaultSSLPort = configure.defaultSSLManagerPort 
 39  defaultTCPPort = configure.defaultTCPManagerPort 
 40   
41 -def _createParser():
42 usagemessage = "usage: %prog [options] manager.xml flow1.xml [...]" 43 desc = "The manager is the core component of the Flumotion streaming\ 44 server. It takes its configuration from one or more planet configuration\ 45 files. The first file is mandatory, and contains base configuration \ 46 information for the manager. Zero or more additional configuration files\ 47 can be provided, these are used to configure flows that the manager should run\ 48 on available workers." 49 50 parser = optparse.OptionParser(usage=usagemessage, description=desc) 51 parser.add_option('-d', '--debug', 52 action="store", type="string", dest="debug", 53 help="set debug levels") 54 parser.add_option('-v', '--verbose', 55 action="store_true", dest="verbose", 56 help="be verbose") 57 parser.add_option('', '--version', 58 action="store_true", dest="version", 59 default=False, 60 help="show version information") 61 62 group = optparse.OptionGroup(parser, "manager options") 63 group.add_option('-H', '--hostname', 64 action="store", type="string", dest="host", 65 help="hostname to listen as") 66 group.add_option('-P', '--port', 67 action="store", type="int", dest="port", 68 default=None, 69 help="port to listen on [default %d (ssl) or %d (tcp)]" % (defaultSSLPort, defaultTCPPort)) 70 group.add_option('-T', '--transport', 71 action="store", type="string", dest="transport", 72 help="transport protocol to use (tcp/ssl) [default ssl]") 73 group.add_option('-C', '--certificate', 74 action="store", type="string", dest="certificate", 75 default=None, 76 help="PEM certificate file (for SSL) " 77 "[default default.pem]") 78 group.add_option('-n', '--name', 79 action="store", type="string", dest="name", 80 help="manager name") 81 group.add_option('-s', '--service-name', 82 action="store", type="string", dest="serviceName", 83 help="name to use for log and pid files " 84 "when run as a daemon") 85 group.add_option('-D', '--daemonize', 86 action="store_true", dest="daemonize", 87 default=False, 88 help="run in background as a daemon") 89 group.add_option('', '--daemonize-to', 90 action="store", dest="daemonizeTo", 91 help="what directory to run from when daemonizing") 92 93 parser.add_option('-L', '--logdir', 94 action="store", dest="logdir", 95 help="flumotion log directory (default: %s)" % 96 configure.logdir) 97 parser.add_option('-R', '--rundir', 98 action="store", dest="rundir", 99 help="flumotion run directory (default: %s)" % 100 configure.rundir) 101 102 parser.add_option_group(group) 103 104 return parser
105
106 -def _error(message, reason):
107 msg = message 108 if reason: 109 msg += "\n%s" % reason 110 # since our SystemError is going to be lost in the reactor, we may as well 111 # trap it here 112 # FIXME: maybe we should stop making this raise SystemErrror ? 113 try: 114 log.error('manager', msg) 115 except errors.SystemError: 116 pass
117
118 -def _initialLoadConfig(vishnu, paths):
119 # this is used with a callLater for the initial config loading 120 # since this is run after daemonizing, it should show errors, but not stop 121 for path in paths: 122 log.debug('manager', 'Loading configuration file from (%s)' % path) 123 try: 124 vishnu.loadConfigurationXML(path, manager.LOCAL_IDENTITY) 125 except config.ConfigError, reason: 126 _error( 127 "configuration error in configuration file\n'%s':" % path, 128 reason.args[0]) 129 except errors.UnknownComponentError, reason: 130 _error( 131 "unknown component in configuration file\n'%s':" % path, 132 reason.args[0]) 133 except Exception, e: 134 # a re-raise here would be caught by twisted and only shows at 135 # debug level 4 because that's where we hooked up twisted logging 136 # so print a traceback before stopping the program 137 traceback.print_tb(sys.exc_info()[2]) 138 _error("failed to load planet configuration '%s':" % path, 139 "%s: %s" % (e.__class__, str(e)))
140
141 -def main(args):
142 # XXX: gst_init should remove all options, like gtk_init 143 args = [arg for arg in args if not arg.startswith('--gst')] 144 145 parser = _createParser() 146 147 log.debug('manager', 'Parsing arguments (%r)' % ', '.join(args)) 148 options, args = parser.parse_args(args) 149 150 # Force options down configure's throat 151 for d in ['logdir', 'rundir']: 152 o = getattr(options, d, None) 153 if o: 154 log.debug('manager', 'Setting configure.%s to %s' % (d, o)) 155 setattr(configure, d, o) 156 157 # verbose overrides --debug 158 if options.verbose: 159 options.debug = "*:3" 160 161 # Handle options that don't require a configuration file. 162 if options.version: 163 print common.version("flumotion-manager") 164 return 0 165 166 # parse planet config file 167 if len(args) <= 1: 168 log.warning('manager', 'Please specify a planet configuration file') 169 sys.stderr.write("Please specify a planet configuration file.\n") 170 return 1 171 172 planetFile = args[1] 173 try: 174 cfg = config.FlumotionConfigXML(planetFile) 175 except IOError, e: 176 sys.stderr.write("ERROR: Could not read configuration from '%s':\n" % 177 planetFile) 178 sys.stderr.write("ERROR: %s\n" % e.strerror) 179 return 1 180 except errors.ConfigError, e: 181 sys.stderr.write("ERROR: Could not read configuration from '%s':\n" % 182 planetFile) 183 sys.stderr.write("ERROR: %s\n" % e.args[0]) 184 return 1 185 186 configDir = os.path.abspath(os.path.dirname(planetFile)) 187 188 # now copy over stuff from config that is not set yet 189 if cfg.manager: 190 if not options.host and cfg.manager.host: 191 options.host = cfg.manager.host 192 log.debug('manager', 'Setting manager host to %s' % options.host) 193 if not options.port and cfg.manager.port: 194 options.port = cfg.manager.port 195 log.debug('manager', 'Setting manager port to %s' % options.port) 196 if not options.transport and cfg.manager.transport: 197 options.transport = cfg.manager.transport 198 log.debug('manager', 'Setting manager transport to %s' % 199 options.transport) 200 if not options.certificate and cfg.manager.certificate: 201 options.certificate = cfg.manager.certificate 202 log.debug('manager', 'Using certificate %s' % 203 options.certificate) 204 if not options.name and cfg.manager.name: 205 options.name = cfg.manager.name 206 log.debug('manager', 'Setting manager name to %s' % options.name) 207 # environment debug > command-line debug > config file debug 208 if not options.debug and cfg.manager.fludebug \ 209 and not os.environ.has_key('FLU_DEBUG'): 210 options.debug = cfg.manager.fludebug 211 log.debug('manager', 'Setting debug level to config file value %s' % 212 options.debug) 213 214 # set debug level as soon as we can after deciding 215 if options.debug: 216 log.setFluDebug(options.debug) 217 218 # set default values for all unset options 219 if not options.host: 220 options.host = "" # needed for bind to work 221 if not options.transport: 222 options.transport = 'ssl' 223 if not options.port: 224 if options.transport == "tcp": 225 options.port = defaultTCPPort 226 elif options.transport == "ssl": 227 options.port = defaultSSLPort 228 if not options.certificate and options.transport == 'ssl': 229 options.certificate = 'default.pem' 230 if not options.name: 231 try: 232 # if the file is in a directory under a 'managers' directory, 233 # use the parent directory name 234 head, filename = os.path.split(os.path.abspath(planetFile)) 235 head, name = os.path.split(head) 236 head, managers = os.path.split(head) 237 if managers != 'managers': 238 raise 239 options.name = name 240 log.debug('manager', 'Setting name to %s based on path' % name) 241 except: 242 options.name = 'unnamed' 243 log.debug('manager', 'Setting name to unnamed') 244 245 # check for wrong options/arguments 246 if not options.transport in ['ssl', 'tcp']: 247 sys.stderr.write('ERROR: wrong transport %s, must be ssl or tcp\n' % 248 options.transport) 249 return 1 250 251 # register package path 252 setup.setupPackagePath() 253 254 # log our standardized starting marker 255 log.info('manager', "Starting manager '%s'" % options.name) 256 257 log.debug('manager', 'Running Flumotion version %s' % 258 configure.version) 259 import twisted.copyright 260 log.debug('manager', 'Running against Twisted version %s' % 261 twisted.copyright.version) 262 from flumotion.project import project 263 for p in project.list(): 264 log.debug('manager', 'Registered project %s version %s' % ( 265 p, project.get(p, 'version'))) 266 267 vishnu = manager.Vishnu(options.name, configDir=configDir) 268 269 paths = [os.path.abspath(filename) for filename in args[1:]] 270 reactor.callLater(0, _initialLoadConfig, vishnu, paths) 271 272 # set up server based on transport 273 myServer = server.Server(vishnu) 274 try: 275 if options.transport == "ssl": 276 myServer.startSSL(options.host, options.port, options.certificate, 277 configure.configdir) 278 elif options.transport == "tcp": 279 myServer.startTCP(options.host, options.port) 280 except error.CannotListenError, e: 281 # e is a socket.error() 282 message = "Could not listen on port %d: %s" % ( 283 e.port, e.socketError.args[1]) 284 raise errors.SystemError, message 285 286 if options.daemonizeTo and not options.daemonize: 287 sys.stderr.write( 288 'ERROR: --daemonize-to can only be used with -D/--daemonize.\n') 289 return 1 290 291 if options.serviceName and not options.daemonize: 292 sys.stderr.write( 293 'ERROR: --service-name can only be used with -D/--daemonize.\n') 294 return 1 295 296 name = options.name 297 298 if options.daemonize: 299 if options.serviceName: 300 name = options.serviceName 301 302 common.startup("manager", name, options.daemonize, 303 options.daemonizeTo) 304 305 reactor.run() 306 307 return 0
308