1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 """
39 Implements the standard 'validate' action.
40 @sort: executeValidate
41 @author: Kenneth J. Pronovici <pronovic@ieee.org>
42 """
43
44
45
46
47
48
49
50 import os
51 import logging
52
53
54 from CedarBackup3.util import getUidGid, getFunctionReference
55 from CedarBackup3.actions.util import createWriter
56
57
58
59
60
61
62 logger = logging.getLogger("CedarBackup3.log.actions.validate")
63
64
65
66
67
68
69
70
71
72
74 """
75 Executes the validate action.
76
77 This action validates each of the individual sections in the config file.
78 This is a "runtime" validation. The config file itself is already valid in
79 a structural sense, so what we check here that is that we can actually use
80 the configuration without any problems.
81
82 There's a separate validation function for each of the configuration
83 sections. Each validation function returns a true/false indication for
84 whether configuration was valid, and then logs any configuration problems it
85 finds. This way, one pass over configuration indicates most or all of the
86 obvious problems, rather than finding just one problem at a time.
87
88 Any reported problems will be logged at the ERROR level normally, or at the
89 INFO level if the quiet flag is enabled.
90
91 @param configPath: Path to configuration file on disk.
92 @type configPath: String representing a path on disk.
93
94 @param options: Program command-line options.
95 @type options: Options object.
96
97 @param config: Program configuration.
98 @type config: Config object.
99
100 @raise ValueError: If some configuration value is invalid.
101 """
102 logger.debug("Executing the 'validate' action.")
103 if options.quiet:
104 logfunc = logger.info
105 else:
106 logfunc = logger.error
107 valid = True
108 valid &= _validateReference(config, logfunc)
109 valid &= _validateOptions(config, logfunc)
110 valid &= _validateCollect(config, logfunc)
111 valid &= _validateStage(config, logfunc)
112 valid &= _validateStore(config, logfunc)
113 valid &= _validatePurge(config, logfunc)
114 valid &= _validateExtensions(config, logfunc)
115 if valid:
116 logfunc("Configuration is valid.")
117 else:
118 logfunc("Configuration is not valid.")
119
120
121
122
123
124
125
126
127
128
129 -def _checkDir(path, writable, logfunc, prefix):
130 """
131 Checks that the indicated directory is OK.
132
133 The path must exist, must be a directory, must be readable and executable,
134 and must optionally be writable.
135
136 @param path: Path to check.
137 @param writable: Check that path is writable.
138 @param logfunc: Function to use for logging errors.
139 @param prefix: Prefix to use on logged errors.
140
141 @return: True if the directory is OK, False otherwise.
142 """
143 if not os.path.exists(path):
144 logfunc("%s [%s] does not exist." % (prefix, path))
145 return False
146 if not os.path.isdir(path):
147 logfunc("%s [%s] is not a directory." % (prefix, path))
148 return False
149 if not os.access(path, os.R_OK):
150 logfunc("%s [%s] is not readable." % (prefix, path))
151 return False
152 if not os.access(path, os.X_OK):
153 logfunc("%s [%s] is not executable." % (prefix, path))
154 return False
155 if writable and not os.access(path, os.W_OK):
156 logfunc("%s [%s] is not writable." % (prefix, path))
157 return False
158 return True
159
160
161
162
163
164
166 """
167 Execute runtime validations on reference configuration.
168
169 We only validate that reference configuration exists at all.
170
171 @param config: Program configuration.
172 @param logfunc: Function to use for logging errors
173
174 @return: True if configuration is valid, false otherwise.
175 """
176 valid = True
177 if config.reference is None:
178 logfunc("Required reference configuration does not exist.")
179 valid = False
180 return valid
181
182
183
184
185
186
188 """
189 Execute runtime validations on options configuration.
190
191 The following validations are enforced:
192
193 - The options section must exist
194 - The working directory must exist and must be writable
195 - The backup user and backup group must exist
196
197 @param config: Program configuration.
198 @param logfunc: Function to use for logging errors
199
200 @return: True if configuration is valid, false otherwise.
201 """
202 valid = True
203 if config.options is None:
204 logfunc("Required options configuration does not exist.")
205 valid = False
206 else:
207 valid &= _checkDir(config.options.workingDir, True, logfunc, "Working directory")
208 try:
209 getUidGid(config.options.backupUser, config.options.backupGroup)
210 except ValueError:
211 logfunc("Backup user:group [%s:%s] invalid." % (config.options.backupUser, config.options.backupGroup))
212 valid = False
213 return valid
214
215
216
217
218
219
221 """
222 Execute runtime validations on collect configuration.
223
224 The following validations are enforced:
225
226 - The target directory must exist and must be writable
227 - Each of the individual collect directories must exist and must be readable
228
229 @param config: Program configuration.
230 @param logfunc: Function to use for logging errors
231
232 @return: True if configuration is valid, false otherwise.
233 """
234 valid = True
235 if config.collect is not None:
236 valid &= _checkDir(config.collect.targetDir, True, logfunc, "Collect target directory")
237 if config.collect.collectDirs is not None:
238 for collectDir in config.collect.collectDirs:
239 valid &= _checkDir(collectDir.absolutePath, False, logfunc, "Collect directory")
240 return valid
241
242
243
244
245
246
248 """
249 Execute runtime validations on stage configuration.
250
251 The following validations are enforced:
252
253 - The target directory must exist and must be writable
254 - Each local peer's collect directory must exist and must be readable
255
256 @note: We currently do not validate anything having to do with remote peers,
257 since we don't have a straightforward way of doing it. It would require
258 adding an rsh command rather than just an rcp command to configuration, and
259 that just doesn't seem worth it right now.
260
261 @param config: Program configuration.
262 @param logfunc: Function to use for logging errors
263
264 @return: True if configuration is valid, False otherwise.
265 """
266 valid = True
267 if config.stage is not None:
268 valid &= _checkDir(config.stage.targetDir, True, logfunc, "Stage target dir ")
269 if config.stage.localPeers is not None:
270 for peer in config.stage.localPeers:
271 valid &= _checkDir(peer.collectDir, False, logfunc, "Local peer collect dir ")
272 return valid
273
274
275
276
277
278
280 """
281 Execute runtime validations on store configuration.
282
283 The following validations are enforced:
284
285 - The source directory must exist and must be readable
286 - The backup device (path and SCSI device) must be valid
287
288 @param config: Program configuration.
289 @param logfunc: Function to use for logging errors
290
291 @return: True if configuration is valid, False otherwise.
292 """
293 valid = True
294 if config.store is not None:
295 valid &= _checkDir(config.store.sourceDir, False, logfunc, "Store source directory")
296 try:
297 createWriter(config)
298 except ValueError:
299 logfunc("Backup device [%s] [%s] is not valid." % (config.store.devicePath, config.store.deviceScsiId))
300 valid = False
301 return valid
302
303
304
305
306
307
309 """
310 Execute runtime validations on purge configuration.
311
312 The following validations are enforced:
313
314 - Each purge directory must exist and must be writable
315
316 @param config: Program configuration.
317 @param logfunc: Function to use for logging errors
318
319 @return: True if configuration is valid, False otherwise.
320 """
321 valid = True
322 if config.purge is not None:
323 if config.purge.purgeDirs is not None:
324 for purgeDir in config.purge.purgeDirs:
325 valid &= _checkDir(purgeDir.absolutePath, True, logfunc, "Purge directory")
326 return valid
327
328
329
330
331
332
359