[953] | 1 | #!/usr/bin/env python
|
---|
| 2 | # -*- coding: utf-8 -*-
|
---|
| 3 |
|
---|
| 4 | # $Id: bacresources.py 12826 2011-04-03 16:49:56Z pstorz $
|
---|
| 5 |
|
---|
| 6 | import time
|
---|
| 7 |
|
---|
| 8 | #from directive import *
|
---|
| 9 | #from configrules import *
|
---|
| 10 | from auto_configrules import *
|
---|
| 11 |
|
---|
| 12 | import logging
|
---|
| 13 | from auto_onlinehelp import *
|
---|
| 14 | logger = logging.getLogger('bacresources')
|
---|
| 15 |
|
---|
| 16 | import os
|
---|
| 17 | import tarfile
|
---|
| 18 | import tempfile
|
---|
| 19 | import glob
|
---|
| 20 | import shutil
|
---|
| 21 | import string
|
---|
| 22 | import random
|
---|
| 23 |
|
---|
| 24 | #TODO: we have a problem if inside of a password there is a special character like {}
|
---|
| 25 |
|
---|
| 26 |
|
---|
| 27 | def genPw(self,length=32, chars=string.letters + string.digits):
|
---|
| 28 | # from http://code.activestate.com/recipes/59873-random-password-generation/
|
---|
| 29 | return ''.join([random.choice(chars) for i in range(length)])
|
---|
| 30 |
|
---|
| 31 |
|
---|
| 32 |
|
---|
| 33 |
|
---|
| 34 | def config2blocks(configstring, processEventsCallback = None):
|
---|
| 35 | """
|
---|
| 36 | Parses the configstring and returns a list of blocks.
|
---|
| 37 | Each block is represented by its start- and end characterindex
|
---|
| 38 | saved in 'start' and 'end'
|
---|
| 39 | the configstring is expected without comment lines
|
---|
| 40 | """
|
---|
| 41 | blockdepth = 0
|
---|
| 42 | blockstack = []
|
---|
| 43 | blocks = []
|
---|
| 44 | instring = False # are we in a string between (") ?
|
---|
| 45 | lastcharbackslash = False
|
---|
| 46 |
|
---|
| 47 | for i in range(0, len(configstring)):
|
---|
| 48 |
|
---|
| 49 | #if processEventsCallback is not None and not (i%100):
|
---|
| 50 | ## #print "calling processEventsCallback"
|
---|
| 51 | # processEventsCallback(i)
|
---|
| 52 |
|
---|
| 53 | chr = configstring[i]
|
---|
| 54 | if chr == '\\':
|
---|
| 55 | lastcharbackslash = True
|
---|
| 56 | #print 'foundbackslash'
|
---|
| 57 | else:
|
---|
| 58 | lastcharbackslash = False
|
---|
| 59 |
|
---|
| 60 | if chr == '"' and not lastcharbackslash: # we may have a brace in a password, but can escape with \"
|
---|
| 61 | instring = not instring # TODO:password with { or } inside this still make problems!
|
---|
| 62 |
|
---|
| 63 | if chr == '{' and not instring:
|
---|
| 64 | blockdepth += 1
|
---|
| 65 | #print '\n ',blockdepth,' **{** ->',configstring[i-10:i+20],'<-',
|
---|
| 66 | b = {}
|
---|
| 67 | b['start'] = i
|
---|
| 68 | b['level'] = blockdepth
|
---|
| 69 | blockstack.append(b)
|
---|
| 70 |
|
---|
| 71 | elif chr == '}' and not instring:
|
---|
| 72 | blockdepth -= 1
|
---|
| 73 | b = blockstack.pop()
|
---|
| 74 | b['end'] = i
|
---|
| 75 | #print '\n ', blockdepth , ' **}** ->',configstring[i-10:i+1],'<-'
|
---|
| 76 | # find name just before the block beginning
|
---|
| 77 | s = configstring[:b['start']]
|
---|
| 78 | m = RXP_RESTYPE.search(s)
|
---|
| 79 | #logger.debug( "searching for ResType in >" + s + "<" )
|
---|
| 80 | if m:
|
---|
| 81 | b['namestart'] = b['start'] - len(m.group('resourcetype')) - 1 # start of resname......{ instead of {
|
---|
| 82 | b['name'] = m.group('resourcetype').strip(' =\n').replace(' ','') # there are also resname = {xxx}
|
---|
| 83 | #b['name'] = m.group('resourcetype').strip(' =\n') # there are also resname = {xxx}
|
---|
| 84 | if b['name'].endswith('\n'):
|
---|
| 85 | print '>>>>>>>>>>>>>>>>>>>>>>>>><>' + b['name'] + '<'
|
---|
| 86 | blocks.append(b)
|
---|
| 87 | else:
|
---|
| 88 | b['name'] = 'name not found!'
|
---|
| 89 | logger.error('Problem parsing the config file, regex did not match')
|
---|
| 90 |
|
---|
| 91 | if blockdepth != 0:
|
---|
| 92 | # TODO: throw exception
|
---|
| 93 | print "unbalanced braces in config2blocks"
|
---|
| 94 | return "unbalanced braces in config2blocks"
|
---|
| 95 | return blocks
|
---|
| 96 |
|
---|
| 97 |
|
---|
| 98 |
|
---|
| 99 |
|
---|
| 100 | '''
|
---|
| 101 | Class for ressources inside of configurations
|
---|
| 102 | hierarchy:
|
---|
| 103 | Config -> Resource -> Items+
|
---|
| 104 | |-> Resource -> Items
|
---|
| 105 | '''
|
---|
| 106 |
|
---|
| 107 | class Resource(object):
|
---|
| 108 | """
|
---|
| 109 | This class represents a bacula resource .
|
---|
| 110 | On creation, it is automatically filled with the possible configuration items
|
---|
| 111 | for the specific resource type.
|
---|
| 112 | Some items can exist multiple times (like file=, plugin= etc.),
|
---|
| 113 | These are created one time and set to their default value
|
---|
| 114 | """
|
---|
| 115 | def __init__(self, parentconfig, resourcetype, indentlevel = 1, printall = False, onlinehelpURL = ''):
|
---|
| 116 | #def __init__(self, parentconfig, resourcetype, name = None, indentlevel = 1, printall = False):
|
---|
| 117 | self.onlinehelpURL = onlinehelpURL
|
---|
| 118 | self.indentlevel = indentlevel
|
---|
| 119 | #print resourcetype, type(self.indentlevel) ,self.indentlevel
|
---|
| 120 | self.shortname = res2shrtn[resourcetype]
|
---|
| 121 | self.parentconfig = parentconfig # what configuration does this resource belong to?
|
---|
| 122 | #print "my parentconfig is" + repr(parentconfig)
|
---|
| 123 | self.printall = printall
|
---|
| 124 | self.resources = []
|
---|
| 125 | self.items = []
|
---|
| 126 | self.reflist = [] # what resources reference this resource?
|
---|
| 127 | if resourcetype == 'runscript':
|
---|
| 128 | items = eval ( "dird_"+ res2shrtn[resourcetype] + "_items[:]") #TODO : ensure this works
|
---|
| 129 | self.items = copy.deepcopy(items)
|
---|
| 130 | logging.debug('eval: ' + " dird_"+ res2shrtn[resourcetype] + "_items[:]")
|
---|
| 131 | elif resourcetype == 'messages':
|
---|
| 132 | items = eval ( "lib_"+ res2shrtn[resourcetype] + "_items[:]") #TODO : ensure this works
|
---|
| 133 | self.items = copy.deepcopy(items)
|
---|
| 134 | logging.debug('eval: ' + " lib_"+ res2shrtn[resourcetype] + "_items[:]")
|
---|
| 135 | elif resourcetype == 'options':
|
---|
| 136 | items = eval ( "inc_"+ res2shrtn[resourcetype] + "_items[:]") #TODO : ensure this works
|
---|
| 137 | self.items = copy.deepcopy(items)
|
---|
| 138 | logging.debug('eval: ' + "inc_"+ res2shrtn[resourcetype] + "_items[:]")
|
---|
| 139 | else:
|
---|
| 140 | #print resourcetype
|
---|
| 141 | #self.items = eval ( self.parentconfig.shortname+"_"+ res2shrtn[resourcetype] + "_items[:]") #TODO : ensure this works
|
---|
| 142 | items = eval ( self.parentconfig.shortname+"_"+ res2shrtn[resourcetype] + "_items[:]") #TODO : ensure this works
|
---|
| 143 | self.items = copy.deepcopy(items)
|
---|
| 144 | logging.debug('eval: ' + self.parentconfig.shortname+"_"+ res2shrtn[resourcetype] + "_items[:]" )
|
---|
| 145 |
|
---|
| 146 | #for item in self.items:
|
---|
| 147 | # logger.debug(item.name + ' id: '+ str(id(item)))
|
---|
| 148 | # if item.name in MULTIPLE_ALLOWED_ITEMS_SET:
|
---|
| 149 | # del item
|
---|
| 150 |
|
---|
| 151 |
|
---|
| 152 |
|
---|
| 153 | # set parent resource for all own items
|
---|
| 154 | for item in self.items:
|
---|
| 155 | item.parentresource = self
|
---|
| 156 | item.indentlevel = 1
|
---|
| 157 |
|
---|
| 158 |
|
---|
| 159 |
|
---|
| 160 | self.__create_valid_items_set__()
|
---|
| 161 | self.__create_items_dict___()
|
---|
| 162 | self.resourcetype = resourcetype # director, filedaemon ...
|
---|
| 163 | #self.name = name # bacula-dir, bacula-fd ...
|
---|
| 164 | #self.items.sort()
|
---|
| 165 | logger.debug('Created ressource ' + resourcetype + ' with id #' + str(id(self)) )
|
---|
| 166 |
|
---|
| 167 | def getResourcesListByResType(self,restype):
|
---|
| 168 | """
|
---|
| 169 | returns a list of resources of the specified resource type.
|
---|
| 170 | """
|
---|
| 171 | reslist = []
|
---|
| 172 | if restype == 'client' or restype == 'filedaemon':
|
---|
| 173 | for res in self.resources:
|
---|
| 174 | if res.resourcetype == 'client' or res.resourcetype == 'filedaemon':
|
---|
| 175 | reslist.append(res)
|
---|
| 176 | else:
|
---|
| 177 | for res in self.resources:
|
---|
| 178 | if res.resourcetype == restype:
|
---|
| 179 | reslist.append(res)
|
---|
| 180 | return reslist
|
---|
| 181 |
|
---|
| 182 | def getItemsListByItemName(self,itemname):
|
---|
| 183 | '''
|
---|
| 184 | returns a list of items of the specified item name
|
---|
| 185 | '''
|
---|
| 186 | itemlist = []
|
---|
| 187 | for item in self.items:
|
---|
| 188 | if item.name == itemname:
|
---|
| 189 | itemlist.append(item)
|
---|
| 190 | return itemlist
|
---|
| 191 |
|
---|
| 192 |
|
---|
| 193 | def getName(self):
|
---|
| 194 | '''
|
---|
| 195 | gets the value of the item "name"
|
---|
| 196 | '''
|
---|
| 197 | if self.items_dict.has_key('name'):
|
---|
| 198 | return self.items_dict['name'].storage.value.strip('"')
|
---|
| 199 | else:
|
---|
| 200 | return ''
|
---|
| 201 |
|
---|
| 202 | def setName(self,name):
|
---|
| 203 | '''
|
---|
| 204 | gets the value of the item "name"
|
---|
| 205 | '''
|
---|
| 206 | if self.items_dict.has_key('name'):
|
---|
| 207 | self.items_dict['name'].setValue(name)
|
---|
| 208 | else:
|
---|
| 209 | print "could not set name " + name
|
---|
| 210 |
|
---|
| 211 | def getPassword(self):
|
---|
| 212 | '''
|
---|
| 213 | gets the value of the item "password"
|
---|
| 214 | '''
|
---|
| 215 | if self.items_dict.has_key('password'):
|
---|
| 216 | return self.items_dict['password'].storage.value.strip('"')
|
---|
| 217 | else:
|
---|
| 218 | return "ERROR: no password defined"
|
---|
| 219 |
|
---|
| 220 | def getItemValue(self, itemname):
|
---|
| 221 | '''
|
---|
| 222 | gets the value of the itemname
|
---|
| 223 | '''
|
---|
| 224 | if self.items_dict.has_key(itemname):
|
---|
| 225 | return self.items_dict[itemname].storage.value
|
---|
| 226 | else:
|
---|
| 227 | return "ERROR: no item " + itemname + "defined"
|
---|
| 228 |
|
---|
| 229 | def setItemValue(self, itemname, newValue):
|
---|
| 230 | '''
|
---|
| 231 | gets the value of the itemname
|
---|
| 232 | '''
|
---|
| 233 | if self.items_dict.has_key(itemname):
|
---|
| 234 | self.items_dict[itemname].setValue(newValue)
|
---|
| 235 | else:
|
---|
| 236 | print "ERROR: no item " + itemname + "defined"
|
---|
| 237 |
|
---|
| 238 | def __create_valid_items_set__(self):
|
---|
| 239 | """
|
---|
| 240 | create a set of the valid items for this resource.
|
---|
| 241 | """
|
---|
| 242 | self.validitemsset = set()
|
---|
| 243 | for item in self.items:
|
---|
| 244 | self.validitemsset.add(item.name)
|
---|
| 245 |
|
---|
| 246 | def __create_items_dict___(self):
|
---|
| 247 | """
|
---|
| 248 | create a dict with the name of the items as key
|
---|
| 249 | for easier access
|
---|
| 250 | """
|
---|
| 251 | self.items_dict = {}
|
---|
| 252 | for item in self.items:
|
---|
| 253 | self.items_dict[item.name] = item
|
---|
| 254 | item.indentlevel = self.indentlevel + 1
|
---|
| 255 |
|
---|
| 256 | def __str__(self):
|
---|
| 257 | """
|
---|
| 258 | create a string representation of the resource
|
---|
| 259 | including subresources and items
|
---|
| 260 | """
|
---|
| 261 | if self.resourcetype in RESSOURCES_WITH_EQUALSIGN:
|
---|
| 262 | s = "%s%s = { \n" % (self.indentlevel * INDENTSTRING, prettyName(self.resourcetype))#, self.__class__.__name__ +' id: '+ str(id(self)) )
|
---|
| 263 | else:
|
---|
| 264 | s = "%s%s { \n" % (self.indentlevel * INDENTSTRING, prettyName(self.resourcetype))#, self.__class__.__name__ +' id: '+ str(id(self)) )
|
---|
| 265 |
|
---|
| 266 |
|
---|
| 267 |
|
---|
| 268 | # print own items
|
---|
| 269 | for item in self.items:
|
---|
| 270 | item.printall = self.printall
|
---|
| 271 | if str(item) != '':
|
---|
| 272 | s += str(item)
|
---|
| 273 |
|
---|
| 274 | # print subresources
|
---|
| 275 | for v in self.resources:
|
---|
| 276 | s += str(v)
|
---|
| 277 |
|
---|
| 278 | s += '%s}\n' % ( self.indentlevel * INDENTSTRING )
|
---|
| 279 |
|
---|
| 280 | return s
|
---|
| 281 |
|
---|
| 282 | def parse_string(self, configstring):
|
---|
| 283 | '''
|
---|
| 284 | parse resource configuration string and
|
---|
| 285 | set the resource items accordingly.
|
---|
| 286 | '''
|
---|
| 287 | logger.debug( self.resourcetype + " : parse_string called with \n\"" + configstring + '\"' )
|
---|
| 288 |
|
---|
| 289 | #TODO REMOVE THE FOUND SUBBLOCK FROM THE ANALYSIS INSIND OF THE PARENTBLOCK:
|
---|
| 290 | # search for subblocks
|
---|
| 291 | block_to_check = configstring
|
---|
| 292 | blocks = config2blocks(configstring)
|
---|
| 293 | for block in blocks:
|
---|
| 294 | if block['level'] == 1:
|
---|
| 295 | # find containing blocks and only parse the block without the subblocks (resources)
|
---|
| 296 | #logger.debug( "found block:" + str(block['start']) + ':' + str(block['end']) )
|
---|
| 297 | #logger.debug( "block now :" + block_to_check )
|
---|
| 298 | block_to_del = configstring[block['namestart']:block['end']+1]
|
---|
| 299 | logger.debug( "delete:"+ block_to_del + 'in' + block_to_check)
|
---|
| 300 | tmp = block_to_check.replace(block_to_del,'') # remove the subblock/resource
|
---|
| 301 | block_to_check = tmp
|
---|
| 302 |
|
---|
| 303 | #logger.debug(self.resourcetype +':' + block['name'].lower() )
|
---|
| 304 | # parentconfig, resourcetype, name = None, indentlevel = 1, printall = False
|
---|
| 305 | newres = Resource(self, block['name'].lower(), self.indentlevel + 1 )
|
---|
| 306 | if newres != None:
|
---|
| 307 | newres.parse_string(configstring[block['start']+1:block['end']])
|
---|
| 308 | #newres.parse_string(configstring[block['start']+1:block['end']])
|
---|
| 309 | self.resources.append(newres)
|
---|
| 310 | logger.debug( "just appended resource :" + str(id(newres)) )
|
---|
| 311 | else:
|
---|
| 312 | logger.error('did not get a resource back, maybe resource not allowed in this configuration?')
|
---|
| 313 |
|
---|
| 314 |
|
---|
| 315 | ''' find all occurrences of "simple" item = value lines'''
|
---|
| 316 | for line in RXP_SIMPLE_ITEM.finditer(block_to_check):
|
---|
| 317 | logger.debug("checking for simple_items: " +block_to_check)
|
---|
| 318 | #logger.debug( line.groups())
|
---|
| 319 | logger.debug('SIMPLE_ITEM_MATCH:*' + self.resourcetype + '* >' + line.group('itemname') + '< >' + line.group('value') + '<')
|
---|
| 320 | normalized_itemname = line.group('itemname').strip().lower().replace(' ','')
|
---|
| 321 | #logger.debug(str(id(self))+ '*' + str(self))
|
---|
| 322 | if normalized_itemname not in self.validitemsset:
|
---|
| 323 | logger.error( normalized_itemname + ' not allowed in this ressource')
|
---|
| 324 | else:
|
---|
| 325 | logger.debug( normalized_itemname + ' ok in this ressource')
|
---|
| 326 |
|
---|
| 327 | #if normalized_itemname == 'commandacl':
|
---|
| 328 | # self.items_dict[normalized_itemname].ACLDict = commands.keys();
|
---|
| 329 |
|
---|
| 330 | if normalized_itemname not in MULTIPLE_ALLOWED_ITEMS_SET:
|
---|
| 331 | self.items_dict[normalized_itemname].setValue(line.group('value').strip())
|
---|
| 332 |
|
---|
| 333 |
|
---|
| 334 | elif normalized_itemname == 'file':
|
---|
| 335 | newitem = Item('file', 0, 0, False, 'store_dir', False, indentlevel = self.indentlevel + 1) # "File" Items can exist multiple times
|
---|
| 336 | logger.debug( 'created new \"' + normalized_itemname + '\" Item with id #' + str(id(newitem)) )
|
---|
| 337 | newitem.setValue(line.group('value'))
|
---|
| 338 | self.items.append(newitem)
|
---|
| 339 | newitem.parentresource = self
|
---|
| 340 | #logger.debug('appended #' + str(id(newitem)) + str(newitem) + ' to #' + str(id(self)) + self.name + ' ' + self.resourcetype)
|
---|
| 341 | #logger.debug(self.items)
|
---|
| 342 | elif normalized_itemname == 'run':
|
---|
| 343 | newitem = Item('run', '', 0, False, 'store_run', False, indentlevel = self.indentlevel + 1) # "run" Items can exist multiple times
|
---|
| 344 | logger.debug( 'created new \"' + normalized_itemname + '\" Item with id #' + str(id(newitem)) )
|
---|
| 345 | newitem.setValue(line.group('value'))
|
---|
| 346 | self.items.append(newitem)
|
---|
| 347 | newitem.parentresource = self
|
---|
| 348 |
|
---|
| 349 | else:
|
---|
| 350 | logger.debug( 'please create logic for multiple item type ' + normalized_itemname )
|
---|
| 351 |
|
---|
| 352 |
|
---|
| 353 |
|
---|
| 354 |
|
---|
| 355 |
|
---|
| 356 |
|
---|
| 357 | class BaculaConfig(object):
|
---|
| 358 | '''
|
---|
| 359 | base class for bacula config file (console, dir, sd, fd)
|
---|
| 360 | if processEventsCallback is given,it is called at regular basis to enable the
|
---|
| 361 | update of the gui.
|
---|
| 362 | '''
|
---|
| 363 | def __init__(self, configAsString, parentdatacenter = None, processEventsCallback = None, filename = None):
|
---|
| 364 | self.filename = filename
|
---|
| 365 | self.parentdatacenter = parentdatacenter
|
---|
| 366 | self.validresources = eval(self.shortname+'_resources') # TODO: Try/Except
|
---|
| 367 | #self.onlinehelp = {}
|
---|
| 368 | if not self.resources:
|
---|
| 369 | self.resources = []
|
---|
| 370 |
|
---|
| 371 | self.name = '' # Name of director, filedaemon, storage daemon, console
|
---|
| 372 | self.__create_validresources_set__()
|
---|
| 373 |
|
---|
| 374 | if len(configAsString) > 0 : # if configstring is not empty
|
---|
| 375 | self.parse_configfile(configAsString, processEventsCallback)
|
---|
| 376 | else:
|
---|
| 377 | for r in self.validresourcesset: # if configstring is empty -> initialize needed resources
|
---|
| 378 | if (self.__class__.__name__ == 'FileDaemonConfig'
|
---|
| 379 | and r == 'client'): # Filedaemon and Client are the same, we only need one
|
---|
| 380 | continue
|
---|
| 381 | logger.debug("initializing new resource:" + r)
|
---|
| 382 | self.createResource(r)
|
---|
| 383 |
|
---|
| 384 | logger.debug( 'Created BaculaConfig ' + self.__class__.__name__ )
|
---|
| 385 |
|
---|
| 386 | def getName(self):
|
---|
| 387 | '''
|
---|
| 388 | get name from own main resource:
|
---|
| 389 | in director config the name of the director resource,
|
---|
| 390 | other resource files respectively
|
---|
| 391 | '''
|
---|
| 392 | mainresources = self.getResourcesListByResType(self.longname)
|
---|
| 393 | logger.debug(mainresources, self.longname)
|
---|
| 394 | #assert len(mainresources) < 2
|
---|
| 395 | # this assertion can break on console.confs, where multiple consoles can be defined.
|
---|
| 396 | # TODO: check this
|
---|
| 397 | # we only take the name of the first defined console, maybe we should show all names?
|
---|
| 398 | if len(mainresources) == 0:
|
---|
| 399 | return ''
|
---|
| 400 | elif len(mainresources) == 1:
|
---|
| 401 | return mainresources[0].getName()
|
---|
| 402 | else:
|
---|
| 403 | namelist = []
|
---|
| 404 | for res in mainresources:
|
---|
| 405 | namelist.append(res.getName())
|
---|
| 406 | return ','.join(namelist)
|
---|
| 407 |
|
---|
| 408 |
|
---|
| 409 |
|
---|
| 410 | def getPassword(self):
|
---|
| 411 | '''
|
---|
| 412 | get password from own main resource:
|
---|
| 413 | in director config the name of the director resource,
|
---|
| 414 | other resource files respectively
|
---|
| 415 | '''
|
---|
| 416 | mainresources = self.getResourcesListByResType(self.longname)
|
---|
| 417 | logger.debug(mainresources, self.longname)
|
---|
| 418 | #assert len(mainresources) < 2
|
---|
| 419 | # this assertion can break on console.confs, where multiple consoles can be defined.
|
---|
| 420 | # TODO: check this
|
---|
| 421 | # we only take the name of the first defined console, maybe we should show all names?
|
---|
| 422 | if len(mainresources) == 0:
|
---|
| 423 | return ''
|
---|
| 424 | else:
|
---|
| 425 | #return mainresources[0].items_dict['name'].storage.value
|
---|
| 426 | return mainresources[0].getPassword()
|
---|
| 427 |
|
---|
| 428 | def getResourcesListByResType(self,restype):
|
---|
| 429 | """
|
---|
| 430 | returns a list of resources of the specified resource type.
|
---|
| 431 | """
|
---|
| 432 | reslist = []
|
---|
| 433 | for res in self.resources:
|
---|
| 434 | if res.resourcetype == restype:
|
---|
| 435 | reslist.append(res)
|
---|
| 436 | return reslist
|
---|
| 437 |
|
---|
| 438 | def getResourceByName(self,name):
|
---|
| 439 | """
|
---|
| 440 | returns a list of resources with name in parameter "name"
|
---|
| 441 | """
|
---|
| 442 | for res in self.resources:
|
---|
| 443 | #print res.items_dict['name'].storage.value , name
|
---|
| 444 | if str(res.items_dict['name'].storage.value).strip('"') == name.strip('"'):
|
---|
| 445 | return res
|
---|
| 446 | return None
|
---|
| 447 |
|
---|
| 448 | def getReferencingResourcesListForResource(self,resource):
|
---|
| 449 | """
|
---|
| 450 | return a list of resources referencing the given resource
|
---|
| 451 | """
|
---|
| 452 | reslist = []
|
---|
| 453 | for res in self.resources:
|
---|
| 454 | for item in res.items:
|
---|
| 455 | referredType = item.name
|
---|
| 456 | if referredType.endswith('pool'): #incrementalpool, differentialpool, etc
|
---|
| 457 | #print "setting referredType to pool as", referredType
|
---|
| 458 | referredType = 'pool'
|
---|
| 459 | #print "checking:", referredType, resource.resourcetype
|
---|
| 460 |
|
---|
| 461 | # check for overrides in run entry for references
|
---|
| 462 | if referredType == 'run':
|
---|
| 463 | if hasattr(item.storage,'runentry'):# check for runentry in schedules
|
---|
| 464 | #print item.storage.runentry.overrides
|
---|
| 465 | for ov,val in item.storage.runentry.overrides.iteritems():
|
---|
| 466 | #print "checking: ",ov,val
|
---|
| 467 | if val is None:
|
---|
| 468 | continue
|
---|
| 469 | #if ov.endswith('pool'):
|
---|
| 470 | # ovcheck = 'pool'
|
---|
| 471 | #else:
|
---|
| 472 | ovcheck = val
|
---|
| 473 | #print "OVERRIDE_CHECKING",ovcheck,resource.items_dict['name'].storage.value
|
---|
| 474 | if ovcheck == resource.items_dict['name'].storage.value:
|
---|
| 475 | #print "FOUND_OVERRIDE:", ovcheck,resource.items_dict['name'].storage.value
|
---|
| 476 | reslist.append(res)
|
---|
| 477 |
|
---|
| 478 | if referredType == resource.resourcetype:
|
---|
| 479 | #print "found:",item.name, referredType, resource.resourcetype
|
---|
| 480 | #print "comparing", str(item.storage.value).strip('"'), str(resource.items_dict['name'].storage.value).strip('"')
|
---|
| 481 | if item.storage.value != None:
|
---|
| 482 | if str(item.storage.value).strip('"') == resource.items_dict['name'].storage.value.strip('"'):
|
---|
| 483 | #print "FOUND:", item.storage.value, resource.items_dict['name'].storage.value
|
---|
| 484 | reslist.append(res)
|
---|
| 485 | #print item.name,item.storage.value, resource.resourcetype, resource.items_dict['name'].storage.value
|
---|
| 486 |
|
---|
| 487 |
|
---|
| 488 | #if item.value == resource.items_dict['name']:
|
---|
| 489 |
|
---|
| 490 | return reslist
|
---|
| 491 |
|
---|
| 492 | def parse_configfile(self, configstring, callback):
|
---|
| 493 | """
|
---|
| 494 | parses the configstring: removes the comment lines,
|
---|
| 495 | """
|
---|
| 496 |
|
---|
| 497 | cf = ''
|
---|
| 498 | for line in configstring.splitlines(True):
|
---|
| 499 | cf += line[:line.find('#')]+'\n' # remove comments
|
---|
| 500 |
|
---|
| 501 | blocks = config2blocks(cf)
|
---|
| 502 |
|
---|
| 503 | #b = 1
|
---|
| 504 | for block in blocks:
|
---|
| 505 | #print "%d of %d blocks" % (b, len(blocks))
|
---|
| 506 | #b+=1
|
---|
| 507 | if block['level'] == 1:
|
---|
| 508 | logger.debug( block['name'].lower() )
|
---|
| 509 | # TODO: can we call Resource() directly?
|
---|
| 510 |
|
---|
| 511 | newres = self.createResource( block['name'].lower() )
|
---|
| 512 | if callback is not None:
|
---|
| 513 | callback("creating new " + block['name'].lower() + " resource" ) # call callback function after every resource
|
---|
| 514 | if newres != None:
|
---|
| 515 | newres.parse_string(cf[block['start']+1:block['end']])
|
---|
| 516 | if callback is not None:
|
---|
| 517 | callback(newres.getName()) # call callback function after every resource
|
---|
| 518 | else:
|
---|
| 519 | logger.error('did not get a ressource back, maybe ressource not allowed in this configuration?')
|
---|
| 520 |
|
---|
| 521 |
|
---|
| 522 |
|
---|
| 523 | def __str__(self):
|
---|
| 524 | """
|
---|
| 525 | creates the string representation of the configuration file
|
---|
| 526 | by recursively calling the string representation of all resources
|
---|
| 527 | """
|
---|
| 528 | s = '' # string representation
|
---|
| 529 | now = time.asctime()
|
---|
| 530 |
|
---|
| 531 | # set verid string to the date
|
---|
| 532 | # TODO: Make this configurable
|
---|
| 533 | #dirconfs = self.getResourcesListByResType('director')
|
---|
| 534 | #
|
---|
| 535 | #for d in dirconfs:
|
---|
| 536 | # try:
|
---|
| 537 | # d.items_dict['verid'].storage.setValue('" | configuration file created on :' + now + '"' )
|
---|
| 538 | # except:
|
---|
| 539 | # logger.error('verid setting impossible, maybe object not yet initialized?')
|
---|
| 540 |
|
---|
| 541 |
|
---|
| 542 |
|
---|
| 543 | s += '# config file written on ' + now + '\n'
|
---|
| 544 | for v in self.resources:
|
---|
| 545 | s += str(v)
|
---|
| 546 | s += "\n"
|
---|
| 547 | return s
|
---|
| 548 |
|
---|
| 549 |
|
---|
| 550 | def selfcheck(self):
|
---|
| 551 | """
|
---|
| 552 | selfcheck for valid conditions
|
---|
| 553 | TODO documentation
|
---|
| 554 | """
|
---|
| 555 | retval = True
|
---|
| 556 | logger.debug(self.__class__.__name__ + "Selfcheck starts")
|
---|
| 557 | # check if defined resources are allowed
|
---|
| 558 | for res in self.resources:
|
---|
| 559 | if res.resourcetype not in self.validresourcesset:
|
---|
| 560 | logger.error( "Error: resource name " + res.resourcetype + " not allowed")
|
---|
| 561 | retval = False
|
---|
| 562 | else:
|
---|
| 563 | logger.debug(res.resourcetype + " is allowed")
|
---|
| 564 |
|
---|
| 565 | # check if at least one of the needed resources is defined
|
---|
| 566 | for res in self.validresourcesset:
|
---|
| 567 | if self.getResourcesListByResType(res) == None:
|
---|
| 568 | logger.error("Resourctype " + " is missing!")
|
---|
| 569 | retval = False
|
---|
| 570 | else:
|
---|
| 571 | logger.debug(res + " is configured, OK")
|
---|
| 572 | logger.debug(self.__class__.__name__ + "Selfcheck end")
|
---|
| 573 | return retval
|
---|
| 574 |
|
---|
| 575 |
|
---|
| 576 |
|
---|
| 577 | def createResource(self, resourcetype ):
|
---|
| 578 | '''
|
---|
| 579 | creates a ressource of type "ressourcetype"
|
---|
| 580 | inside of this bacula configuration
|
---|
| 581 | '''
|
---|
| 582 | if resourcetype not in self.validresourcesset:
|
---|
| 583 | logger.error("ressource type \"" + resourcetype + "\" not allowed in this configuration")
|
---|
| 584 | else:
|
---|
| 585 | if self.onlinehelp.has_key(resourcetype):
|
---|
| 586 | helpurl = self.onlinehelp[resourcetype]
|
---|
| 587 | else:
|
---|
| 588 | helpurl = ''
|
---|
| 589 | newres = Resource( self, resourcetype, indentlevel = 0, onlinehelpURL = helpurl)
|
---|
| 590 | self.resources.append( newres )
|
---|
| 591 |
|
---|
| 592 | return newres
|
---|
| 593 |
|
---|
| 594 | def deleteResource(self, resource ):
|
---|
| 595 | '''
|
---|
| 596 | delete given resource from own resources
|
---|
| 597 | '''
|
---|
| 598 | try:
|
---|
| 599 | self.resources.remove(resource)
|
---|
| 600 | retval = True
|
---|
| 601 | except:
|
---|
| 602 | logger.error("could not remove resource")
|
---|
| 603 | retval = False
|
---|
| 604 | return retval
|
---|
| 605 |
|
---|
| 606 |
|
---|
| 607 |
|
---|
| 608 | def __create_validresources_set__(self):
|
---|
| 609 | '''
|
---|
| 610 | Create a set of allowed ressources
|
---|
| 611 | inside of this bacula configuration
|
---|
| 612 | '''
|
---|
| 613 | self.validresourcesset = set()
|
---|
| 614 | for validresource in self.validresources:
|
---|
| 615 | self.validresourcesset.add(validresource[0]) # add name
|
---|
| 616 | #print self.validresourcesset
|
---|
| 617 |
|
---|
| 618 |
|
---|
| 619 |
|
---|
| 620 |
|
---|
| 621 | class DirectorConfig(BaculaConfig):
|
---|
| 622 | '''
|
---|
| 623 | Class for configuration of one director ( bacula-dir.conf )
|
---|
| 624 | '''
|
---|
| 625 | def __init__(self, configAsString, parentdatacenter = None, processEventsCallback = None, filename = None):
|
---|
| 626 | self.shortname = 'dird'
|
---|
| 627 | self.longname = 'director'
|
---|
| 628 | self.onlinehelp = onlinehelp[self.longname]
|
---|
| 629 | self.resources = []
|
---|
| 630 | BaculaConfig.__init__(self, configAsString, parentdatacenter, processEventsCallback, filename)
|
---|
| 631 |
|
---|
| 632 |
|
---|
| 633 |
|
---|
| 634 | class StorageDaemonConfig(BaculaConfig):
|
---|
| 635 | '''
|
---|
| 636 | Class for configuration of one storage daemon ( bacula-sd.conf )
|
---|
| 637 | '''
|
---|
| 638 | def __init__(self, configAsString, parentdatacenter = None, processEventsCallback = None, filename = None):
|
---|
| 639 | self.shortname = 'stored'
|
---|
| 640 | #self.longname = 'storagedaemon'
|
---|
| 641 | self.longname = 'storage'
|
---|
[959] | 642 | self.onlinehelp = onlinehelp['storage']
|
---|
[953] | 643 | self.resources = []
|
---|
| 644 | BaculaConfig.__init__(self, configAsString, parentdatacenter, processEventsCallback, filename)
|
---|
| 645 |
|
---|
| 646 |
|
---|
| 647 | class FileDaemonConfig(BaculaConfig):
|
---|
| 648 | '''
|
---|
| 649 | Class for configuration of one storage daemon ( bacula-fd.conf )
|
---|
| 650 | '''
|
---|
| 651 | def __init__(self, configAsString, parentdatacenter = None, processEventsCallback = None, filename = None):
|
---|
| 652 | self.shortname = 'filed'
|
---|
| 653 | self.longname = 'filedaemon'
|
---|
| 654 | self.onlinehelp = onlinehelp['client']
|
---|
| 655 | self.resources = []
|
---|
| 656 | BaculaConfig.__init__(self, configAsString, parentdatacenter , processEventsCallback, filename)
|
---|
| 657 |
|
---|
| 658 |
|
---|
| 659 |
|
---|
| 660 | def createFdConfigFromDirClient(self, dirClient = None):
|
---|
| 661 | '''
|
---|
| 662 | create a Filedaemon Config from a
|
---|
| 663 | Client Config in Director
|
---|
| 664 | we have to set some required values to defaults
|
---|
| 665 | TODO: we should be able to use different defaults for
|
---|
| 666 | different classes of clients (windows, linux, solaris etc.)
|
---|
| 667 | '''
|
---|
| 668 |
|
---|
| 669 | directors = self.getResourcesListByResType('director')
|
---|
| 670 | if len(directors) != 1:
|
---|
| 671 | logger.error("here we should have one director!")
|
---|
| 672 | return None
|
---|
| 673 |
|
---|
| 674 | messages = self.getResourcesListByResType('messages')
|
---|
| 675 | if len(messages) != 1:
|
---|
| 676 | logger.error("here we should have one messages!")
|
---|
| 677 | return None
|
---|
| 678 |
|
---|
| 679 | filedaemons = self.getResourcesListByResType('filedaemon') # same as client
|
---|
| 680 | if len(filedaemons) != 1:
|
---|
| 681 | logger.error("here we should have one filedaemon!")
|
---|
| 682 | return None
|
---|
| 683 |
|
---|
| 684 | dirDirector = dirClient.parentconfig.getResourcesListByResType('director')[0]
|
---|
| 685 |
|
---|
| 686 | # get password and dirname from director config
|
---|
| 687 | directors[0].items_dict['name'].storage.value = dirDirector.items_dict['name'].storage.value
|
---|
| 688 | directors[0].items_dict['password'].storage.value = dirClient.items_dict['password'].storage.value
|
---|
| 689 | filedaemons[0].items_dict['name'].storage.value = dirClient.items_dict['name'].storage.value
|
---|
| 690 |
|
---|
| 691 | self.name = filedaemons[0].items_dict['name'].storage.value
|
---|
| 692 |
|
---|
| 693 | # TODO: make the following configurable
|
---|
| 694 | filedaemons[0].items_dict['workingdirectory'].storage.value = '/var/lib/bacula'
|
---|
| 695 | filedaemons[0].items_dict['piddirectory'].storage.value = '/var/run'
|
---|
| 696 |
|
---|
| 697 | messages[0].items_dict['name'].storage.value = 'Standard'
|
---|
| 698 | messagesentry = directors[0].items_dict['name'].storage.value + ' = all, !skipped, !restored'
|
---|
| 699 | messages[0].items_dict['director'].storage.setValue(messagesentry)
|
---|
| 700 | #messages[0].items_dict['director'].storage.value = directors[0].items_dict['name'].storage.value + ' = all, !skipped, !restored'
|
---|
| 701 |
|
---|
| 702 | #filedaemons[0].items_dict['password'].storage.value = dirClient.items_dict['password'].storage.value
|
---|
| 703 |
|
---|
| 704 | #dirClient.parentconfig.getResourceByName(parentname).items_dict['name']
|
---|
| 705 |
|
---|
| 706 |
|
---|
| 707 |
|
---|
| 708 | #self.items_dict['password'] = DirDirector.items_dict['password']
|
---|
| 709 |
|
---|
| 710 |
|
---|
| 711 |
|
---|
| 712 | class ConsoleConfig(BaculaConfig):
|
---|
| 713 | '''
|
---|
| 714 | Class for configuration of a console ( bconsole.conf )
|
---|
| 715 | '''
|
---|
| 716 | def __init__(self, configAsString, parentdatacenter = None, processEventsCallback = None, filename = None):
|
---|
| 717 | self.shortname = 'console'
|
---|
| 718 | self.longname = 'console'
|
---|
| 719 | self.onlinehelp = onlinehelp[self.longname]
|
---|
| 720 | self.resources = []
|
---|
| 721 | BaculaConfig.__init__(self, configAsString, parentdatacenter, processEventsCallback, filename)
|
---|
| 722 |
|
---|
| 723 |
|
---|
| 724 |
|
---|
| 725 |
|
---|
| 726 |
|
---|
| 727 |
|
---|
| 728 | class DataCenter(object):
|
---|
| 729 | '''
|
---|
| 730 | A datacenter is the sum of all configurations that
|
---|
| 731 | make a running bacula system, i.e. director, storaged,
|
---|
| 732 | console and filed configurations
|
---|
| 733 | A datacenter resides in an own subdirectory
|
---|
| 734 | and has subdirs for consoles, directors, storagedaemons and filedaemons
|
---|
| 735 | /datacenter/
|
---|
| 736 | /datacenter/consoles/
|
---|
| 737 | /datacenter/directors/
|
---|
| 738 | /datacenter/storagedaemons/
|
---|
| 739 | /datacenter/filedaemons/
|
---|
| 740 |
|
---|
| 741 | this directory structure is hidden inside of a tar.gz file
|
---|
| 742 | '''
|
---|
| 743 |
|
---|
| 744 | def __createDataCenterDirs__(self, basedir):
|
---|
| 745 | olddir = os.getcwdu()
|
---|
| 746 | os.mkdir(basedir)
|
---|
| 747 | #os.chdir(basedir)
|
---|
| 748 | for subdir in self.subdirs:
|
---|
| 749 | os.mkdir( os.path.normpath(basedir+'/'+subdir) )
|
---|
| 750 | #os.chdir(olddir)
|
---|
| 751 |
|
---|
| 752 |
|
---|
| 753 |
|
---|
| 754 | def __init__(self, targzfile, callbackfunction = None):
|
---|
| 755 | '''
|
---|
| 756 | extract the targz file,
|
---|
| 757 | open the *.conf file inside the
|
---|
| 758 | subdirs and create the configurations accordingly
|
---|
| 759 | '''
|
---|
| 760 | self.filename = targzfile
|
---|
| 761 | self.subdirs = ['consoles','directors','storagedaemons','filedaemons']
|
---|
| 762 | self.directors = set()
|
---|
| 763 | self.consoles = set()
|
---|
| 764 | self.storagedaemons = set()
|
---|
| 765 | self.filedaemons = set()
|
---|
| 766 | tmpdir = tempfile.mkdtemp(prefix = 'dassmodus-')
|
---|
| 767 | # TODO: delete this after use
|
---|
| 768 |
|
---|
| 769 | # if the targz file does not exist, then create an empty
|
---|
| 770 | # datacenter file
|
---|
| 771 | if not os.path.isfile(targzfile):
|
---|
| 772 | print targzfile + ' does not exist, creating new file'
|
---|
| 773 | self.name='datacenter'
|
---|
| 774 | os.mkdir(tmpdir + '/' + self.name)# datacentername
|
---|
| 775 | for subdir in self.subdirs:
|
---|
| 776 | os.mkdir(tmpdir + '/' + self.name + '/' + subdir)
|
---|
| 777 |
|
---|
| 778 | # create a new tarfile
|
---|
| 779 | tar = tarfile.open(targzfile, "w:gz")
|
---|
| 780 | dirs = glob.glob(os.path.normpath(tmpdir + '/*/*'))
|
---|
| 781 | for d in dirs:
|
---|
| 782 | tar.add(d, arcname = d.replace(tmpdir + '/',''))
|
---|
| 783 | tar.close()
|
---|
| 784 |
|
---|
| 785 |
|
---|
| 786 | # extract subdirs inside of the tarfile into tmp dir
|
---|
| 787 | tar = tarfile.open(targzfile, "r:gz")
|
---|
| 788 |
|
---|
| 789 | #olddir = os.getcwdu()
|
---|
| 790 | #os.chdir(self.tmpdir)
|
---|
| 791 | tar.extractall(path = tmpdir)
|
---|
| 792 | tar.close
|
---|
| 793 |
|
---|
| 794 | basedir = os.listdir(tmpdir)
|
---|
| 795 | datacenterdir = os.path.normpath(tmpdir + '/' + basedir[0])
|
---|
| 796 | #os.chdir(basedir[0]) # change into the
|
---|
| 797 |
|
---|
| 798 | self.name = basedir[0]
|
---|
| 799 |
|
---|
| 800 |
|
---|
| 801 |
|
---|
| 802 | for subdir in self.subdirs:
|
---|
| 803 | files = glob.glob(os.path.normpath(datacenterdir + '/' + subdir + '/*.conf' ) )
|
---|
| 804 | for filename in files:
|
---|
| 805 | if callbackfunction is not None:
|
---|
| 806 | callbackfunction('parsing file ' + filename)
|
---|
| 807 |
|
---|
| 808 | if subdir == 'directors':
|
---|
| 809 | configstring = open(filename).read()
|
---|
| 810 | conf = DirectorConfig(configstring, parentdatacenter = self, filename = filename, processEventsCallback = callbackfunction )
|
---|
| 811 | self.directors.add(conf)
|
---|
| 812 |
|
---|
| 813 | elif subdir == 'storagedaemons':
|
---|
| 814 | configstring = open(filename).read()
|
---|
| 815 | conf = StorageDaemonConfig(configstring, parentdatacenter = self, filename = filename, processEventsCallback = callbackfunction)
|
---|
| 816 | self.storagedaemons.add(conf)
|
---|
| 817 |
|
---|
| 818 | elif subdir == 'filedaemons':
|
---|
| 819 | configstring = open(filename).read()
|
---|
| 820 | conf = FileDaemonConfig(configstring, parentdatacenter = self, filename = filename ,processEventsCallback = callbackfunction)
|
---|
| 821 | self.filedaemons.add(conf)
|
---|
| 822 |
|
---|
| 823 | elif subdir == 'consoles':
|
---|
| 824 | configstring = open(filename).read()
|
---|
| 825 | conf = ConsoleConfig(configstring, parentdatacenter = self, filename = filename, processEventsCallback = callbackfunction)
|
---|
| 826 | self.consoles.add(conf)
|
---|
| 827 | else:
|
---|
| 828 | raise NameError('help me')
|
---|
| 829 |
|
---|
| 830 |
|
---|
| 831 | # remove temporary files
|
---|
| 832 | shutil.rmtree(tmpdir)
|
---|
| 833 | #os.chdir(olddir) # restore working dir
|
---|
| 834 |
|
---|
| 835 |
|
---|
| 836 | def getName(self):
|
---|
| 837 | return self.name
|
---|
| 838 |
|
---|
| 839 | def setName(self, name):
|
---|
| 840 | self.name = name
|
---|
| 841 |
|
---|
| 842 | def setFileName(self, filename):
|
---|
| 843 | self.filename = filename
|
---|
| 844 | self.name = os.path.basename(filename).split('.')[0]
|
---|
| 845 |
|
---|
| 846 | def importConfigurationFile(self, filename, configtype):
|
---|
| 847 | '''
|
---|
| 848 | import a existing configuration file into this
|
---|
| 849 | datacenter.
|
---|
| 850 | allowed configtypes: filedaemon, storagedaemon, console, director
|
---|
| 851 | '''
|
---|
| 852 | print "importing file " + filename + ' ' + configtype
|
---|
| 853 | if configtype == 'filedaemon':
|
---|
| 854 | configstring = open(filename).read()
|
---|
| 855 | conf = FileDaemonConfig(configstring, filename = filename)
|
---|
| 856 | self.filedaemons.add(conf)
|
---|
| 857 |
|
---|
| 858 | elif configtype == 'storagedaemon':
|
---|
| 859 | configstring = open(filename).read()
|
---|
| 860 | conf = StorageDaemonConfig(configstring, filename = filename)
|
---|
| 861 | self.storagedaemons.add(conf)
|
---|
| 862 |
|
---|
| 863 | elif configtype == 'console':
|
---|
| 864 | configstring = open(filename).read()
|
---|
| 865 | conf = ConsoleConfig(configstring, filename = filename)
|
---|
| 866 | self.consoles.add(conf)
|
---|
| 867 |
|
---|
| 868 | elif configtype == 'director':
|
---|
| 869 | configstring = open(filename).read()
|
---|
| 870 | conf = DirectorConfig(configstring, filename = filename)
|
---|
| 871 | self.directors.add(conf)
|
---|
| 872 |
|
---|
| 873 | else:
|
---|
| 874 | raise NameError('Unknown configtype, allowed : filedaemon, storagedaemon, console, director')
|
---|
| 875 | return False
|
---|
| 876 |
|
---|
| 877 |
|
---|
| 878 | def deleteConfiguration(self, configuration):
|
---|
| 879 | '''
|
---|
| 880 | delete the refered configuration resource/configfile
|
---|
| 881 | '''
|
---|
| 882 | for configtype in [self.directors, self.filedaemons, self.storagedaemons, self.consoles]:
|
---|
| 883 | if configuration in configtype:
|
---|
| 884 | configtype.remove(configuration)
|
---|
| 885 | del configuration
|
---|
| 886 | break
|
---|
| 887 |
|
---|
| 888 |
|
---|
| 889 |
|
---|
| 890 |
|
---|
| 891 | def checkFileDaemonsIntegrity(self):
|
---|
| 892 | '''
|
---|
| 893 | Possible configuration problems:
|
---|
| 894 | 1a: - dirconf refers to filedaemon, but no filedaemon conf exists
|
---|
| 895 | 1b: - dirconf refers to filedaemon, but filedaemon conf has wrong password for this director
|
---|
| 896 | 2a: - filedaemon conf refers to Director that does not exist
|
---|
| 897 | 2b: - filedaemon conf refers to existing Director, but password is wrong for this director
|
---|
| 898 | 1b and 2b are the same
|
---|
| 899 |
|
---|
| 900 | this leads to
|
---|
| 901 | 3 cases:
|
---|
| 902 | - Dir does not exist,
|
---|
| 903 | - Filedaemon does not exist,
|
---|
| 904 | - Passwords do not match
|
---|
| 905 | '''
|
---|
| 906 |
|
---|
| 907 | s = '' # return string
|
---|
| 908 | director_filedaemons_passwords = {} # dictionary of director -> filedaemonname -> password, extracted from dirconfs
|
---|
| 909 | filedaemons_directors_passwords = {} # dictionary of filedaemon -> director -> password , extracted from fdconfs
|
---|
| 910 |
|
---|
| 911 | # collect info about all defined filedaemons/clients in ALL Director Configurations
|
---|
| 912 | for dir in self.directors:
|
---|
| 913 | dirfds = dir.getResourcesListByResType('client')
|
---|
| 914 | director_filedaemons_passwords[dir.getName()] = {}
|
---|
| 915 | for fd in dirfds:
|
---|
| 916 | director_filedaemons_passwords[dir.getName()][fd.getName()] = fd.getPassword()
|
---|
| 917 |
|
---|
| 918 | # collect info about all definied Directors in all Filedaemon Configurations
|
---|
| 919 | for fdconf in self.filedaemons:
|
---|
| 920 | filedaemons_directors_passwords[fdconf.getName()] = {}
|
---|
| 921 | for dir in fdconf.getResourcesListByResType('director'):
|
---|
| 922 | filedaemons_directors_passwords[fdconf.getName()][dir.getName()] = dir.getPassword()
|
---|
| 923 |
|
---|
| 924 | #print "Filedaemon View:"
|
---|
| 925 | # check from the view of filedaemons configurations
|
---|
| 926 | for f,d in filedaemons_directors_passwords.iteritems():
|
---|
| 927 | for dir,pw in d.iteritems():
|
---|
| 928 | #print f,dir,pw
|
---|
| 929 | if director_filedaemons_passwords.has_key(dir): # do we have a director config of this director?
|
---|
| 930 | if director_filedaemons_passwords[dir].has_key(f): # has this dir a definition of this fd?
|
---|
| 931 | if director_filedaemons_passwords[dir][f] == pw: # and is the password identical?
|
---|
| 932 | s += "OK: Filedaemon %s has definition of Director %s and password is the same\n" % (f,dir)
|
---|
| 933 | #s += "INFO: Filedaemon %s has definition of Director %s and password is the same: %s\n" % (f,dir,pw)
|
---|
| 934 | else:
|
---|
| 935 | s+= "ERROR: Filedaemon %s has definition of Director %s but password is different: %s != %s\n" % (f,dir,pw,director_filedaemons_passwords[dir][f])
|
---|
| 936 | else:
|
---|
| 937 | s+= "ERROR: Filedaemon %s has not a definition of Director %s\n" % (dir,f)
|
---|
| 938 | else:
|
---|
| 939 | s+= "ERROR: Director configuration for %s is MISSING , it was referenced by configfile of %s\n" % (dir,f)
|
---|
| 940 |
|
---|
| 941 | #print "Director View:"
|
---|
| 942 | # check from the view of director configurations
|
---|
| 943 | for d,f in director_filedaemons_passwords.iteritems():
|
---|
| 944 | for fs,pwd in f.iteritems():
|
---|
| 945 | #print d,fs,pwd
|
---|
| 946 | if filedaemons_directors_passwords.has_key(fs): # do we have a fd-conf for this filedaemon?
|
---|
| 947 | if filedaemons_directors_passwords[fs].has_key(d): # does this fd-conf have a reference to this dir?
|
---|
| 948 | if filedaemons_directors_passwords[fs][d] == pwd: # is the password identical?
|
---|
| 949 | s+= "OK: Director %s is known by Filedaemon %s and passwords are the same.\n" %(d, fs)
|
---|
| 950 | #s+= "OK: Director %s is known by Filedaemon %s and passwords are the same: %s\n" %(d, fs, pwd)
|
---|
| 951 | else:
|
---|
| 952 | s+= "ERROR: Director %s is known by Filedaemon %s, but passwords are NOT the same: %s != %s\n" % (d, fs, pwd,filedaemons_directors_passwords[fs][d])
|
---|
| 953 | else:
|
---|
| 954 | s+= "WARNING: Director %s does not reference Filedaemon %s,that may be OK\n" % (dir, fs)
|
---|
| 955 | # Not every Dir has to reference every Filedaemon
|
---|
| 956 | else:
|
---|
| 957 | s+= "ERROR: fd-conf is MISSING for Filedaemon %s : please import or create.\n" %(fs)
|
---|
| 958 |
|
---|
| 959 | return s
|
---|
| 960 |
|
---|
| 961 |
|
---|
| 962 |
|
---|
| 963 |
|
---|
| 964 |
|
---|
| 965 | def checkStorageDaemonsIntegrity(self):
|
---|
| 966 | '''
|
---|
| 967 | Possible configuration problems:
|
---|
| 968 | 1a: - dirconf refers to storage, but no storagedaemon conf exists with this storage
|
---|
| 969 | 1b: - dirconf refers to storage, storagedaemon has this storage but has wrong password for this director
|
---|
| 970 |
|
---|
| 971 | 2a: - StorageDaemon conf refers to Director that does not exist
|
---|
| 972 | 2b: - StorageDaemon conf refers to existing Director, but password is wrong for this director
|
---|
| 973 |
|
---|
| 974 | 3a: - dirconf refers to Device or Autochanger that is not defined in Storage Daemon
|
---|
| 975 | 3b: - Storage Daemon defines Device or Autochanger that is not used by any Director
|
---|
| 976 | (info, not problem, may be used in a autochanger)
|
---|
| 977 | 4a: - dirconf refers to Device or Autochanger that is defined, but the *MediaType* is not the same
|
---|
| 978 | '''
|
---|
| 979 |
|
---|
| 980 | '''
|
---|
| 981 | Datastructures we need:
|
---|
| 982 |
|
---|
| 983 | # Director view
|
---|
| 984 | directorName - storageName - password
|
---|
| 985 | - Device
|
---|
| 986 | - Media Type
|
---|
| 987 | - AutoChanger?
|
---|
| 988 |
|
---|
| 989 | # Storage view
|
---|
| 990 | storageName - directorName - Password
|
---|
| 991 | - DeviceName - MediaType
|
---|
| 992 | - AutochangerName[Devices]
|
---|
| 993 | '''
|
---|
| 994 |
|
---|
| 995 | director_storages = {}
|
---|
| 996 | storage_directors = {}
|
---|
| 997 |
|
---|
| 998 | # collect info about all defined storages in ALL Director Configurations
|
---|
| 999 | for dir in self.directors:
|
---|
| 1000 | dirstorages = dir.getResourcesListByResType('storage')
|
---|
| 1001 | director_storages[dir.getName()] = {}
|
---|
| 1002 | for storage in dirstorages:
|
---|
| 1003 | director_storages[dir.getName()]['password'] = storage.getPassword()
|
---|
| 1004 | director_storages[dir.getName()]['device'] = storage.getItemValue('device')
|
---|
| 1005 | director_storages[dir.getName()]['mediatype'] = storage.getItemValue('mediatype')
|
---|
| 1006 |
|
---|
| 1007 | # collect info about all definied Directors in all Filedaemon Configurations
|
---|
| 1008 | for sdconf in self.storagedaemons:
|
---|
| 1009 | storage_directors[sdconf.getName()] = {}
|
---|
| 1010 |
|
---|
| 1011 | for dir in sdconf.getResourcesListByResType('director'):
|
---|
| 1012 | storage_directors[sdconf.getName()][dir.getName()] = dir.getPassword()
|
---|
| 1013 |
|
---|
| 1014 | for device in sdconf.getResourcesListByResType('device'):
|
---|
| 1015 | storage_directors[sdconf.getName()][device.getName()] = device.getItemValue('mediatype')
|
---|
| 1016 |
|
---|
| 1017 | for autochanger in sdconf.getResourcesListByResType('autochanger'):
|
---|
| 1018 | storage_directors[sdconf.getName()][autochanger.getName()] = device.getItemValue('device')
|
---|
| 1019 |
|
---|
| 1020 | '''
|
---|
| 1021 | TODO: implement the checks and output
|
---|
| 1022 | TODO: implement test cases for this function!
|
---|
| 1023 | '''
|
---|
| 1024 |
|
---|
| 1025 |
|
---|
| 1026 | def checkConsolesIntegrity(self):
|
---|
| 1027 | '''
|
---|
| 1028 | check if we have a console conf for every main dir in each dirconf (passwds)
|
---|
| 1029 | and if we have a console for every named console in each dir (names)
|
---|
| 1030 | including passwords check
|
---|
| 1031 | '''
|
---|
| 1032 | '''
|
---|
| 1033 | possible configuration problems:
|
---|
| 1034 | - no console.conf for director entry in director configuration (check passwds)
|
---|
| 1035 | - no console.conf for named console entries in director configurations
|
---|
| 1036 | - console.conf for named console entry but passwords not the same
|
---|
| 1037 | - console.conf, whose password does not match name/password of named consoles and
|
---|
| 1038 | not password of anonymous console
|
---|
| 1039 | - console.conf contains console entry that refers a director that is not defined inside of this console conf
|
---|
| 1040 |
|
---|
| 1041 | Datastructures we need:
|
---|
| 1042 | # director view:
|
---|
| 1043 | directorname - mainpassword # anonymous/default console
|
---|
| 1044 | - consolename - password # named console
|
---|
| 1045 | # console view:
|
---|
| 1046 | console - directorname - password # anonymous/default console
|
---|
| 1047 | - consolename - directorname # named console, refers to defined director inside of this configfile
|
---|
| 1048 | # consoles can have multiple director entries, and multiple console entries referring these directors
|
---|
| 1049 | '''
|
---|
| 1050 |
|
---|
| 1051 | directors_consoles = {}
|
---|
| 1052 | consoles_directors = {}
|
---|
| 1053 |
|
---|
| 1054 | for dir in self.directors: # look in all directors of our DataCenter
|
---|
| 1055 | dirname = dir.getName()
|
---|
| 1056 | defaultconsolepassword = dir.getPassword()
|
---|
| 1057 | #dir.getResourcesListByResType('director')[0].getPassword() # we can only have 1 director entry per director conf
|
---|
| 1058 | directors_consoles[dirname]={}
|
---|
| 1059 | directors_consoles[dirname]['defaultconsole'] = defaultconsolepassword
|
---|
| 1060 |
|
---|
| 1061 | for console in dir.getResourcesListByResType('console'):
|
---|
| 1062 | directors_consoles[dirname][console.getName()] = console.getPassword()
|
---|
| 1063 |
|
---|
| 1064 |
|
---|
| 1065 | defconsoles = 0
|
---|
| 1066 | for consoleconf in self.consoles: # check all consoles in DC
|
---|
| 1067 | #print consoleconf
|
---|
| 1068 | consolename = consoleconf.getName()
|
---|
| 1069 | if consolename == '': # we have an defaultconsole
|
---|
| 1070 | defconsoles += 1
|
---|
| 1071 | consolename = '__defaultconsole__%d' % (defconsoles)
|
---|
| 1072 | consoles_directors[consolename]={}
|
---|
| 1073 | consoles_directors[consolename]['directors']= {}
|
---|
| 1074 | consoles_directors[consolename]['consoles'] = {}
|
---|
| 1075 |
|
---|
| 1076 | for dir in consoleconf.getResourcesListByResType('director'):
|
---|
| 1077 | consoles_directors[consolename]['directors'][dir.getName()] = dir.getPassword()
|
---|
| 1078 |
|
---|
| 1079 | for con in consoleconf.getResourcesListByResType('console'):
|
---|
| 1080 | consoles_directors[consolename]['consoles'][con.getItemValue('director')] = {}
|
---|
| 1081 | consoles_directors[consolename]['consoles'][con.getItemValue('director')]['name'] = con.getName()
|
---|
| 1082 | consoles_directors[consolename]['consoles'][con.getItemValue('director')]['password'] = con.getPassword()
|
---|
| 1083 | print "break"
|
---|
| 1084 |
|
---|
| 1085 |
|
---|
| 1086 | s = ''
|
---|
| 1087 | # check the directorconfig view
|
---|
| 1088 | for dir in directors_consoles:
|
---|
| 1089 | defaultpw = directors_consoles[dir]['defaultconsole']
|
---|
| 1090 | for consolename, dirinfo in consoles_directors.iteritems(): # console resource in console config
|
---|
| 1091 | unreferred_dirs = set() # main directors in dirconfs -> Default Consoles
|
---|
| 1092 | if consolename.startswith('__defaultconsole__'): # we have a default console
|
---|
| 1093 | for d,pw in dirinfo['directors'].iteritems():
|
---|
| 1094 | unreferred_dirs.add(d) # remember dirs
|
---|
| 1095 | if d == dir:
|
---|
| 1096 | unreferred_dirs.remove(d)
|
---|
| 1097 | s += "found defaultconsole in console.conf for dir %s" % ( d )
|
---|
| 1098 | if defaultpw == pw:
|
---|
| 1099 | s += " and passwords are the same"
|
---|
| 1100 | else:
|
---|
| 1101 | s += " and passwords are different!"
|
---|
| 1102 | else:
|
---|
| 1103 | s+= "default console not configured for this dir"
|
---|
| 1104 |
|
---|
| 1105 | #print out unreferred main dir confs
|
---|
| 1106 | for unrefdir in unreferred_dirs:
|
---|
| 1107 | s+= "director %s not referred by any console.conf as default console" % (unrefdir)
|
---|
| 1108 |
|
---|
| 1109 | else: # named console
|
---|
| 1110 | print "found named console" ,consolename
|
---|
| 1111 | for c, consdir in dirinfo['consoles'].iteritems():
|
---|
| 1112 | print c, consdir
|
---|
| 1113 |
|
---|
| 1114 | for d,pw in dirinfo['directors'].iteritems():
|
---|
| 1115 | #print d,pw
|
---|
| 1116 | print d, pw, dirinfo['consoles'][d]['password']
|
---|
| 1117 | #print consolename, dirinfo,
|
---|
| 1118 | try:
|
---|
| 1119 | print directors_consoles[dir][d]
|
---|
| 1120 | except:
|
---|
| 1121 | print "no named console for dir " , d
|
---|
| 1122 |
|
---|
| 1123 |
|
---|
| 1124 |
|
---|
| 1125 | # check if we have
|
---|
| 1126 |
|
---|
| 1127 |
|
---|
| 1128 |
|
---|
| 1129 |
|
---|
| 1130 | #unreferred_dirs.add(d) # remember dirs
|
---|
| 1131 | if d == dir:
|
---|
| 1132 | unreferred_dirs.remove(d)
|
---|
| 1133 | s += "found defaultconsole in console.conf for dir %s" % ( d )
|
---|
| 1134 | if defaultpw == pw:
|
---|
| 1135 | s += " and passwords are the same"
|
---|
| 1136 | else:
|
---|
| 1137 | s += " and passwords are different!"
|
---|
| 1138 | else:
|
---|
| 1139 | s+= "default console not configured for this dir"
|
---|
| 1140 |
|
---|
| 1141 | #print out unreferred main dir confs
|
---|
| 1142 | for unrefdir in unreferred_dirs:
|
---|
| 1143 | s+= "director %s not referred by any console.conf as default console" % (unrefdir)
|
---|
| 1144 |
|
---|
| 1145 |
|
---|
| 1146 |
|
---|
| 1147 | #for conscons in consoles_directors
|
---|
| 1148 | # print conscons
|
---|
| 1149 | #referred_dirs.add(conscons[dir])
|
---|
| 1150 |
|
---|
| 1151 | #for consdir in console['directors']:
|
---|
| 1152 | ''' now we have collected all info about defined dirs and consoles in this Datacenter
|
---|
| 1153 | Checks:
|
---|
| 1154 | Director view
|
---|
| 1155 | A: iterate over all directors,
|
---|
| 1156 | I:check if we have a anonymous console conf that refers to the given password
|
---|
| 1157 | II:iterate over every named console:
|
---|
| 1158 | 1.: do we have a director entry in the console conf with the correct name TODO:(address/port)
|
---|
| 1159 | 2.: we have a console entry for this named console with the correct name and dirname
|
---|
| 1160 | AND do we have a director with this dirname defined inside of this particular console conf
|
---|
| 1161 |
|
---|
| 1162 |
|
---|
| 1163 | Console view
|
---|
| 1164 | B: iterate over all consoles,
|
---|
| 1165 | I check if we have a director for every defined director in console (check names)
|
---|
| 1166 | II check if our console definitions refer to defined Director resources inside of this consoleconfig (If we have consoles)
|
---|
| 1167 | III check if we have a named console definition in dirconf of director DIRNAME with the Name of our console conf and the same password
|
---|
| 1168 | IV check for not by console entries referred directors if the console Director Passwd is identical to the Director default password
|
---|
| 1169 |
|
---|
| 1170 | '''
|
---|
| 1171 |
|
---|
| 1172 | '''
|
---|
| 1173 | TODO: implement the checks and output
|
---|
| 1174 | TODO: implement test cases for this function!
|
---|
| 1175 | '''
|
---|
| 1176 |
|
---|
| 1177 |
|
---|
| 1178 |
|
---|
| 1179 | def safeDatacenter(self):
|
---|
| 1180 | '''
|
---|
| 1181 | safe the Datacenter under the known filename
|
---|
| 1182 | '''
|
---|
| 1183 | self.writeDatacenter(os.path.dirname(self.filename))
|
---|
| 1184 |
|
---|
| 1185 | def writeDatacenter(self,targetdir):
|
---|
| 1186 | '''
|
---|
| 1187 | create the subdirs
|
---|
| 1188 | write the configs
|
---|
| 1189 | create tarfile
|
---|
| 1190 | '''
|
---|
| 1191 | tar = tarfile.open(targetdir + '/' + self.name + '.dmdz','w:gz')
|
---|
| 1192 | writedir = tempfile.mkdtemp(prefix = 'dassmodus-')
|
---|
| 1193 | writebasedir = writedir+'/' + self.name
|
---|
| 1194 | self.__createDataCenterDirs__(writebasedir)
|
---|
| 1195 |
|
---|
| 1196 | for director in self.directors:
|
---|
| 1197 | #print director.getName()
|
---|
| 1198 | writefile = open(writebasedir + '/' + 'directors' + '/' + director.getName() + '.conf','w')
|
---|
| 1199 | writefile.write(str(director))
|
---|
| 1200 | writefile.close()
|
---|
| 1201 |
|
---|
| 1202 | for storagedaemon in self.storagedaemons:
|
---|
| 1203 | #print storagedaemon.getName()
|
---|
| 1204 | writefile = open(writebasedir + '/' + 'storagedaemons' + '/' + storagedaemon.getName() + '.conf','w')
|
---|
| 1205 | writefile.write(str(storagedaemon))
|
---|
| 1206 | writefile.close()
|
---|
| 1207 |
|
---|
| 1208 | for filedaemon in self.filedaemons:
|
---|
| 1209 | #print storagedaemon.getName()
|
---|
| 1210 | writefile = open(writebasedir + '/' + 'filedaemons' + '/' + filedaemon.getName() + '.conf','w')
|
---|
| 1211 | writefile.write(str(filedaemon))
|
---|
| 1212 | writefile.close()
|
---|
| 1213 |
|
---|
| 1214 | consolenr = 0
|
---|
| 1215 | for console in self.consoles:
|
---|
| 1216 | #print storagedaemon.getName()
|
---|
| 1217 | name = console.getName()
|
---|
| 1218 | if name == '':
|
---|
| 1219 | consolenr += 1
|
---|
| 1220 | name = "bconsole-%d" % ( consolenr )
|
---|
| 1221 | writefile = open(writebasedir + '/' + 'consoles' + '/' + name + '.conf','w')
|
---|
| 1222 | writefile.write(str(console))
|
---|
| 1223 | writefile.close()
|
---|
| 1224 |
|
---|
| 1225 |
|
---|
| 1226 | #os.chdir(writedir)
|
---|
| 1227 |
|
---|
| 1228 | dirs = glob.glob(os.path.normpath(writedir + '/*/*'))
|
---|
| 1229 | for d in dirs:
|
---|
| 1230 | tar.add(d, arcname = d.replace(writedir+'/',''))
|
---|
| 1231 | tar.close()
|
---|
| 1232 |
|
---|
| 1233 | # remove temp dir
|
---|
| 1234 | shutil.rmtree(writedir)
|
---|
| 1235 |
|
---|
| 1236 |
|
---|
| 1237 |
|
---|
| 1238 |
|
---|
| 1239 |
|
---|
| 1240 | if __name__ == "__main__":
|
---|
| 1241 | #msgsstore = store_msgs("root@localhost = mount")
|
---|
| 1242 | import logging
|
---|
| 1243 | logging.basicConfig(level=logging.DEBUG,
|
---|
| 1244 | format='%(asctime)s %(levelname)s \t (%(module)s:%(lineno)d) %(message)s ',
|
---|
| 1245 | #filename='vanHelsing.log',
|
---|
| 1246 | filemode='w')
|
---|
| 1247 | cfg = '''
|
---|
| 1248 | Pool {
|
---|
| 1249 | LabelFormat = "${Year}-${Month:p/2/0/r}-${Day:p/2/0/r}"
|
---|
| 1250 | }
|
---|
| 1251 | '''
|
---|
| 1252 | dconfig = DirectorConfig(cfg)
|
---|