1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 __doc__='''zenrestore
16
17 Restores a zenoss backup created by zenbackup.
18 '''
19
20 import logging
21 import sys
22 import os
23 import os.path
24 import subprocess
25 import tarfile
26 import ConfigParser
27
28 import Globals
29 from ZCmdBase import ZCmdBase
30 from Products.ZenUtils.Utils import zenPath, binPath
31
32 from ZenBackupBase import *
33
34
36
38 ZenBackupBase.__init__(self)
39 self.log = logging.getLogger("zenrestore")
40 logging.basicConfig()
41 if self.options.verbose:
42 self.log.setLevel(10)
43 else:
44 self.log.setLevel(40)
45
47 """basic options setup sub classes can add more options here"""
48 ZenBackupBase.buildOptions(self)
49
50 self.parser.add_option('--file',
51 dest="file",
52 default=None,
53 help='File from which to restore.')
54 self.parser.add_option('--dir',
55 dest="dir",
56 default=None,
57 help='Path to an untarred backup file'
58 ' from which to restore.')
59 self.parser.add_option('--no-zodb',
60 dest="noZODB",
61 default=False,
62 action='store_true',
63 help='Do not restore the ZODB.')
64 self.parser.add_option('--no-eventsdb',
65 dest="noEventsDb",
66 default=False,
67 action='store_true',
68 help='Do not restore the events database.')
69 self.parser.add_option('--no-perfdata',
70 dest="noPerfdata",
71 default=False,
72 action='store_true',
73 help='Do not restore performance data.')
74 self.parser.add_option('--deletePreviousPerfData',
75 dest="deletePreviousPerfData",
76 default=False,
77 action='store_true',
78 help='Delete ALL existing performance data before restoring?')
79 self.parser.add_option('--zenpacks',
80 dest='zenpacks',
81 default=False,
82 action='store_true',
83 help=('Experimental: Restore any ZenPacks in '
84 'the backup. Some ZenPacks may not work '
85 'properly. Reinstall ZenPacks if possible'))
86
101
103 """
104 Find path to sql file in backup, trying gzipped versions
105 Returns path to real file, or none if nothing found
106 """
107 pathFile = os.path.join(self.tempDir, filename)
108 for path in (pathFile, pathFile + '.gz'):
109 if os.path.isfile(path):
110 return path
111 return None
112
114 """
115 Create MySQL database if it doesn't exist.
116 """
117 mysql_cmd = ['mysql', '-u%s' % user]
118 mysql_cmd.extend(passwd)
119 if host and host != 'localhost':
120 mysql_cmd.extend(['--host', host])
121 if self.options.compressTransport:
122 mysql_cmd.append('--compress')
123 if port and str(port) != '3306':
124 mysql_cmd.extend(['--port', str(port)])
125
126 mysql_cmd = subprocess.list2cmdline(mysql_cmd)
127
128 cmd = 'echo "create database if not exists %s" | %s' % (db, mysql_cmd)
129 os.system(cmd)
130
131 if sqlFile.endswith('.gz'):
132 cmd = 'gzip -dc %s | %s %s' % (
133 os.path.join(self.tempDir, sqlFile), mysql_cmd, db
134 )
135 else:
136 cmd = '%s %s < %s' % (
137 mysql_cmd, db, os.path.join(self.tempDir, sqlFile)
138 )
139
140 os.system(cmd)
141
142
144 '''
145 Restore ZEP DB and indexes
146 '''
147 zepSql = self.getSqlFile('zep.sql')
148 if not zepSql:
149 self.msg('This backup does not contain a ZEP database backup.')
150 return
151
152 self.msg('Restoring ZEP database.')
153 self.restoreMySqlDb(self.options.zepdbhost, self.options.zepdbport,
154 self.options.zepdbname, self.options.zepdbuser,
155 self.getPassArg('zepdbpass'), zepSql)
156 self.msg('ZEP database restored.')
157 self.msg('Restoring ZEP indexes.')
158 zepTar = tarfile.open(os.path.join(self.tempDir, 'zep.tar'))
159 zepTar.extractall(zenPath('var'))
160 self.msg('ZEP indexes restored.')
161
162
164 repozoDir = os.path.join(self.tempDir, 'repozo')
165 return os.path.isdir(repozoDir)
166
169
172
184
186 zodbSql = self.getSqlFile('zodb.sql')
187 if not zodbSql:
188 self.msg('This archive does not contain a ZODB backup.')
189 return
190 self.msg('Restoring ZODB database.')
191 self.restoreMySqlDb(self.options.host, self.options.port,
192 self.options.mysqldb, self.options.mysqluser,
193 self.getPassArg('mysqlpasswd'), zodbSql)
194
196 repozoDir = os.path.join(self.tempDir, 'repozo')
197 tempFilePath = os.path.join(self.tempDir, 'Data.fs')
198 tempZodbConvert = os.path.join(self.tempDir, 'convert.conf')
199
200 self.msg('Restoring ZEO backup into MySQL.')
201
202
203 cmd = []
204 cmd.append(binPath('repozo'))
205 cmd.append('--recover')
206 cmd.append('--repository')
207 cmd.append(repozoDir)
208 cmd.append('--output')
209 cmd.append(tempFilePath)
210
211 rc = subprocess.call(cmd, stdout=PIPE, stderr=PIPE)
212 if rc:
213 return -1
214
215
216 zodbconvert_conf = open(tempZodbConvert, 'w')
217 zodbconvert_conf.write('<filestorage source>\n')
218 zodbconvert_conf.write(' path %s\n' % tempFilePath)
219 zodbconvert_conf.write('</filestorage>\n\n')
220
221 zodbconvert_conf.write('<relstorage destination>\n')
222 zodbconvert_conf.write(' <mysql>\n')
223 zodbconvert_conf.write(' host %s\n' % self.options.host)
224 zodbconvert_conf.write(' port %s\n' % self.options.port)
225 zodbconvert_conf.write(' db %s\n' % self.options.mysqldb)
226 zodbconvert_conf.write(' user %s\n' % self.options.mysqluser)
227 zodbconvert_conf.write(' passwd %s\n' % self.options.mysqlpasswd or '')
228 zodbconvert_conf.write(' </mysql>\n')
229 zodbconvert_conf.write('</relstorage>\n')
230 zodbconvert_conf.close()
231
232 rc = subprocess.call(['zodbconvert', '--clear', tempZodbConvert],
233 stdout=PIPE, stderr=PIPE)
234 if rc:
235 return -1
236
237
239 self.msg('Restoring config files.')
240 cmd = 'cp -p %s %s' % (os.path.join(zenPath('etc'), 'global.conf'), self.tempDir)
241 if os.system(cmd): return -1
242 cmd = 'rm -rf %s' % zenPath('etc')
243 if os.system(cmd): return -1
244 cmd = 'tar Cxf %s %s' % (
245 zenPath(),
246 os.path.join(self.tempDir, 'etc.tar')
247 )
248 if os.system(cmd): return -1
249 if not os.path.exists(os.path.join(zenPath('etc'), 'global.conf')):
250 self.msg('Restoring default global.conf')
251 cmd = 'mv %s %s' % (os.path.join(self.tempDir, 'global.conf'), zenPath('etc'))
252 if os.system(cmd): return -1
253
255 self.msg('Restoring ZenPacks.')
256 cmd = 'rm -rf %s' % zenPath('ZenPacks')
257 if os.system(cmd): return -1
258 cmd = 'tar Cxf %s %s' % (
259 zenPath(),
260 os.path.join(self.tempDir, 'ZenPacks.tar'))
261 if os.system(cmd): return -1
262
263
264 tempBin = os.path.join(self.tempDir, 'bin.tar')
265 if os.path.isfile(tempBin):
266 self.msg('Restoring bin dir.')
267
268 cmd = ['tar', 'Cxfk', zenPath(),
269 os.path.join(self.tempDir, 'bin.tar')]
270 self.runCommand(cmd)
271
273 dmd = ZCmdBase(noopts=True).dmd
274 self.log.info("Restoring ZenPack contents.")
275 for pack in dmd.ZenPackManager.packs():
276 pack.restore(self.tempDir, self.log)
277 self.log.info("ZenPack contents restored.")
278
280 cmd = 'rm -rf %s' % os.path.join(zenPath(), 'perf')
281 if os.system(cmd): return -1
282 self.msg('Restoring performance data.')
283 cmd = 'tar Cxf %s %s' % (
284 zenPath(),
285 os.path.join(self.tempDir, 'perf.tar'))
286 if os.system(cmd): return -1
287
289 """
290 Restore from a previous backup
291 """
292 if self.options.file and self.options.dir:
293 sys.stderr.write('You cannot specify both --file and --dir.\n')
294 sys.exit(-1)
295 elif not self.options.file and not self.options.dir:
296 sys.stderr.write('You must specify either --file or --dir.\n')
297 sys.exit(-1)
298
299
300
301 rootTempDir = ''
302 if self.options.file:
303 if not os.path.isfile(self.options.file):
304 sys.stderr.write('The specified backup file does not exist: %s\n' %
305 self.options.file)
306 sys.exit(-1)
307
308 self.msg('Unpacking backup file')
309 rootTempDir = self.getTempDir()
310 cmd = 'tar xzfC %s %s' % (self.options.file, rootTempDir)
311 if os.system(cmd): return -1
312 self.tempDir = os.path.join(rootTempDir, BACKUP_DIR)
313 else:
314 self.msg('Using %s as source of restore' % self.options.dir)
315 if not os.path.isdir(self.options.dir):
316 sys.stderr.write('The specified backup directory does not exist:'
317 ' %s\n' % self.options.dir)
318 sys.exit(-1)
319 self.tempDir = self.options.dir
320
321
322 self.getSettings()
323
324 if self.options.zenpacks and not self.hasZODBBackup():
325 sys.stderr.write('Archive does not contain ZODB backup; cannot'
326 'restore ZenPacks')
327 sys.exit(-1)
328
329
330 if self.hasZODBBackup():
331 self.restoreZODB()
332 else:
333 self.msg('Archive does not contain a ZODB backup')
334
335
336 self.restoreEtcFiles()
337
338
339 if self.options.zenpacks:
340 tempPacks = os.path.join(self.tempDir, 'ZenPacks.tar')
341 if os.path.isfile(tempPacks):
342 self.restoreZenPacks()
343 self.restoreZenPackContents()
344 else:
345 self.msg('Backup contains no ZenPacks.')
346
347
348 tempPerf = os.path.join(self.tempDir, 'perf.tar')
349 if os.path.isfile(tempPerf):
350 self.restorePerfData()
351 else:
352 self.msg('Backup contains no perf data.')
353
354
355 if self.options.noEventsDb:
356 self.msg('Skipping the events database.')
357 else:
358 self.restoreZEP()
359
360
361 if self.options.file:
362 self.msg('Cleaning up temporary files.')
363 cmd = 'rm -r %s' % rootTempDir
364 if os.system(cmd): return -1
365
366 self.msg('Restore complete.')
367 return 0
368
370 self.msg('Flushing memcached cache.')
371 import memcache
372 mc = memcache.Client(cacheservers, debug=0)
373 mc.flush_all()
374 mc.disconnect_all()
375 self.msg('Completed flushing memcached cache.')
376
377 if __name__ == '__main__':
378 zb = ZenRestore()
379 if zb.doRestore():
380 sys.exit(-1)
381