Merge lp:~nuclearbob/utah/iso-static-validation-updates into lp:utah

Proposed by Max Brustkern
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
Reviewer Review Type Date Requested Status
Joe Talbott (community) Approve
Review via email: mp+134201@code.launchpad.net

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-type-arch.iso. It also updated iso.py to move all the functions into the ISO class since they are now not used externally by anything.

To post a comment you must log in.
739. By Max Brustkern

Updated config handling: directories now supported, as well as most
command line options

Revision history for this message
Joe Talbott (joetalbott) wrote :

Looks good to me.

review: Approve
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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

Subscribers

People subscribed via source and target branches