Package flumotion :: Package admin :: Package command :: Module component
[hide private]

Source Code for Module flumotion.admin.command.component

  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  component commands 
 24  """ 
 25   
 26  from twisted.python import failure 
 27   
 28  from flumotion.common import errors, planet, log 
 29  from flumotion.common import common as fccommon 
 30  from flumotion.monitor.nagios import util 
 31  from flumotion.common.planet import moods 
 32   
 33  from flumotion.admin.command import common 
 34   
 35  __version__ = "$Rev: 6562 $" 
 36   
 37   
38 -class Delete(common.AdminCommand):
39 description = "Delete a component." 40
41 - def doCallback(self, args):
42 if not self.parentCommand.componentId: 43 common.errorRaise("Please specify a component id " 44 "with 'component -i [component-id]'") 45 46 d = self.getRootCommand().medium.callRemote('deleteComponent', 47 self.parentCommand.componentState) 48 49 def cb(result): 50 self.stdout.write("Deleted component.\n")
51 52 def eb(failure): 53 if failure.check(errors.ComponentMoodError, 54 errors.BusyComponentError): 55 common.errorRaise("Component '%s' is in the wrong mood." % 56 self.parentCommand.componentId) 57 else: 58 common.errorRaise(log.getFailureMessage(failure))
59 60 d.addCallback(cb) 61 d.addErrback(eb) 62 63 return d 64 65
66 -class Invoke(common.AdminCommand):
67 usage = "[method-name] [arguments]" 68 summary = "invoke a method on a component" 69 description = """Invoke a method on a component. 70 %s 71 For a list of methods that can be invoked, see the component's medium class 72 and its remote_* methods. 73 74 Examples: getConfig, setFluDebug""" % common.ARGUMENTS_DESCRIPTION 75
76 - def addOptions(self):
77 self.parser.add_option('-r', '--raw-output', 78 action="store_true", dest="rawOutput", 79 help="do not pretty print the output")
80
81 - def handleOptions(self, options):
82 self.rawOutput = options.rawOutput
83
84 - def doCallback(self, args):
85 if not self.parentCommand.componentId: 86 common.errorRaise("Please specify a component id " 87 "with 'component -i [component-id]'") 88 89 try: 90 methodName = args[0] 91 except IndexError: 92 common.errorRaise('Please specify a method name to invoke.') 93 if len(args) > 1: 94 args = common.parseTypedArgs(args[1], args[2:]) 95 if args is None: 96 common.errorRaise('Could not parse arguments.') 97 else: 98 args = [] 99 100 p = self.parentCommand 101 d = self.getRootCommand().medium.componentCallRemote( 102 self.parentCommand.componentState, methodName, *args) 103 104 def cb(result): 105 if self.rawOutput: 106 self.stdout.write(str(result)) 107 else: 108 import pprint 109 self.stdout.write("Invoking '%s' on '%s' returned:\n%s\n" % ( 110 methodName, p.componentId, pprint.pformat(result)))
111 112 def eb(failure): 113 if failure.check(errors.NoMethodError): 114 common.errorRaise("No method '%s' on component '%s'." % ( 115 methodName, p.componentId)) 116 elif failure.check(errors.SleepingComponentError): 117 common.errorRaise( 118 "Component '%s' is sleeping." % p.componentId) 119 else: 120 common.errorRaise(log.getFailureMessage(failure))
121 122 d.addCallback(cb) 123 d.addErrback(eb) 124 125 return d 126 127
128 -class List(common.AdminCommand):
129 description = "List components." 130
131 - def doCallback(self, args):
132 p = self.parentCommand 133 a = p.planetState.get('atmosphere') 134 if a.get('components'): 135 self.stdout.write('atmosphere:\n') 136 for c in a.get('components'): 137 self.stdout.write(' ' + c.get('name') + '\n') 138 139 for f in p.planetState.get('flows'): 140 if f.get('components'): 141 self.stdout.write('%s flow:\n' % f.get('name')) 142 for c in f.get('components'): 143 self.stdout.write(' ' + c.get('name') + '\n')
144 145
146 -class DetailedList(common.AdminCommand):
147 description = "List components with types and worker hosts." 148
149 - def doCallback(self, args):
150 p = self.parentCommand 151 a = p.planetState.get('atmosphere') 152 s = p.workerHeavenState 153 workers = s.get('workers') 154 a_comps = a.get('components') 155 if a_comps: 156 self.stdout.write('atmosphere:\n') 157 self.parentCommand.print_components(a_comps, workers) 158 159 for f in p.planetState.get('flows'): 160 f_comps = f.get('components') 161 if f_comps: 162 self.stdout.write('%s flow:\n' % f.get('name')) 163 self.parentCommand.print_components(f_comps, workers)
164 165
166 -class UpstreamList(common.AdminCommand):
167 description = """List a component and its upstream components along 168 with types and worker hosts.""" 169
170 - def get_eaters_ids(self, eaters_dic):
171 avatars = [] 172 for flow in eaters_dic.keys(): 173 comps = eaters_dic[flow] 174 for c in comps: 175 (name, what) = c[0].split(':') 176 avatars.append('/%s/%s' % (flow, name)) 177 return avatars
178
179 - def doCallback(self, args):
180 p = self.parentCommand 181 s = p.workerHeavenState 182 workers = s.get('workers') 183 184 if not p.componentId: 185 common.errorRaise("Please specify a component id " 186 "with 'component -i [component-id]'") 187 188 eaters = p.componentState.get('config').get('eater', {}) 189 eaters_id = self.get_eaters_ids(eaters) 190 comps = [p.componentState] 191 while len(eaters_id) > 0: 192 eaters = {} 193 for i in eaters_id: 194 try: 195 compState = util.findComponent(p.planetState, i) 196 comps.append(compState) 197 eaters.update(compState.get('config').get('eater', {})) 198 except Exception, e: 199 self.debug(log.getExceptionMessage(e)) 200 common.errorRaise("Error retrieving component '%s'" % i) 201 eaters_id = self.get_eaters_ids(eaters) 202 203 self.stdout.write('Upstream Components:\n') 204 self.parentCommand.print_components(comps, workers)
205 206
207 -class Mood(common.AdminCommand):
208 description = "Check the mood of a component." 209
210 - def doCallback(self, args):
211 if not self.parentCommand.componentId: 212 common.errorRaise("Please specify a component id " 213 "with 'component -i [component-id]'") 214 215 p = self.parentCommand 216 moodValue = p.componentState.get('mood') 217 moodName = planet.moods.get(moodValue).name 218 self.stdout.write("Component '%s' is %s.\n" % (p.componentId, 219 moodName))
220 221
222 -class PropertyGet(common.AdminCommand):
223 description = "Get a property of a component." 224 name = 'get' 225
226 - def do(self, args):
227 if not args: 228 return common.errorReturn('Please specify a property to get.') 229 230 self._propertyName = args[0] 231 232 return common.AdminCommand.do(self, args)
233
234 - def doCallback(self, args):
235 u = self.parentCommand.uiState 236 name = self._propertyName 237 238 if not u.hasKey(name): 239 common.errorRaise("Component '%s' does not have property '%s'." % ( 240 self.parentCommand.parentCommand.componentId, name)) 241 242 self.stdout.write("Property '%s' is '%r'.\n" % ( 243 name, u.get(name)))
244 245
246 -class PropertyList(common.AdminCommand):
247 description = "List properties of a component." 248 name = 'list' 249
250 - def doCallback(self, args):
251 l = self.parentCommand.uiState.keys() 252 l.sort() 253 self.stdout.write('Properties:\n') 254 for p in l: 255 self.stdout.write('- %s\n' % p)
256 257 # FIXME: why is this called property when it really is about ui state ? 258 259
260 -class Property(util.LogCommand):
261 """ 262 @param uiState: the ui state of the component; set after logging in. 263 """ 264 265 description = "Act on properties of a component." 266 267 subCommandClasses = [PropertyGet, PropertyList] 268
269 - def handleOptions(self, options):
270 if not self.parentCommand.componentId: 271 common.errorRaise("Please specify a component id " 272 "with 'component -i [component-id]'") 273 274 # call our callback after connecting 275 d = self.getRootCommand().loginDeferred 276 d.addCallback(self._callback) 277 d.addErrback(self._errback)
278
279 - def _callback(self, result):
280 281 def getUIStateCb(uiState): 282 self.uiState = uiState
283 284 componentCommand = self.parentCommand 285 model = componentCommand.parentCommand.medium 286 d = model.componentCallRemote( 287 componentCommand.componentState, 'getUIState') 288 d.addCallback(getUIStateCb) 289 return d
290
291 - def _errback(self, failure):
292 failure.trap(errors.SleepingComponentError) 293 common.errorRaise("Component '%s' is sleeping." % 294 self.parentCommand.componentId)
295 296
297 -class Start(common.AdminCommand):
298 description = "Start a component." 299
300 - def doCallback(self, args):
301 if not self.parentCommand.componentId: 302 common.errorRaise("Please specify a component id " 303 "with 'component -i [component-id]'") 304 305 p = self.parentCommand 306 moodValue = p.componentState.get('mood') 307 if moodValue == moods.happy.value: 308 self.stdout.write("Component is already happy.\n") 309 return 0 310 311 d = self.getRootCommand().medium.callRemote('componentStart', 312 self.parentCommand.componentState) 313 314 def cb(result): 315 self.stdout.write("Started component.\n")
316 317 def eb(failure): 318 if failure.trap(errors.ComponentMoodError): 319 common.errorRaise("Component '%s' is in the wrong mood." % 320 self.parentCommand.componentId) 321 else: 322 common.errorRaise(log.getFailureMessage(failure))
323 324 d.addCallback(cb) 325 d.addErrback(eb) 326 327 return d 328 329
330 -class Stop(common.AdminCommand):
331 description = "Stop a component." 332
333 - def doCallback(self, args):
334 if not self.parentCommand.componentId: 335 common.errorRaise("Please specify a component id " 336 "with 'component -i [component-id]'") 337 338 p = self.parentCommand 339 moodValue = p.componentState.get('mood') 340 if moodValue == moods.sleeping.value: 341 self.stdout.write("Component is already sleeping.\n") 342 return 0 343 344 d = self.getRootCommand().medium.callRemote('componentStop', 345 self.parentCommand.componentState) 346 347 def cb(result): 348 self.stdout.write("Stopped component.\n")
349 350 def eb(failure): 351 if failure.trap(errors.ComponentMoodError): 352 common.errorRaise("Component '%s' is in the wrong mood." % 353 self.parentCommand.componentId) 354 else: 355 common.errorRaise(log.getFailureMessage(failure))
356 357 d.addCallback(cb) 358 d.addErrback(eb) 359 360 return d 361 362
363 -class Component(util.LogCommand):
364 """ 365 @ivar componentId: the component id, passed as an argument 366 @ivar componentState: the component state; set when logged in to manager. 367 @type componentState: L{flumotion.common.state.AdminComponentState} 368 @ivar planetState: the planet state; set when logged in to manager. 369 @type planetState: L{flumotion.common.state.AdminPlanetState} 370 """ 371 description = "Act on a component." 372 usage = "-i [component id]" 373 374 subCommandClasses = [Delete, Invoke, List, DetailedList, 375 UpstreamList, Mood, Property, Start, Stop] 376 377 componentId = None 378 componentState = None 379 planetState = None 380 workerHeavenState = None 381
382 - def addOptions(self):
383 self.parser.add_option('-i', '--component-id', 384 action="store", dest="componentId", 385 help="component id of the component")
386
387 - def handleOptions(self, options):
388 self.componentId = options.componentId 389 # call our callback after connecting 390 self.getRootCommand().loginDeferred.addCallback(self._callback)
391
392 - def _callback(self, result):
393 d = self.parentCommand.medium.callRemote('getPlanetState') 394 395 def gotPlanetStateCb(result): 396 self.planetState = result 397 self.debug('gotPlanetStateCb') 398 399 # only get componentState if we got passed an argument for it 400 if not self.componentId: 401 return 402 403 try: 404 self.componentState = util.findComponent(result, 405 self.componentId) 406 except Exception, e: 407 self.debug(log.getExceptionMessage(e)) 408 common.errorRaise("Invalid component id '%s'" % 409 self.componentId) 410 self.debug('gotPlanetStateCb') 411 if not self.componentState: 412 common.errorRaise('Could not find component %s' % 413 self.componentId)
414 415 def getWorkerHeavenStateCb(result): 416 d = self.parentCommand.medium.callRemote('getWorkerHeavenState') 417 return d
418 419 def gotWorkerHeavenStateCb(result): 420 self.workerHeavenState = result 421 422 d.addCallback(gotPlanetStateCb) 423 d.addCallback(getWorkerHeavenStateCb) 424 d.addCallback(gotWorkerHeavenStateCb) 425 return d 426
427 - def pprint(self, comps):
428 tab = 4 429 cols = [[c[i] for c in comps] for i in xrange(len(comps[0]))] 430 max_widths = [max(map(len, c)) for c in cols] 431 for c in comps: 432 s = " " 433 for i in xrange(len(c)): 434 width = "%d" % (max_widths[i] + tab) 435 s += ('%-' + width + "s") % c[i] 436 self.stdout.write(s + "\n")
437
438 - def print_components(self, components, workers):
439 comps = [] 440 for c in components: 441 workerName = c.get('workerName') 442 host = "unknown" 443 for w in workers: 444 if workerName == w.get('name'): 445 host = w.get('host') 446 break 447 comps.append((c.get('name'), c.get('type'), host)) 448 self.pprint(comps)
449