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 ConfigParser
25
26 import Globals
27 from Products.ZenUtils.Utils import zenPath, binPath
28
29 from ZenBackupBase import *
30
31
33
35 ZenBackupBase.__init__(self)
36 self.log = logging.getLogger("zenrestore")
37 logging.basicConfig()
38 if self.options.verbose:
39 self.log.setLevel(10)
40 else:
41 self.log.setLevel(40)
42
44 """basic options setup sub classes can add more options here"""
45 ZenBackupBase.buildOptions(self)
46
47 self.parser.add_option('--dbname',
48 dest='dbname',
49 default=None,
50 help='MySQL events database name. Defaults'
51 ' to value saved with backup or "events".')
52 self.parser.add_option('--dbuser',
53 dest='dbuser',
54 default=None,
55 help='MySQL username. Defaults'
56 ' to value saved with backup or "zenoss".')
57 self.parser.add_option('--dbpass',
58 dest='dbpass',
59 default=None,
60 help='MySQL password. Defaults'
61 ' to value saved with backup.')
62 self.parser.add_option('--dbhost',
63 dest='dbhost',
64 default='localhost',
65 help='MySQL server host.'
66 ' Defaults to value saved with backup.'),
67 self.parser.add_option('--dbport',
68 dest='dbport',
69 default='3306',
70 help='MySQL server port number.'
71 ' Defaults to value saved with backup.'),
72 self.parser.add_option('--file',
73 dest="file",
74 default=None,
75 help='File from which to restore.')
76 self.parser.add_option('--dir',
77 dest="dir",
78 default=None,
79 help='Path to an untarred backup file'
80 ' from which to restore.')
81 self.parser.add_option('--no-zodb',
82 dest="noZODB",
83 default=False,
84 action='store_true',
85 help='Do not restore the ZODB.')
86 self.parser.add_option('--no-eventsdb',
87 dest="noEventsDb",
88 default=False,
89 action='store_true',
90 help='Do not restore the events database.')
91 self.parser.add_option('--no-perfdata',
92 dest="noPerfdata",
93 default=False,
94 action='store_true',
95 help='Do not restore performance data.')
96 self.parser.add_option('--deletePreviousPerfData',
97 dest="deletePreviousPerfData",
98 default=False,
99 action='store_true',
100 help='Delete ALL existing performance data before restoring?')
101 self.parser.add_option('--zenpacks',
102 dest='zenpacks',
103 default=False,
104 action='store_true',
105 help=('Experimental: Restore any ZenPacks in '
106 'the backup. Some ZenPacks may not work '
107 'properly. Reinstall ZenPacks if possible'))
108
110 ''' Retrieve some options from settings file
111 '''
112 try:
113 f = open(os.path.join(tempDir, CONFIG_FILE), 'r')
114 except:
115 return
116 try:
117 config = ConfigParser.SafeConfigParser()
118 config.readfp(f)
119 finally:
120 f.close()
121 for key, default, zemAttr in CONFIG_FIELDS:
122 if getattr(self.options, key, None) == None:
123 if config.has_option(CONFIG_SECTION, key):
124 setattr(self.options, key, config.get(CONFIG_SECTION, key))
125 else:
126 setattr(self.options, key, default)
127
128
130 '''
131 Create the events schema in MySQL if it does not exist.
132 Return true if the command was able to complete, otherwise
133 (eg permissions or login error), return false.
134 '''
135
136
137
138 sql = 'create database if not exists %s' % self.options.dbname
139 if self.runMysqlCmd(sql):
140 self.msg('MySQL events database creation was successful.')
141 return True
142 else:
143 self.msg('MySQL events database creation faild and returned %d' % result[2])
144 return False
145
147 """
148 Restore the MySQL events database
149 """
150 eventsSql = os.path.join(tempDir, 'events.sql')
151 if not os.path.isfile(eventsSql):
152 self.msg('This backup does not contain an events database backup.')
153 return
154
155
156 self.msg('Creating the events database (if necessary).')
157 if not self.createMySqlDb():
158 return
159
160
161 self.msg('Restoring events database.')
162 sql = 'source %s' % eventsSql
163 if self.runMysqlCmd(sql, switchDB=True):
164 self.msg('Successfully loaded events into MySQL database.')
165 else:
166 self.msg('FAILED to load events into MySQL events database.')
167
169 '''
170 Restore from a previous backup
171 '''
172 def hasZeoBackup(tempDir):
173 repozoDir = os.path.join(tempDir, 'repozo')
174 return os.path.isdir(repozoDir)
175
176 if self.options.file and self.options.dir:
177 sys.stderr.write('You cannot specify both --file and --dir.\n')
178 sys.exit(-1)
179 elif not self.options.file and not self.options.dir:
180 sys.stderr.write('You must specify either --file or --dir.\n')
181 sys.exit(-1)
182
183
184
185
186 rootTempDir = ''
187 if self.options.file:
188 if not os.path.isfile(self.options.file):
189 sys.stderr.write('The specified backup file does not exist: %s\n' %
190 self.options.file)
191 sys.exit(-1)
192
193 self.msg('Unpacking backup file')
194 rootTempDir = self.getTempDir()
195 cmd = 'tar xzfC %s %s' % (self.options.file, rootTempDir)
196 if os.system(cmd): return -1
197 tempDir = os.path.join(rootTempDir, BACKUP_DIR)
198 else:
199 self.msg('Using %s as source of restore' % self.options.dir)
200 if not os.path.isdir(self.options.dir):
201 sys.stderr.write('The specified backup directory does not exist:'
202 ' %s\n' % self.options.dir)
203 sys.exit(-1)
204 tempDir = self.options.dir
205
206 if self.options.zenpacks and not hasZeoBackup(tempDir):
207 sys.stderr.write('archive does not contain ZEO database backup, '
208 'cannot restore ZenPacks.\n')
209 sys.exit(-1)
210
211
212 self.getSettings(tempDir)
213 if not self.options.dbname:
214 self.options.dbname = 'events'
215 if not self.options.dbuser:
216 self.options.dbuser = 'zenoss'
217
218
219
220
221 if not os.path.isfile(zenPath('var', 'Data.fs')):
222 self.msg('There does not appear to be a zeo database.'
223 ' Starting zeo to create one.')
224 os.system(binPath('zeoctl') + 'start > /dev/null')
225 os.system(binPath('zeoctl') + 'stop > /dev/null')
226
227
228 if self.options.noZODB:
229 self.msg('Skipping the ZEO database..')
230 elif hasZeoBackup(tempDir):
231 repozoDir = os.path.join(tempDir, 'repozo')
232 self.msg('Restoring the ZEO database.')
233 cmd ='%s %s --recover --repository %s --output %s' % (
234 binPath('python'),
235 binPath('repozo.py'),
236 repozoDir,
237 zenPath('var', 'Data.fs'))
238 if os.system(cmd): return -1
239 else:
240 self.msg('Archive does not contain ZEO database backup')
241
242
243 self.msg('Restoring config files.')
244 cmd = 'rm -rf %s' % zenPath('etc')
245 if os.system(cmd): return -1
246 cmd = 'tar Cxf %s %s' % (
247 zenPath(),
248 os.path.join(tempDir, 'etc.tar'))
249 if os.system(cmd): return -1
250
251
252
253 if not self.options.noZODB and \
254 self.options.zenpacks and \
255 hasZeoBackup(tempDir):
256 tempPacks = os.path.join(tempDir, 'ZenPacks.tar')
257 if os.path.isfile(tempPacks):
258 self.msg('Restoring ZenPacks.')
259 cmd = 'rm -rf %s' % zenPath('ZenPacks')
260 if os.system(cmd): return -1
261 cmd = 'tar Cxf %s %s' % (
262 zenPath(),
263 os.path.join(tempDir, 'ZenPacks.tar'))
264 if os.system(cmd): return -1
265
266
267 tempBin = os.path.join(tempDir, 'bin.tar')
268 if os.path.isfile(tempBin):
269 self.msg('Restoring bin dir.')
270
271 cmd = ['tar', 'Cxfk', zenPath(),
272 os.path.join(tempDir, 'bin.tar')]
273 self.runCommand(cmd)
274 else:
275 self.msg('Backup contains no ZenPacks.')
276
277
278 if self.options.noPerfdata:
279 self.msg('Skipping performance data.')
280 else:
281 tempPerf = os.path.join(tempDir, 'perf.tar')
282 if os.path.isfile(tempPerf):
283 if self.options.deletePreviousPerfData:
284 self.msg('Removing previous performance data...')
285 cmd = 'rm -rf %s' % os.path.join(zenPath(), 'perf')
286 if os.system(cmd):
287 return -1
288
289 self.msg('Restoring performance data.')
290 cmd = 'tar Cxf %s %s' % (
291 zenPath(),
292 os.path.join(tempDir, 'perf.tar'))
293 if os.system(cmd): return -1
294 else:
295 self.msg('Backup contains no perf data.')
296
297 if self.options.noEventsDb:
298 self.msg('Skipping the events database.')
299 else:
300 self.restoreEventsDatabase(tempDir)
301
302
303 if self.options.file:
304 self.msg('Cleaning up temporary files.')
305 cmd = 'rm -r %s' % rootTempDir
306 if os.system(cmd): return -1
307
308 self.msg('Restore complete.')
309 return 0
310
311
312 if __name__ == '__main__':
313 zb = ZenRestore()
314 if zb.doRestore():
315 sys.exit(-1)
316