Merge lp:~nuclearbob/utah/iso-static-validation-updates into lp:utah
- iso-static-validation-updates
- Merge into dev
Status: | Merged |
---|---|
Merged at revision: | 743 |
Proposed branch: | lp:~nuclearbob/utah/iso-static-validation-updates |
Merge into: | lp:utah |
Diff against target: |
400 lines (+117/-140) 3 files modified
debian/utah.install (+1/-0) utah/iso.py (+76/-105) utah/isotest/iso_static_validation.py (+40/-35) |
To merge this branch: | bzr merge lp:~nuclearbob/utah/iso-static-validation-updates |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Joe Talbott (community) | Approve | ||
Review via email: mp+134201@code.launchpad.net |
Commit message
Description of the change
This branch makes several updates to the ISO static validation code. It updated it to use the new ISO class. It allows it to run from an arbitrary directory. It allows it to run on ISOs not named series-
- 739. By Max Brustkern
-
Updated config handling: directories now supported, as well as most
command line options
- 740. By Max Brustkern
-
Added config import to example scripts sop serieschoices can be pulled in. The failure to generate options was breaking the build, so I'm comitting this directly.
- 741. By Max Brustkern
-
Added support for automatic ISO downloading and made CustomVM the
default provisioning method - 742. By Max Brustkern
-
Added support for desktop image kernel detection from bootloader
configuration files - 743. By Max Brustkern
-
Updated ISO static validation to use new features of ISO class and
work independent of script directory and image directory and image
name
Preview Diff
1 | === modified file 'debian/utah.install' |
2 | --- debian/utah.install 2012-10-05 14:09:09 +0000 |
3 | +++ debian/utah.install 2012-11-14 16:06:21 +0000 |
4 | @@ -1,5 +1,6 @@ |
5 | conf/config var/lib/utah/.ssh |
6 | conf/utah etc |
7 | examples usr/share/utah |
8 | +utah/isotest usr/share/utah |
9 | utah-client_*_all.deb usr/share/utah |
10 | python-jsonschema_*_all.deb usr/share/utah |
11 | |
12 | === modified file 'utah/iso.py' |
13 | --- utah/iso.py 2012-08-30 08:45:59 +0000 |
14 | +++ utah/iso.py 2012-11-14 16:06:21 +0000 |
15 | @@ -1,9 +1,6 @@ |
16 | """ |
17 | All commands use bsdtar and accept a logmethod to use for logging. |
18 | """ |
19 | -#TODO: Make an iso class that can return things like arch, series, type, etc. |
20 | -#TODO: Add the existing functions to the iso class. |
21 | -#TODO: Convert the code to use the class instead of the existing functions. |
22 | import logging |
23 | import logging.handlers |
24 | import os |
25 | @@ -15,102 +12,6 @@ |
26 | from utah.exceptions import UTAHException |
27 | |
28 | |
29 | -def listfiles(image, logmethod=None, returnlist=False): |
30 | - """ |
31 | - Return either a subprocess instance listing the contents of an iso, or a |
32 | - list of files in the iso if returnlist is True. |
33 | - """ |
34 | - cmd = ['bsdtar', '-t', '-f', image] |
35 | - if logmethod is not None: |
36 | - logmethod('bsdtar list command: ' + ' '.join(cmd)) |
37 | - if returnlist: |
38 | - return subprocess.check_output(cmd).strip().split('\n') |
39 | - else: |
40 | - return subprocess.Popen(cmd, stdout=subprocess.PIPE, |
41 | - stderr=subprocess.PIPE).communicate() |
42 | - |
43 | - |
44 | -def getrealfile(image, filename, outdir=None, logmethod=None): |
45 | - """ |
46 | - Return a command to safely extract a file from an iso. |
47 | - Based on unbsdtar-safelink from ubuntu iso testing. |
48 | - """ |
49 | - cmd = ['bsdtar', '-t', '-v', '-f', image, filename] |
50 | - if logmethod is not None: |
51 | - logmethod('bsdtar list command: ' + ' '.join(cmd)) |
52 | - output = (subprocess.Popen(cmd, stdout=subprocess.PIPE) |
53 | - .communicate()[0].split('\n')[0].split()) |
54 | - try: |
55 | - if output[0].startswith('l'): |
56 | - if outdir is None: |
57 | - cmd = ['ln', '-s', output[-1], output[-3]] |
58 | - else: |
59 | - cmd = ['ln', '-s', output[-1], |
60 | - os.path.join(outdir, output[-3])] |
61 | - else: |
62 | - realfile = output[-1] |
63 | - if outdir is None: |
64 | - cmd = ['bsdtar', '-x', '-f', image, '-O', realfile] |
65 | - else: |
66 | - cmd = ['bsdtar', '-x', '-f', image, '-C', outdir, |
67 | - '-O', realfile] |
68 | - except IndexError: |
69 | - raise UTAHException('Cannot unpack image: ' + image) |
70 | - if logmethod is not None: |
71 | - logmethod('bsdtar extract command: ' + ' '.join(cmd)) |
72 | - return cmd |
73 | - |
74 | - |
75 | -def extract(image, filename, outdir=None, outfile=None, logmethod=None, **kw): |
76 | - """ |
77 | - Return a subprocess to extract a file from an iso, passing any additional |
78 | - keyword arguments to the subprocess. |
79 | - If outfile is None, extract to standard out. |
80 | - If outdir is present and outfile is None, extract the file to outdir with |
81 | - the same name. |
82 | - If outdir and outfile are both present, extract to outfile in outdir. |
83 | - If the file is a hardlink, extract the actual file. |
84 | - If the file is a symlink, return a command to create the symlink. |
85 | - """ |
86 | - if outfile is None: |
87 | - if outdir is None: |
88 | - cmd = getrealfile(image, filename, logmethod=logmethod) |
89 | - # The original function was designed to send the file over stdout, |
90 | - # this removes that |
91 | - # I think the updated function takes care of this already |
92 | - # if '-C' in cmd: |
93 | - # cmd.remove('-C') |
94 | - if cmd[-1] != filename: |
95 | - if logmethod is not None: |
96 | - logmethod(filename + ' appears to be a link to ' + cmd[-1]) |
97 | - dirname = os.path.dirname(filename) |
98 | - if not os.path.isdir(dirname): |
99 | - os.makedirs(dirname) |
100 | - os.chmod(dirname, 0775) |
101 | - if os.path.isfile(filename): |
102 | - os.chmod(filename, 0775) |
103 | - return subprocess.call(cmd, stdout=open(filename, 'w'), **kw) |
104 | - else: |
105 | - cmd = getrealfile(image, filename, |
106 | - outdir=outdir, logmethod=logmethod) |
107 | - if '-O' in cmd: |
108 | - cmd.remove('-O') |
109 | - return subprocess.Popen(cmd, stdout=subprocess.PIPE, |
110 | - stderr=subprocess.PIPE, **kw).communicate() |
111 | - else: |
112 | - cmd = getrealfile(image, filename, logmethod=logmethod) |
113 | - return subprocess.call(cmd, stdout=open(outfile, 'w'), **kw) |
114 | - |
115 | - |
116 | -def dump(image, filename, logmethod=None, **kw): |
117 | - """ |
118 | - Return a subprocess dumping a file in an iso to standard out, passing any |
119 | - additional keyword arguments to the subprocess. |
120 | - """ |
121 | - cmd = getrealfile(image, filename, logmethod=logmethod) |
122 | - return subprocess.Popen(cmd, stdout=subprocess.PIPE, **kw) |
123 | - |
124 | - |
125 | class ISO(object): |
126 | """ |
127 | Provide a simplified method of interfacing with images. |
128 | @@ -226,18 +127,88 @@ |
129 | self.logger.debug("%s read, %s%% of %s total" % (read, percent, total)) |
130 | |
131 | def listfiles(self, returnlist=False): |
132 | - return listfiles(self.image, self.logger.debug, returnlist=returnlist) |
133 | + """ |
134 | + Return either a subprocess instance listing the contents of an iso, or |
135 | + a list of files in the iso if returnlist is True. |
136 | + """ |
137 | + cmd = ['bsdtar', '-t', '-f', self.image] |
138 | + self.logger.debug('bsdtar list command: ' + ' '.join(cmd)) |
139 | + if returnlist: |
140 | + return subprocess.check_output(cmd).strip().split('\n') |
141 | + else: |
142 | + return subprocess.Popen(cmd, stdout=subprocess.PIPE, |
143 | + stderr=subprocess.PIPE).communicate() |
144 | |
145 | def getrealfile(self, filename, outdir=None): |
146 | - return getrealfile(self.image, filename, outdir=outdir, |
147 | - logmethod=self.logger.debug) |
148 | + """ |
149 | + Return a command to safely extract a file from an iso. |
150 | + Based on unbsdtar-safelink from ubuntu iso testing. |
151 | + """ |
152 | + cmd = ['bsdtar', '-t', '-v', '-f', self.image, filename] |
153 | + self.logger.debug('bsdtar list command: ' + ' '.join(cmd)) |
154 | + output = (subprocess.Popen(cmd, stdout=subprocess.PIPE) |
155 | + .communicate()[0].split('\n')[0].split()) |
156 | + try: |
157 | + if output[0].startswith('l'): |
158 | + if outdir is None: |
159 | + cmd = ['ln', '-s', output[-1], output[-3]] |
160 | + else: |
161 | + cmd = ['ln', '-s', output[-1], |
162 | + os.path.join(outdir, output[-3])] |
163 | + else: |
164 | + realfile = output[-1] |
165 | + if outdir is None: |
166 | + cmd = ['bsdtar', '-x', '-f', self.image, '-O', realfile] |
167 | + else: |
168 | + cmd = ['bsdtar', '-x', '-f', self.image, '-C', outdir, |
169 | + '-O', realfile] |
170 | + except IndexError: |
171 | + raise UTAHException('Cannot unpack image: ' + self.image) |
172 | + self.logger.debug('bsdtar extract command: ' + ' '.join(cmd)) |
173 | + return cmd |
174 | |
175 | def extract(self, filename, outdir=None, outfile=None, **kw): |
176 | - return extract(self.image, filename, outdir, outfile, |
177 | - logmethod=self.logger.debug, **kw) |
178 | + """ |
179 | + Return a subprocess to extract a file from an iso, passing any |
180 | + additional keyword arguments to the subprocess. |
181 | + If outfile is None, extract to standard out. |
182 | + If outdir is present and outfile is None, extract the file to outdir |
183 | + with the same name. |
184 | + If outdir and outfile are both present, extract to outfile in outdir. |
185 | + If the file is a hardlink, extract the actual file. |
186 | + If the file is a symlink, return a command to create the symlink. |
187 | + """ |
188 | + if outfile is None: |
189 | + if outdir is None: |
190 | + cmd = self.getrealfile(filename) |
191 | + if cmd[-1] != filename: |
192 | + self.logger.debug(filename + ' appears to be a link to ' |
193 | + + cmd[-1]) |
194 | + dirname = os.path.dirname(filename) |
195 | + if not os.path.isdir(dirname): |
196 | + os.makedirs(dirname) |
197 | + os.chmod(dirname, 0775) |
198 | + if os.path.isfile(filename): |
199 | + os.chmod(filename, 0775) |
200 | + return subprocess.call(cmd, stdout=open(filename, 'w'), |
201 | + **kw) |
202 | + else: |
203 | + cmd = self.getrealfile(filename, outdir=outdir) |
204 | + if '-O' in cmd: |
205 | + cmd.remove('-O') |
206 | + return subprocess.Popen(cmd, stdout=subprocess.PIPE, |
207 | + stderr=subprocess.PIPE, **kw).communicate() |
208 | + else: |
209 | + cmd = self.getrealfile(filename) |
210 | + return subprocess.call(cmd, stdout=open(outfile, 'w'), **kw) |
211 | |
212 | def dump(self, filename, **kw): |
213 | - return dump(self.image, filename, logmethod=self.logger.debug, **kw) |
214 | + """ |
215 | + Return a subprocess dumping a file in an iso to standard out, passing |
216 | + any additional keyword arguments to the subprocess. |
217 | + """ |
218 | + cmd = self.getrealfile(filename) |
219 | + return subprocess.Popen(cmd, stdout=subprocess.PIPE, **kw) |
220 | |
221 | def extractall(self): |
222 | for myfile in self.listfiles(returnlist=True): |
223 | |
224 | === modified file 'utah/isotest/iso_static_validation.py' |
225 | --- utah/isotest/iso_static_validation.py 2012-07-24 11:07:42 +0000 |
226 | +++ utah/isotest/iso_static_validation.py 2012-11-14 16:06:21 +0000 |
227 | @@ -34,7 +34,8 @@ |
228 | |
229 | lib_path = os.path.abspath('../') |
230 | sys.path.append(lib_path) |
231 | -import iso |
232 | +from utah.iso import ISO |
233 | +from utah import config |
234 | |
235 | |
236 | # Defaults |
237 | @@ -55,18 +56,26 @@ |
238 | print 'The usage:', sys.argv[0], '--name release-variant-arch.iso' |
239 | sys.exit(1) |
240 | else: |
241 | - st_name = args.name.rstrip('.iso') |
242 | - try: |
243 | - (st_release, st_variant, st_arch) = st_name.rsplit('-') |
244 | - except ValueError: |
245 | - sys.exit("Image name be in the form of release-variant-arch.iso") |
246 | - logging.debug("The file being tested is: '%s'", args.name) |
247 | + # Set default path |
248 | + iso_location = args.name |
249 | + # Iterate over possible paths, starting with old default behavior |
250 | + for path in (os.path.join(DEFAULT_ISOROOT, args.name), args.name): |
251 | + if os.path.isfile(path): |
252 | + iso_location = path |
253 | + break |
254 | + iso = ISO(iso_location) |
255 | + st_variant = iso.installtype |
256 | + st_arch = iso.arch |
257 | + |
258 | |
259 | #Set a flag for ubiquity based images |
260 | if st_variant == 'desktop' or st_variant == 'dvd': |
261 | ubiquity_image = True |
262 | else: |
263 | ubiquity_image = False |
264 | + |
265 | +#Setup the path for data files |
266 | +DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') |
267 | |
268 | |
269 | class TestValidateISO(unittest.TestCase): |
270 | @@ -79,12 +88,16 @@ |
271 | unittest.fail("Setup error") |
272 | |
273 | def setUp(self): |
274 | - self.iso_name = args.name |
275 | self.block_size = ONE_MB_BLOCK |
276 | - self.iso_location = os.path.join(DEFAULT_ISOROOT, args.name) |
277 | - self.st_release = st_release |
278 | - self.st_variant = st_variant |
279 | - self.st_arch = st_arch |
280 | + self.iso_location = iso_location |
281 | + logging.debug('Using iso at: ' + self.iso_location) |
282 | + self.iso = ISO(self.iso_location, logger=logging) |
283 | + self.st_release = self.iso.series |
284 | + self.st_variant = self.iso.installtype |
285 | + self.st_arch = self.iso.arch |
286 | + self.iso_name = '-'.join([self.st_release, self.st_variant, |
287 | + self.st_arch]) + '.iso' |
288 | + logging.debug('Standard name for this iso is: ' + self.iso_name) |
289 | |
290 | if self.st_release != 'precise': |
291 | self.url = DEFAULT_URL |
292 | @@ -164,7 +177,7 @@ |
293 | self.fail("Failed to fetch files list from the server") |
294 | |
295 | logging.debug('Extracting list file info from ISO') |
296 | - (stdout, stderr) = iso.listfiles(self.iso_location) |
297 | + (stdout, stderr) = self.iso.listfiles() |
298 | logging.debug('Checking for error in extracting the file list') |
299 | self.assertEqual(stderr, '') |
300 | |
301 | @@ -188,9 +201,8 @@ |
302 | self.fail("Failed to fetch manifest file from the server") |
303 | |
304 | logging.debug('Extracting manifest from the iso') |
305 | - (stdout, stderr) = iso.extract(self.iso_location, |
306 | - 'casper/filesystem.manifest', |
307 | - self.temp_dir) |
308 | + (stdout, stderr) = self.iso.extract('casper/filesystem.manifest', |
309 | + self.temp_dir) |
310 | logging.debug('Check for error in extracting manifest info from iso') |
311 | self.assertEqual(stderr, '') |
312 | |
313 | @@ -206,8 +218,7 @@ |
314 | # the same as that given in distro info |
315 | def test_build_id(self): |
316 | logging.debug('Extract distro information of the image from the iso') |
317 | - (stdout, stderr) = iso.extract(self.iso_location, "./.disk/info", |
318 | - self.temp_dir) |
319 | + (stdout, stderr) = self.iso.extract("./.disk/info", self.temp_dir) |
320 | logging.debug('Checking for error in extracting distro info from iso') |
321 | self.assertEqual(stderr, '') |
322 | |
323 | @@ -237,8 +248,7 @@ |
324 | st_arch != 'powerpc', "Skipping non ubiquity images") |
325 | def test_wubi(self): |
326 | logging.debug('Extracting wubi from the desktop images') |
327 | - (stdout, stderr) = iso.extract(self.iso_location, './wubi.exe', |
328 | - self.temp_dir) |
329 | + (stdout, stderr) = self.iso.extract('./wubi.exe', self.temp_dir) |
330 | logging.debug('Check for error in extracting wubi.exe from the iso') |
331 | self.assertEqual(stderr, '') |
332 | |
333 | @@ -256,11 +266,10 @@ |
334 | @unittest.skipUnless(st_variant == 'desktop' and |
335 | st_arch != 'powerpc', "Skipping for non desktop iso") |
336 | def test_files_ubiquity(self): |
337 | - (stdout, stderr) = iso.listfiles(self.iso_location, |
338 | - logmethod=logging.debug) |
339 | + (stdout, stderr) = self.iso.listfiles() |
340 | logging.debug('Check for error in extracting file list from the iso') |
341 | self.assertEqual(stderr, '') |
342 | - files_list = open("data/file_list_ubiquity") |
343 | + files_list = open(os.path.join(DATA_PATH, 'file_list_ubiquity')) |
344 | for list_server in files_list: |
345 | logging.debug('Check if relevant files are present in the iso') |
346 | self.assertIn(list_server.rstrip(), stdout) |
347 | @@ -269,11 +278,10 @@ |
348 | @unittest.skipUnless(st_variant == 'dvd', |
349 | "This file list test is only specific for dvd") |
350 | def test_files_ubiquity_dvd(self): |
351 | - (stdout, stderr) = iso.listfiles(self.iso_location, |
352 | - logmethod=logging.debug) |
353 | + (stdout, stderr) = self.iso.listfiles() |
354 | logging.debug('Check for error in extracting file list from the iso') |
355 | self.assertEqual(stderr, '') |
356 | - files_list = open("data/file_list_ubiquity_dvd") |
357 | + files_list = open(os.path.join(DATA_PATH, 'file_list_ubiquity_dvd')) |
358 | for list_entry in files_list: |
359 | logging.debug('Check if relevant files are present in the iso') |
360 | self.assertIn(list_entry.rstrip(), stdout) |
361 | @@ -285,15 +293,14 @@ |
362 | # Test is skipped for ubiquity based images |
363 | @unittest.skipIf(ubiquity_image, "Skipping for ubiquity images") |
364 | def test_files_di(self): |
365 | - (stdout, stderr) = iso.listfiles(self.iso_location, |
366 | - logmethod=logging.debug) |
367 | + (stdout, stderr) = self.iso.listfiles() |
368 | logging.debug('Check for error in extracting file list from the iso') |
369 | self.assertEqual(stderr, '') |
370 | |
371 | if self.st_arch == 'powerpc' or self.st_arch == 'amd64+mac': |
372 | - files_list = open("data/file_list_di_powerpc") |
373 | + files_list = open(os.path.join(DATA_PATH, 'file_list_di_powerpc')) |
374 | else: # i386 or amd64 |
375 | - files_list = open("data/file_list_di") |
376 | + files_list = open(os.path.join(DATA_PATH, 'file_list_di')) |
377 | |
378 | for list_server in files_list: |
379 | logging.debug('check if important d-i files are present in iso') |
380 | @@ -303,8 +310,7 @@ |
381 | @unittest.skipUnless(ubiquity_image and st_arch != 'powerpc', |
382 | "vmlinuz is present only for ubiquity based images") |
383 | def test_vmlinuz(self): |
384 | - (stdout, stderr) = iso.extract(self.iso_location, 'casper/vmlinuz', |
385 | - self.temp_dir) |
386 | + (stdout, stderr) = self.iso.extract('casper/vmlinuz', self.temp_dir) |
387 | logging.debug('Asserting that vmlinuz is present in the iso') |
388 | self.assertEqual(stderr, '') |
389 | |
390 | @@ -323,9 +329,8 @@ |
391 | @unittest.skipUnless(ubiquity_image, "Skipping for non ubiquity images") |
392 | def test_filesystem_squashfs(self): |
393 | logging.debug('Extracting the filesystem.squashfs') |
394 | - (stdout, stderr) = iso.extract(self.iso_location, |
395 | - 'casper/filesystem.squashfs', |
396 | - self.temp_dir) |
397 | + (stdout, stderr) = self.iso.extract('casper/filesystem.squashfs', |
398 | + self.temp_dir) |
399 | logging.debug('Check for error in extracting filesystem.squashfs') |
400 | self.assertEqual(stderr, '') |
401 |
Looks good to me.