Package ZenUtils :: Module ZenBackup
[hide private]
[frames] | no frames]

Source Code for Module ZenUtils.ZenBackup

  1  #! /usr/bin/env python  
  2  ########################################################################### 
  3  # 
  4  # This program is part of Zenoss Core, an open source monitoring platform. 
  5  # Copyright (C) 2007, Zenoss Inc. 
  6  # 
  7  # This program is free software; you can redistribute it and/or modify it 
  8  # under the terms of the GNU General Public License version 2 as published by 
  9  # the Free Software Foundation. 
 10  # 
 11  # For complete information please visit: http://www.zenoss.com/oss/ 
 12  # 
 13  ########################################################################### 
 14   
 15   
 16  __doc__='''zenbackup 
 17   
 18  Creates backup of zope data files, zenoss conf files and the events database. 
 19  ''' 
 20   
 21  import Globals 
 22  from ZCmdBase import ZCmdBase 
 23  import sys 
 24  import os 
 25  import os.path 
 26  from datetime import date 
 27  import ConfigParser 
 28  import commands 
 29  import tarfile 
 30  from Products.ZenUtils.Utils import zenPath, binPath 
 31  from ZenBackupBase import * 
 32   
 33   
 34  MAX_UNIQUE_NAME_ATTEMPTS = 1000 
 35   
 36   
