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
=== modified file 'debian/utah.install'
--- debian/utah.install 2012-10-05 14:09:09 +0000
+++ debian/utah.install 2012-11-14 16:06:21 +0000
@@ -1,5 +1,6 @@
1conf/config var/lib/utah/.ssh1conf/config var/lib/utah/.ssh
2conf/utah etc2conf/utah etc
3examples usr/share/utah3examples usr/share/utah
4utah/isotest usr/share/utah
4utah-client_*_all.deb usr/share/utah5utah-client_*_all.deb usr/share/utah
5python-jsonschema_*_all.deb usr/share/utah6python-jsonschema_*_all.deb usr/share/utah
67
=== modified file 'utah/iso.py'
--- utah/iso.py 2012-08-30 08:45:59 +0000
+++ utah/iso.py 2012-11-14 16:06:21 +0000
@@ -1,9 +1,6 @@
1"""1"""
2All commands use bsdtar and accept a logmethod to use for logging.2All commands use bsdtar and accept a logmethod to use for logging.
3"""3"""
4#TODO: Make an iso class that can return things like arch, series, type, etc.
5#TODO: Add the existing functions to the iso class.
6#TODO: Convert the code to use the class instead of the existing functions.
7import logging4import logging
8import logging.handlers5import logging.handlers
9import os6import os
@@ -15,102 +12,6 @@
15from utah.exceptions import UTAHException12from utah.exceptions import UTAHException
1613
1714
18def listfiles(image, logmethod=None, returnlist=False):
19 """
20 Return either a subprocess instance listing the contents of an iso, or a
21 list of files in the iso if returnlist is True.
22 """
23 cmd = ['bsdtar', '-t', '-f', image]
24 if logmethod is not None:
25 logmethod('bsdtar list command: ' + ' '.join(cmd))
26 if returnlist:
27 return subprocess.check_output(cmd).strip().split('\n')
28 else:
29 return subprocess.Popen(cmd, stdout=subprocess.PIPE,
30 stderr=subprocess.PIPE).communicate()
31
32
33def getrealfile(image, filename, outdir=None, logmethod=None):
34 """
35 Return a command to safely extract a file from an iso.
36 Based on unbsdtar-safelink from ubuntu iso testing.
37 """
38 cmd = ['bsdtar', '-t', '-v', '-f', image, filename]
39 if logmethod is not None:
40 logmethod('bsdtar list command: ' + ' '.join(cmd))
41 output = (subprocess.Popen(cmd, stdout=subprocess.PIPE)
42 .communicate()[0].split('\n')[0].split())
43 try:
44 if output[0].startswith('l'):
45 if outdir is None:
46 cmd = ['ln', '-s', output[-1], output[-3]]
47 else:
48 cmd = ['ln', '-s', output[-1],
49 os.path.join(outdir, output[-3])]
50 else:
51 realfile = output[-1]
52 if outdir is None:
53 cmd = ['bsdtar', '-x', '-f', image, '-O', realfile]
54 else:
55 cmd = ['bsdtar', '-x', '-f', image, '-C', outdir,
56 '-O', realfile]
57 except IndexError:
58 raise UTAHException('Cannot unpack image: ' + image)
59 if logmethod is not None:
60 logmethod('bsdtar extract command: ' + ' '.join(cmd))
61 return cmd
62
63
64def extract(image, filename, outdir=None, outfile=None, logmethod=None, **kw):
65 """
66 Return a subprocess to extract a file from an iso, passing any additional
67 keyword arguments to the subprocess.
68 If outfile is None, extract to standard out.
69 If outdir is present and outfile is None, extract the file to outdir with
70 the same name.
71 If outdir and outfile are both present, extract to outfile in outdir.
72 If the file is a hardlink, extract the actual file.
73 If the file is a symlink, return a command to create the symlink.
74 """
75 if outfile is None:
76 if outdir is None:
77 cmd = getrealfile(image, filename, logmethod=logmethod)
78 # The original function was designed to send the file over stdout,
79 # this removes that
80 # I think the updated function takes care of this already
81 # if '-C' in cmd:
82 # cmd.remove('-C')
83 if cmd[-1] != filename:
84 if logmethod is not None:
85 logmethod(filename + ' appears to be a link to ' + cmd[-1])
86 dirname = os.path.dirname(filename)
87 if not os.path.isdir(dirname):
88 os.makedirs(dirname)
89 os.chmod(dirname, 0775)
90 if os.path.isfile(filename):
91 os.chmod(filename, 0775)
92 return subprocess.call(cmd, stdout=open(filename, 'w'), **kw)
93 else:
94 cmd = getrealfile(image, filename,
95 outdir=outdir, logmethod=logmethod)
96 if '-O' in cmd:
97 cmd.remove('-O')
98 return subprocess.Popen(cmd, stdout=subprocess.PIPE,
99 stderr=subprocess.PIPE, **kw).communicate()
100 else:
101 cmd = getrealfile(image, filename, logmethod=logmethod)
102 return subprocess.call(cmd, stdout=open(outfile, 'w'), **kw)
103
104
105def dump(image, filename, logmethod=None, **kw):
106 """
107 Return a subprocess dumping a file in an iso to standard out, passing any
108 additional keyword arguments to the subprocess.
109 """
110 cmd = getrealfile(image, filename, logmethod=logmethod)
111 return subprocess.Popen(cmd, stdout=subprocess.PIPE, **kw)
112
113
114class ISO(object):15class ISO(object):
115 """16 """
116 Provide a simplified method of interfacing with images.17 Provide a simplified method of interfacing with images.
@@ -226,18 +127,88 @@
226 self.logger.debug("%s read, %s%% of %s total" % (read, percent, total))127 self.logger.debug("%s read, %s%% of %s total" % (read, percent, total))
227128
228 def listfiles(self, returnlist=False):129 def listfiles(self, returnlist=False):
229 return listfiles(self.image, self.logger.debug, returnlist=returnlist)130 """
131 Return either a subprocess instance listing the contents of an iso, or
132 a list of files in the iso if returnlist is True.
133 """
134 cmd = ['bsdtar', '-t', '-f', self.image]
135 self.logger.debug('bsdtar list command: ' + ' '.join(cmd))
136 if returnlist:
137 return subprocess.check_output(cmd).strip().split('\n')
138 else:
139 return subprocess.Popen(cmd, stdout=subprocess.PIPE,
140 stderr=subprocess.PIPE).communicate()
230141
231 def getrealfile(self, filename, outdir=None):142 def getrealfile(self, filename, outdir=None):
232 return getrealfile(self.image, filename, outdir=outdir,143 """
233 logmethod=self.logger.debug)144 Return a command to safely extract a file from an iso.
145 Based on unbsdtar-safelink from ubuntu iso testing.
146 """
147 cmd = ['bsdtar', '-t', '-v', '-f', self.image, filename]
148 self.logger.debug('bsdtar list command: ' + ' '.join(cmd))
149 output = (subprocess.Popen(cmd, stdout=subprocess.PIPE)
150 .communicate()[0].split('\n')[0].split())
151 try:
152 if output[0].startswith('l'):
153 if outdir is None:
154 cmd = ['ln', '-s', output[-1], output[-3]]
155 else:
156 cmd = ['ln', '-s', output[-1],
157 os.path.join(outdir, output[-3])]
158 else:
159 realfile = output[-1]
160 if outdir is None:
161 cmd = ['bsdtar', '-x', '-f', self.image, '-O', realfile]
162 else:
163 cmd = ['bsdtar', '-x', '-f', self.image, '-C', outdir,
164 '-O', realfile]
165 except IndexError:
166 raise UTAHException('Cannot unpack image: ' + self.image)
167 self.logger.debug('bsdtar extract command: ' + ' '.join(cmd))
168 return cmd
234169
235 def extract(self, filename, outdir=None, outfile=None, **kw):170 def extract(self, filename, outdir=None, outfile=None, **kw):
236 return extract(self.image, filename, outdir, outfile,171 """
237 logmethod=self.logger.debug, **kw)172 Return a subprocess to extract a file from an iso, passing any
173 additional keyword arguments to the subprocess.
174 If outfile is None, extract to standard out.
175 If outdir is present and outfile is None, extract the file to outdir
176 with the same name.
177 If outdir and outfile are both present, extract to outfile in outdir.
178 If the file is a hardlink, extract the actual file.
179 If the file is a symlink, return a command to create the symlink.
180 """
181 if outfile is None:
182 if outdir is None:
183 cmd = self.getrealfile(filename)
184 if cmd[-1] != filename:
185 self.logger.debug(filename + ' appears to be a link to '
186 + cmd[-1])
187 dirname = os.path.dirname(filename)
188 if not os.path.isdir(dirname):
189 os.makedirs(dirname)
190 os.chmod(dirname, 0775)
191 if os.path.isfile(filename):
192 os.chmod(filename, 0775)
193 return subprocess.call(cmd, stdout=open(filename, 'w'),
194 **kw)
195 else:
196 cmd = self.getrealfile(filename, outdir=outdir)
197 if '-O' in cmd:
198 cmd.remove('-O')
199 return subprocess.Popen(cmd, stdout=subprocess.PIPE,
200 stderr=subprocess.PIPE, **kw).communicate()
201 else:
202 cmd = self.getrealfile(filename)
203 return subprocess.call(cmd, stdout=open(outfile, 'w'), **kw)
238204
239 def dump(self, filename, **kw):205 def dump(self, filename, **kw):
240 return dump(self.image, filename, logmethod=self.logger.debug, **kw)206 """
207 Return a subprocess dumping a file in an iso to standard out, passing
208 any additional keyword arguments to the subprocess.
209 """
210 cmd = self.getrealfile(filename)
211 return subprocess.Popen(cmd, stdout=subprocess.PIPE, **kw)
241212
242 def extractall(self):213 def extractall(self):
243 for myfile in self.listfiles(returnlist=True):214 for myfile in self.listfiles(returnlist=True):
244215
=== modified file 'utah/isotest/iso_static_validation.py'
--- utah/isotest/iso_static_validation.py 2012-07-24 11:07:42 +0000
+++ utah/isotest/iso_static_validation.py 2012-11-14 16:06:21 +0000
@@ -34,7 +34,8 @@
3434
35lib_path = os.path.abspath('../')35lib_path = os.path.abspath('../')
36sys.path.append(lib_path)36sys.path.append(lib_path)
37import iso37from utah.iso import ISO
38from utah import config
3839
3940
40# Defaults41# Defaults
@@ -55,18 +56,26 @@
55 print 'The usage:', sys.argv[0], '--name release-variant-arch.iso'56 print 'The usage:', sys.argv[0], '--name release-variant-arch.iso'
56 sys.exit(1)57 sys.exit(1)
57else:58else:
58 st_name = args.name.rstrip('.iso')59 # Set default path
59 try:60 iso_location = args.name
60 (st_release, st_variant, st_arch) = st_name.rsplit('-')61 # Iterate over possible paths, starting with old default behavior
61 except ValueError:62 for path in (os.path.join(DEFAULT_ISOROOT, args.name), args.name):
62 sys.exit("Image name be in the form of release-variant-arch.iso")63 if os.path.isfile(path):
63 logging.debug("The file being tested is: '%s'", args.name)64 iso_location = path
65 break
66 iso = ISO(iso_location)
67 st_variant = iso.installtype
68 st_arch = iso.arch
69
6470
65#Set a flag for ubiquity based images71#Set a flag for ubiquity based images
66if st_variant == 'desktop' or st_variant == 'dvd':72if st_variant == 'desktop' or st_variant == 'dvd':
67 ubiquity_image = True73 ubiquity_image = True
68else:74else:
69 ubiquity_image = False75 ubiquity_image = False
76
77#Setup the path for data files
78DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data')
7079
7180
72class TestValidateISO(unittest.TestCase):81class TestValidateISO(unittest.TestCase):
@@ -79,12 +88,16 @@
79 unittest.fail("Setup error")88 unittest.fail("Setup error")
8089
81 def setUp(self):90 def setUp(self):
82 self.iso_name = args.name
83 self.block_size = ONE_MB_BLOCK91 self.block_size = ONE_MB_BLOCK
84 self.iso_location = os.path.join(DEFAULT_ISOROOT, args.name)92 self.iso_location = iso_location
85 self.st_release = st_release93 logging.debug('Using iso at: ' + self.iso_location)
86 self.st_variant = st_variant94 self.iso = ISO(self.iso_location, logger=logging)
87 self.st_arch = st_arch95 self.st_release = self.iso.series
96 self.st_variant = self.iso.installtype
97 self.st_arch = self.iso.arch
98 self.iso_name = '-'.join([self.st_release, self.st_variant,
99 self.st_arch]) + '.iso'
100 logging.debug('Standard name for this iso is: ' + self.iso_name)
88101
89 if self.st_release != 'precise':102 if self.st_release != 'precise':
90 self.url = DEFAULT_URL103 self.url = DEFAULT_URL
@@ -164,7 +177,7 @@
164 self.fail("Failed to fetch files list from the server")177 self.fail("Failed to fetch files list from the server")
165178
166 logging.debug('Extracting list file info from ISO')179 logging.debug('Extracting list file info from ISO')
167 (stdout, stderr) = iso.listfiles(self.iso_location)180 (stdout, stderr) = self.iso.listfiles()
168 logging.debug('Checking for error in extracting the file list')181 logging.debug('Checking for error in extracting the file list')
169 self.assertEqual(stderr, '')182 self.assertEqual(stderr, '')
170183
@@ -188,9 +201,8 @@
188 self.fail("Failed to fetch manifest file from the server")201 self.fail("Failed to fetch manifest file from the server")
189202
190 logging.debug('Extracting manifest from the iso')203 logging.debug('Extracting manifest from the iso')
191 (stdout, stderr) = iso.extract(self.iso_location,204 (stdout, stderr) = self.iso.extract('casper/filesystem.manifest',
192 'casper/filesystem.manifest',205 self.temp_dir)
193 self.temp_dir)
194 logging.debug('Check for error in extracting manifest info from iso')206 logging.debug('Check for error in extracting manifest info from iso')
195 self.assertEqual(stderr, '')207 self.assertEqual(stderr, '')
196208
@@ -206,8 +218,7 @@
206 # the same as that given in distro info218 # the same as that given in distro info
207 def test_build_id(self):219 def test_build_id(self):
208 logging.debug('Extract distro information of the image from the iso')220 logging.debug('Extract distro information of the image from the iso')
209 (stdout, stderr) = iso.extract(self.iso_location, "./.disk/info",221 (stdout, stderr) = self.iso.extract("./.disk/info", self.temp_dir)
210 self.temp_dir)
211 logging.debug('Checking for error in extracting distro info from iso')222 logging.debug('Checking for error in extracting distro info from iso')
212 self.assertEqual(stderr, '')223 self.assertEqual(stderr, '')
213224
@@ -237,8 +248,7 @@
237 st_arch != 'powerpc', "Skipping non ubiquity images")248 st_arch != 'powerpc', "Skipping non ubiquity images")
238 def test_wubi(self):249 def test_wubi(self):
239 logging.debug('Extracting wubi from the desktop images')250 logging.debug('Extracting wubi from the desktop images')
240 (stdout, stderr) = iso.extract(self.iso_location, './wubi.exe',251 (stdout, stderr) = self.iso.extract('./wubi.exe', self.temp_dir)
241 self.temp_dir)
242 logging.debug('Check for error in extracting wubi.exe from the iso')252 logging.debug('Check for error in extracting wubi.exe from the iso')
243 self.assertEqual(stderr, '')253 self.assertEqual(stderr, '')
244254
@@ -256,11 +266,10 @@
256 @unittest.skipUnless(st_variant == 'desktop' and266 @unittest.skipUnless(st_variant == 'desktop' and
257 st_arch != 'powerpc', "Skipping for non desktop iso")267 st_arch != 'powerpc', "Skipping for non desktop iso")
258 def test_files_ubiquity(self):268 def test_files_ubiquity(self):
259 (stdout, stderr) = iso.listfiles(self.iso_location,269 (stdout, stderr) = self.iso.listfiles()
260 logmethod=logging.debug)
261 logging.debug('Check for error in extracting file list from the iso')270 logging.debug('Check for error in extracting file list from the iso')
262 self.assertEqual(stderr, '')271 self.assertEqual(stderr, '')
263 files_list = open("data/file_list_ubiquity")272 files_list = open(os.path.join(DATA_PATH, 'file_list_ubiquity'))
264 for list_server in files_list:273 for list_server in files_list:
265 logging.debug('Check if relevant files are present in the iso')274 logging.debug('Check if relevant files are present in the iso')
266 self.assertIn(list_server.rstrip(), stdout)275 self.assertIn(list_server.rstrip(), stdout)
@@ -269,11 +278,10 @@
269 @unittest.skipUnless(st_variant == 'dvd',278 @unittest.skipUnless(st_variant == 'dvd',
270 "This file list test is only specific for dvd")279 "This file list test is only specific for dvd")
271 def test_files_ubiquity_dvd(self):280 def test_files_ubiquity_dvd(self):
272 (stdout, stderr) = iso.listfiles(self.iso_location,281 (stdout, stderr) = self.iso.listfiles()
273 logmethod=logging.debug)
274 logging.debug('Check for error in extracting file list from the iso')282 logging.debug('Check for error in extracting file list from the iso')
275 self.assertEqual(stderr, '')283 self.assertEqual(stderr, '')
276 files_list = open("data/file_list_ubiquity_dvd")284 files_list = open(os.path.join(DATA_PATH, 'file_list_ubiquity_dvd'))
277 for list_entry in files_list:285 for list_entry in files_list:
278 logging.debug('Check if relevant files are present in the iso')286 logging.debug('Check if relevant files are present in the iso')
279 self.assertIn(list_entry.rstrip(), stdout)287 self.assertIn(list_entry.rstrip(), stdout)
@@ -285,15 +293,14 @@
285 # Test is skipped for ubiquity based images293 # Test is skipped for ubiquity based images
286 @unittest.skipIf(ubiquity_image, "Skipping for ubiquity images")294 @unittest.skipIf(ubiquity_image, "Skipping for ubiquity images")
287 def test_files_di(self):295 def test_files_di(self):
288 (stdout, stderr) = iso.listfiles(self.iso_location,296 (stdout, stderr) = self.iso.listfiles()
289 logmethod=logging.debug)
290 logging.debug('Check for error in extracting file list from the iso')297 logging.debug('Check for error in extracting file list from the iso')
291 self.assertEqual(stderr, '')298 self.assertEqual(stderr, '')
292299
293 if self.st_arch == 'powerpc' or self.st_arch == 'amd64+mac':300 if self.st_arch == 'powerpc' or self.st_arch == 'amd64+mac':
294 files_list = open("data/file_list_di_powerpc")301 files_list = open(os.path.join(DATA_PATH, 'file_list_di_powerpc'))
295 else: # i386 or amd64302 else: # i386 or amd64
296 files_list = open("data/file_list_di")303 files_list = open(os.path.join(DATA_PATH, 'file_list_di'))
297304
298 for list_server in files_list:305 for list_server in files_list:
299 logging.debug('check if important d-i files are present in iso')306 logging.debug('check if important d-i files are present in iso')
@@ -303,8 +310,7 @@
303 @unittest.skipUnless(ubiquity_image and st_arch != 'powerpc',310 @unittest.skipUnless(ubiquity_image and st_arch != 'powerpc',
304 "vmlinuz is present only for ubiquity based images")311 "vmlinuz is present only for ubiquity based images")
305 def test_vmlinuz(self):312 def test_vmlinuz(self):
306 (stdout, stderr) = iso.extract(self.iso_location, 'casper/vmlinuz',313 (stdout, stderr) = self.iso.extract('casper/vmlinuz', self.temp_dir)
307 self.temp_dir)
308 logging.debug('Asserting that vmlinuz is present in the iso')314 logging.debug('Asserting that vmlinuz is present in the iso')
309 self.assertEqual(stderr, '')315 self.assertEqual(stderr, '')
310316
@@ -323,9 +329,8 @@
323 @unittest.skipUnless(ubiquity_image, "Skipping for non ubiquity images")329 @unittest.skipUnless(ubiquity_image, "Skipping for non ubiquity images")
324 def test_filesystem_squashfs(self):330 def test_filesystem_squashfs(self):
325 logging.debug('Extracting the filesystem.squashfs')331 logging.debug('Extracting the filesystem.squashfs')
326 (stdout, stderr) = iso.extract(self.iso_location,332 (stdout, stderr) = self.iso.extract('casper/filesystem.squashfs',
327 'casper/filesystem.squashfs',333 self.temp_dir)
328 self.temp_dir)
329 logging.debug('Check for error in extracting filesystem.squashfs')334 logging.debug('Check for error in extracting filesystem.squashfs')
330 self.assertEqual(stderr, '')335 self.assertEqual(stderr, '')
331336

Subscribers

People subscribed via source and target branches