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