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