37 -class ZenBackup(ZenBackupBase):
38 39
40 - def isZeoUp(self):
41 ''' Returns True is zeo appears to be running, false otherwise. 42 ''' 43 # zeoup.py should live in either $ZOPEHOME/lib/bin/ (for the 44 # appliance) or in $ZENHOME/bin (other installs.) 45 cmd = '%s %s -p 8100 -h localhost' % ( 46 binPath('python'), binPath('zeoup.py')) 47 output = commands.getoutput(cmd) 48 return output.startswith('Elapsed time:')
49 50
51 - def readSettingsFromZeo(self):
52 ''' Return dbname, dbuser, dbpass from saved settings 53 ''' 54 zcmd = ZCmdBase(noopts=True) 55 zem = zcmd.dmd.ZenEventManager 56 for key, default, zemAttr in CONFIG_FIELDS: 57 if not getattr(self.options, key, None): 58 setattr(self.options, key, 59 getattr(zem, zemAttr, None) or default)
60 61
62 - def saveSettings(self, tempDir):
63 ''' Save some of the options to a file for use during restore 64 ''' 65 config = ConfigParser.SafeConfigParser() 66 config.add_section(CONFIG_SECTION) 67 config.set(CONFIG_SECTION, 'dbname', self.options.dbname) 68 config.set(CONFIG_SECTION, 'dbuser', self.options.dbuser) 69 if self.options.dbpass != None: 70 config.set(CONFIG_SECTION, 'dbpass', self.options.dbpass) 71 f = open(os.path.join(tempDir, CONFIG_FILE), 'w') 72 try: 73 config.write(f) 74 finally: 75 f.close()
76 77
78 - def getDefaultBackupFile(self):
79 def getName(index=0): 80 return 'zenbackup_%s%s.tgz' % (date.today().strftime('%Y%m%d'), 81 (index and '_%s' % index) or '')
82 backupDir = zenPath('backups') 83 if not os.path.exists(backupDir): 84 os.mkdir(backupDir, 0750) 85 for i in range(MAX_UNIQUE_NAME_ATTEMPTS): 86 name = os.path.join(backupDir, getName(i)) 87 if not os.path.exists(name): 88 break 89 else: 90 sys.stderr.write('Can not determine a unique file name to us' 91 ' in the backup directory (%s).' % backupDir + 92 ' Use --outfile to specify location for the backup' 93 ' file.\n') 94 sys.exit(-1) 95 return name
96 97
98 - def buildOptions(self):
99 """basic options setup sub classes can add more options here""" 100 # pychecker can't handle strings made of multiple tokens 101 __pychecker__ = 'no-noeffect no-constCond' 102 ZenBackupBase.buildOptions(self) 103 self.parser.add_option('--dbname', 104 dest='dbname', 105 default=None, 106 help='MySQL events database name.' 107 ' By default this will be fetched from zenoss' 108 ' unless --dont-fetch-args is set.'), 109 self.parser.add_option('--dbuser', 110 dest='dbuser', 111 default=None, 112 help='MySQL username.' 113 ' By default this will be fetched from zenoss' 114 ' unless --dont-fetch-args is set.'), 115 self.parser.add_option('--dbpass', 116 dest='dbpass', 117 default=None, 118 help='MySQL password.' 119 ' By default this will be fetched from zenoss' 120 ' unless --dont-fetch-args is set.'), 121 self.parser.add_option('--dont-fetch-args', 122 dest='fetchArgs', 123 default=True, 124 action='store_false', 125 help='By default dbname, dbuser and dbpass' 126 ' are retrieved from zenoss if not' 127 ' specified and if zenoss is available.' 128 ' This disables fetching of these values' 129 ' from zenoss.') 130 self.parser.add_option('--file', 131 dest="file", 132 default=None, 133 help='File to backup to.' 134 ' Backups will by default be placed' 135 ' in $ZENHOME/backups/') 136 self.parser.add_option('--no-eventsdb', 137 dest="noEventsDb", 138 default=False, 139 action='store_true', 140 help='Do not include the events database' 141 ' in the backup.') 142 self.parser.add_option('--stdout', 143 dest="stdout", 144 default=False, 145 action='store_true', 146 help='Send backup to stdout instead of a file') 147 self.parser.add_option('--save-mysql-access', 148 dest='saveSettings', 149 default=False, 150 action='store_true', 151 help='Include dbname, dbuser and dbpass' 152 ' in backup' 153 ' file for use during restore.')
154 155
156 - def makeBackup(self):
157 ''' Create a backup of the data and configuration for a zenoss install. 158 getWhatYouCan == True means to continue without reporting errors even 159 if this appears to be an incomplete zenoss install. 160 ''' 161 162 # Output from --verbose would screw up backup being sent to 163 # stdout because of --stdout 164 if self.options.stdout and self.options.verbose: 165 sys.stderr.write('You cannot specify both' 166 ' --stdout and --verbose.\n') 167 sys.exit(-1) 168 169 # Setup defaults for db info 170 if self.options.fetchArgs and not self.options.noEventsDb: 171 if self.isZeoUp(): 172 self.msg('Getting mysql dbname, user, password from zeo') 173 self.readSettingsFromZeo() 174 else: 175 self.msg('Unable to get mysql info from zeo.' 176 ' Looks like zeo is not running.') 177 178 if not self.options.dbname: 179 self.options.dbname = 'events' 180 if not self.options.dbuser: 181 self.options.dbuser = 'zenoss' 182 # A passwd of '' might be valid. A passwd of None is interpretted 183 # as no password. 184 185 # Create temp backup dir 186 rootTempDir = self.getTempDir() 187 tempDir = os.path.join(rootTempDir, BACKUP_DIR) 188 os.mkdir(tempDir, 0750) 189 190 # Save options to a file for use during restore 191 if self.options.saveSettings: 192 self.saveSettings(tempDir) 193 194 # mysqldump to backup dir 195 if self.options.noEventsDb: 196 self.msg('Skipping backup of events database.') 197 else: 198 self.msg('Backup up events database.') 199 cmd = 'mysqldump -u"%s" %s %s --routines %s > %s' % ( 200 self.options.dbuser, 201 self.getPassArg(), 202 "--single-transaction", 203 self.options.dbname, 204 os.path.join(tempDir, 'events.sql')) 205 if os.system(cmd): return -1 206 207 # backup zopedb 208 self.msg('Backing up zeo database.') 209 repozoDir = os.path.join(tempDir, 'repozo') 210 os.mkdir(repozoDir, 0750) 211 cmd = ('%s %s --backup --full ' % 212 (binPath('python'), binPath('repozo.py')) + 213 '--repository %s --file %s' % 214 (repozoDir, zenPath('var', 'Data.fs'))) 215 if os.system(cmd): return -1 216 217 # /etc to backup dir (except for sockets) 218 self.msg('Backing up config files.') 219 etcTar = tarfile.open(os.path.join(tempDir, 'etc.tar'), 'w') 220 etcTar.add(zenPath('etc'), 'etc') 221 etcTar.close() 222 223 # /perf to backup dir 224 if os.path.isdir(zenPath('perf')): 225 self.msg('Backing up performance data.') 226 perfTar = tarfile.open(os.path.join(tempDir, 'perf.tar'), 'w') 227 perfTar.add(zenPath('perf'), 'perf') 228 perfTar.close() 229 else: 230 self.msg('$ZENHOME/perf does not exist, skipping.') 231 232 # tar, gzip and send to outfile 233 self.msg('Packaging backup file.') 234 if self.options.file: 235 outfile = self.options.file 236 else: 237 outfile = self.getDefaultBackupFile() 238 tempHead, tempTail = os.path.split(tempDir) 239 tarFile = outfile 240 if self.options.stdout: 241 tarFile = '-' 242 cmd = 'tar czfC %s %s %s' % (tarFile, tempHead, tempTail) 243 self.msg('Backup file written to %s' % outfile) 244 245 if os.system(cmd): return -1 246 247 # clean up 248 self.msg('Cleaning up temporary files.') 249 cmd = 'rm -r %s' % rootTempDir 250 if os.system(cmd): return -1 251 252 self.msg('Backup complete.') 253 return 0
254 255 256 if __name__ == '__main__': 257 zb = ZenBackup() 258 if zb.makeBackup(): 259 sys.exit(-1) 260