Merge lp:~heber013/utah/fix-provisioning-function into lp:utah
- fix-provisioning-function
- Merge into dev
Status: | Merged |
---|---|
Merged at revision: | 1130 |
Proposed branch: | lp:~heber013/utah/fix-provisioning-function |
Merge into: | lp:utah |
Diff against target: |
277 lines (+78/-41) 3 files modified
conf/utah/default-vm.xml (+5/-2) utah/provisioning/provisioning.py (+56/-37) utah/provisioning/vm.py (+17/-2) |
To merge this branch: | bzr merge lp:~heber013/utah/fix-provisioning-function |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jean-Baptiste Lallement | Approve | ||
Paul Larson | Pending | ||
Review via email: mp+352837@code.launchpad.net |
This proposal supersedes a proposal from 2018-07-10.
Commit message
Fixing broken provisioning function due to initrd file extension change
Description of the change
Fixing broken provisioning function due to initrd file extension change
Paul Larson (pwlars) wrote : Posted in a previous version of this proposal | # |
Jean-Baptiste Lallement (jibel) wrote : Posted in a previous version of this proposal | # |
I think the fix is incomplete. casper/initrd and the target directory initrd have the same name and utah fails with ENOTDIR
cat: write error: Broken pipe
Unhandled error in UTAH:
Traceback (most recent call last):
File "/usr/bin/
exitstatus = timeout(
File "/usr/lib/
return command(*args, **kw)
File "/usr/bin/
exitstatus, locallogs = run_tests(args, _get_machine(args))
File "/usr/lib/
exitstatus, remote_path = _run(machine, args.runlist, extraopts)
File "/usr/lib/
return _install_
File "/usr/lib/
machine.
File "/usr/lib/
self.
File "/usr/lib/
self.
File "/usr/lib/
self.
File "/usr/lib/
config.
File "/usr/lib/
retval = command(*args, **kw)
File "/usr/lib/
self.
File "/usr/lib/
self.
File "/usr/lib/
self.
File "/usr/lib/
shutil.
File "/usr/lib/
copyfile(src, dst)
File "/usr/lib/
with open(dst, 'wb') as fdst:
IOError: [Errno 20] Not a directory: '/var/lib/
Heber Parrucci (heber013) wrote : Posted in a previous version of this proposal | # |
I tried fixing _copy_qemu_scripts and some more errors. Now I am getting an error in the function _preseedcasper:
2018-08-06 17:17:13,086 root WARNING: Command (sed -i 1i/scripts/
- 1130. By Heber Parrucci
-
Fixing issue when repacking initrd
- 1131. By Heber Parrucci
-
Fixing utah tests:
* Adding more memory to created VMs
* Adding video type qxl
* Adding retries when starting the VM with vm.create() - 1132. By Heber Parrucci
-
Increasing wait period default value when starting the virtual machine
- 1133. By Heber Parrucci
-
Updating logic on first VM boot
Jean-Baptiste Lallement (jibel) wrote : | # |
Thanks for this patch.
It fixes the problem with desktop images but breaks server tests.
The error is:
INFO: logpath was already set by /etc/utah/config
2018-09-10 03:00:05,890 cleanup WARNING: OSError when changing directory permissions: [Errno 1] Operation not permitted: '/var/lib/
2018-09-10 03:00:05,890 cleanup WARNING: OSError when changing directory permissions: [Errno 1] Operation not permitted: '/var/lib/
2018-09-10 03:00:05,891 cleanup WARNING: OSError when changing directory permissions: [Errno 1] Operation not permitted: '/var/lib/
2018-09-10 03:00:05,891 cleanup WARNING: OSError when changing directory permissions: [Errno 1] Operation not permitted: '/var/lib/
Unhandled error in UTAH:
Traceback (most recent call last):
File "/usr/bin/
exitstatus = timeout(
File "/usr/lib/
return command(*args, **kw)
File "/usr/bin/
exitstatus, locallogs = run_tests(args, _get_machine(args))
File "/usr/lib/
exitstatus, remote_path = _run(machine, args.runlist, extraopts)
File "/usr/lib/
return _install_
File "/usr/lib/
machine.
File "/usr/lib/
self.
File "/usr/lib/
self.
File "/usr/lib/
self._start()
File "/usr/lib/
self.
File "/usr/lib/
if ret == -1: raise libvirtError ('virDomainCreate() failed', dom=self)
libvirtError: Requested operation is not valid: domain is already running
+ RETCODE=4
- 1134. By Heber Parrucci
-
Fixing start vm function
Heber Parrucci (heber013) wrote : | # |
> Thanks for this patch.
>
> It fixes the problem with desktop images but breaks server tests.
>
> The error is:
>
> INFO: logpath was already set by /etc/utah/config
> 2018-09-10 03:00:05,890 cleanup WARNING: OSError when changing directory
> permissions: [Errno 1] Operation not permitted: '/var/lib/
> -cosmic-
> 2018-09-10 03:00:05,890 cleanup WARNING: OSError when changing directory
> permissions: [Errno 1] Operation not permitted: '/var/lib/
> -cosmic-
> 2018-09-10 03:00:05,891 cleanup WARNING: OSError when changing directory
> permissions: [Errno 1] Operation not permitted: '/var/lib/
> -cosmic-
> 2018-09-10 03:00:05,891 cleanup WARNING: OSError when changing directory
> permissions: [Errno 1] Operation not permitted: '/var/lib/
> -cosmic-
> Unhandled error in UTAH:
> Traceback (most recent call last):
> File "/usr/bin/
> exitstatus = timeout(
> File "/usr/lib/
> return command(*args, **kw)
> File "/usr/bin/
> exitstatus, locallogs = run_tests(args, _get_machine(args))
> File "/usr/lib/
> exitstatus, remote_path = _run(machine, args.runlist, extraopts)
> File "/usr/lib/
> return _install_
> File "/usr/lib/
> _install_and_run
> machine.
> File "/usr/lib/
> line 316, in installclient
> self.uploadfile
> File "/usr/lib/
> in uploadfiles
> self.activecheck()
> File "/usr/lib/
> in activecheck
> self._start()
> File "/usr/lib/
> in _start
> self.vm.create()
> File "/usr/lib/
> if ret == -1: raise libvirtError ('virDomainCreate() failed', dom=self)
> libvirtError: Requested operation is not valid: domain is already running
>
> + RETCODE=4
It should be fixed now. Thanks!
Jean-Baptiste Lallement (jibel) wrote : | # |
Thanks. Tested on Xenial with cosmic and bionic images of Desktop and server.
Preview Diff
1 | === modified file 'conf/utah/default-vm.xml' |
2 | --- conf/utah/default-vm.xml 2016-02-04 16:28:14 +0000 |
3 | +++ conf/utah/default-vm.xml 2018-09-10 14:38:14 +0000 |
4 | @@ -20,8 +20,8 @@ |
5 | <domain type='qemu'> |
6 | <name>Utah Example</name> |
7 | <uuid>00000000-0000-0000-0000-000000000000</uuid> |
8 | - <memory>524288</memory> |
9 | - <currentMemory>524288</currentMemory> |
10 | + <memory>1048576</memory> |
11 | + <currentMemory>1048576</currentMemory> |
12 | <vcpu>1</vcpu> |
13 | <os> |
14 | <type arch='i686' machine='pc'>hvm</type> |
15 | @@ -49,6 +49,9 @@ |
16 | <model type='virtio'/> |
17 | </interface> |
18 | <graphics type='vnc' autoport='yes'/> |
19 | + <video> |
20 | + <model type='qxl' vram='16384' heads='1'/> |
21 | + </video> |
22 | </devices> |
23 | </domain> |
24 | |
25 | |
26 | === modified file 'utah/provisioning/provisioning.py' |
27 | --- utah/provisioning/provisioning.py 2018-07-07 16:12:04 +0000 |
28 | +++ utah/provisioning/provisioning.py 2018-09-10 14:38:14 +0000 |
29 | @@ -25,6 +25,7 @@ |
30 | import re |
31 | import shutil |
32 | import stat |
33 | +import subprocess |
34 | import sys |
35 | import urllib |
36 | import uuid |
37 | @@ -321,7 +322,7 @@ |
38 | 'File not found: {filename}; ' |
39 | 'UTAH was probably updated during the run. ' |
40 | 'Please try again.' |
41 | - .format(filename=deb), |
42 | + .format(filename=deb), |
43 | retry=True) |
44 | raise err |
45 | except AttributeError: |
46 | @@ -508,8 +509,8 @@ |
47 | raise UTAHProvisioningException( |
48 | '{cls} attempted to call the {method} method ' |
49 | 'of the base Machine class, which is not implemented' |
50 | - .format(cls=self.__class__.__name__, |
51 | - method=method)) |
52 | + .format(cls=self.__class__.__name__, |
53 | + method=method)) |
54 | |
55 | def cleanfile(self, path): |
56 | """Register a path to be cleaned later. |
57 | @@ -558,7 +559,6 @@ |
58 | |
59 | |
60 | class CustomInstallMixin(object): |
61 | - |
62 | """Provide routines for automating an install from an image.""" |
63 | |
64 | def _preparekernel(self, kernel=None, tmpdir=None): |
65 | @@ -661,15 +661,24 @@ |
66 | if os.path.splitext(initrd)[1] == '.gz': |
67 | self.logger.debug('Using gzip based on file extension') |
68 | pipe.prepend('zcat $IN', 'f-') |
69 | + pipe.append('cpio -ivd 2>/dev/null', '-.') |
70 | + exitstatus = pipe.copy(initrd, '/dev/null') |
71 | + self.initrd_uncompressed_path = os.path.join(tmpdir, 'initrd.d') |
72 | + self.initrd_no_extension = False |
73 | elif os.path.splitext(initrd)[1] == '.lz': |
74 | self.logger.debug('Using lzma based on file extension') |
75 | pipe.prepend('lzcat -S .lz $IN', 'f-') |
76 | + pipe.append('cpio -ivd 2>/dev/null', '-.') |
77 | + exitstatus = pipe.copy(initrd, '/dev/null') |
78 | + self.initrd_uncompressed_path = os.path.join(tmpdir, 'initrd.d') |
79 | + self.initrd_no_extension = False |
80 | + elif not os.path.splitext(initrd)[1]: |
81 | + exitstatus = subprocess.check_call(['unmkinitramfs', initrd, os.getcwd()]) |
82 | + self.initrd_uncompressed_path = os.path.join(tmpdir, 'initrd.d', 'main') |
83 | + self.initrd_no_extension = True |
84 | else: |
85 | raise UTAHProvisioningException( |
86 | - 'initrd file does have have gz or lz extension: {}' |
87 | - .format(initrd)) |
88 | - pipe.append('cpio -ivd 2>/dev/null', '-.') |
89 | - exitstatus = pipe.copy(initrd, '/dev/null') |
90 | + 'initrd file does have have gz or lz extension or no extension: {}'.format(initrd)) |
91 | if exitstatus != 0: |
92 | # Currently this comes up as 512 when things seem fine |
93 | # TODO: refactor this and check for codes at all stages |
94 | @@ -683,10 +692,10 @@ |
95 | if tmpdir is None: |
96 | tmpdir = self.tmpdir |
97 | shutil.copyfile(config.sshpublickey, |
98 | - os.path.join(tmpdir, 'initrd.d', 'utah-ssh-key')) |
99 | + os.path.join(self.initrd_uncompressed_path, 'utah-ssh-key')) |
100 | |
101 | self.logger.info('Creating latecommand scripts') |
102 | - filename = os.path.join(tmpdir, 'initrd.d', 'utah-latecommand') |
103 | + filename = os.path.join(self.initrd_uncompressed_path, 'utah-latecommand') |
104 | template.write('utah-latecommand.jinja2', |
105 | filename, |
106 | user=config.user, |
107 | @@ -696,19 +705,22 @@ |
108 | install_type=self.image.installtype, |
109 | md5=self.image.getmd5()) |
110 | |
111 | - filename = os.path.join(tmpdir, 'initrd.d', 'utah-setup') |
112 | + filename = os.path.join(self.initrd_uncompressed_path, 'utah-setup') |
113 | template.write('utah-setup.jinja2', |
114 | filename, |
115 | packages=config.installpackages, |
116 | log_file='/var/log/utah-install') |
117 | |
118 | - filename = os.path.join(tmpdir, 'initrd.d', 'utah-autorun.sh') |
119 | + filename = os.path.join(self.initrd_uncompressed_path, 'utah-autorun.sh') |
120 | template.write('utah-autorun.sh.jinja2', |
121 | filename, |
122 | log_file='/var/log/utah-install') |
123 | |
124 | def _copy_qemu_scripts(self, tmpdir=None): |
125 | - initrd_work_dir = os.path.join(tmpdir, 'initrd') |
126 | + if self.initrd_no_extension: |
127 | + initrd_work_dir = self.initrd_uncompressed_path |
128 | + else: |
129 | + initrd_work_dir = os.path.join(tmpdir, 'initrd') |
130 | if not os.path.exists(initrd_work_dir): |
131 | os.makedirs(initrd_work_dir) |
132 | # copy the qemu scripts into initrd |
133 | @@ -736,8 +748,8 @@ |
134 | if self.image.installtype == 'desktop': |
135 | self._rewrite_failure_command(preseed) |
136 | |
137 | - output_preseed_filename = os.path.join(tmpdir, |
138 | - 'initrd.d', 'preseed.cfg') |
139 | + output_preseed_filename = os.path.join(self.initrd_uncompressed_path, |
140 | + 'preseed.cfg') |
141 | with open(output_preseed_filename, 'w') as f: |
142 | f.write(preseed.dump()) |
143 | self.finalpreseed = output_preseed_filename |
144 | @@ -766,7 +778,7 @@ |
145 | question.prepend('ubiquity ubiquity/summary note') |
146 | question.prepend('ubiquity ubiquity/reboot boolean true') |
147 | |
148 | - filename = os.path.join(tmpdir, 'initrd.d', 'latecommand-wrapper') |
149 | + filename = os.path.join(self.initrd_uncompressed_path, 'latecommand-wrapper') |
150 | target_log_file = '/target{}'.format(log_file) |
151 | template.write('latecommand-wrapper.jinja2', |
152 | filename, |
153 | @@ -838,10 +850,8 @@ |
154 | self.logger.info('Inserting preseed into casper') |
155 | if tmpdir is None: |
156 | tmpdir = self.tmpdir |
157 | - |
158 | - casper_dir = os.path.join(tmpdir, 'initrd.d', 'scripts', |
159 | - 'casper-bottom') |
160 | - |
161 | + casper_dir = os.path.join(os.path.join(self.initrd_uncompressed_path, 'scripts', |
162 | + 'casper-bottom')) |
163 | filename = os.path.join(casper_dir, 'utah') |
164 | template.write('casper-preseed-script.jinja2', filename) |
165 | os.chmod(filename, 0755) |
166 | @@ -856,7 +866,7 @@ |
167 | if exitstatus != 0: |
168 | raise UTAHProvisioningException('Failed to setup casper script') |
169 | |
170 | - casper_file = os.path.join(tmpdir, 'initrd.d', 'etc', 'casper.conf') |
171 | + casper_file = os.path.join(self.initrd_uncompressed_path, 'etc', 'casper.conf') |
172 | tmpfilename = '{}.tmp'.format(casper_file) |
173 | with open(casper_file, 'r') as i: |
174 | with open(tmpfilename, 'w') as o: |
175 | @@ -879,7 +889,7 @@ |
176 | """ |
177 | if tmpdir is None: |
178 | tmpdir = self.tmpdir |
179 | - inittab = os.path.join(tmpdir, 'initrd.d', 'etc', 'inittab') |
180 | + inittab = os.path.join(self.initrd_uncompressed_path, 'etc', 'inittab') |
181 | if os.path.isfile(inittab): |
182 | self.logger.info('Updating inittab') |
183 | with open(inittab, 'a') as myfile: |
184 | @@ -889,7 +899,7 @@ |
185 | "-f /var/log/syslog \n") |
186 | |
187 | self.logger.info('Creating rsyslog config file') |
188 | - conffilename = os.path.join(tmpdir, 'initrd.d', '50-utahdefault.conf') |
189 | + conffilename = os.path.join(self.initrd_uncompressed_path, '50-utahdefault.conf') |
190 | with open(conffilename, 'w') as f: |
191 | if self.rsyslog.port: |
192 | ip = self._ipaddr(config.bridge) |
193 | @@ -909,21 +919,30 @@ |
194 | self.logger.info('Repacking initrd') |
195 | if tmpdir is None: |
196 | tmpdir = self.tmpdir |
197 | - pipe = pipes.Template() |
198 | - pipe.prepend('find .', '.-') |
199 | - pipe.append('cpio --quiet -o -H newc', '--') |
200 | - # Desktop image loads initrd.gz, |
201 | - # but for physical machines we should stick with lz |
202 | - if self.image.installtype == 'desktop': |
203 | - self.logger.debug('Using lzma because installtype is desktop') |
204 | - pipe.append('lzma -9fc ', '--') |
205 | - initrd = os.path.join(tmpdir, 'initrd.lz') |
206 | + if self.initrd_no_extension: |
207 | + os.chdir(self.initrd_uncompressed_path) |
208 | + pipe = pipes.Template() |
209 | + pipe.prepend('find .', '.-') |
210 | + pipe.append('cpio --quiet -o -H newc', '--') |
211 | + initrd = os.path.join(tmpdir, 'initrd') |
212 | + if pipe.copy('/dev/null', initrd) != 0: |
213 | + raise UTAHProvisioningException('Failed to repack initrd') |
214 | else: |
215 | - self.logger.debug('Using gzip because installtype is not desktop') |
216 | - pipe.append('gzip -9fc ', '--') |
217 | - initrd = os.path.join(tmpdir, 'initrd.gz') |
218 | - if pipe.copy('/dev/null', initrd) != 0: |
219 | - raise UTAHProvisioningException('Failed to repack initrd') |
220 | + pipe = pipes.Template() |
221 | + pipe.prepend('find .', '.-') |
222 | + pipe.append('cpio --quiet -o -H newc', '--') |
223 | + # Desktop image loads initrd.gz, |
224 | + # but for physical machines we should stick with lz |
225 | + if self.image.installtype == 'desktop': |
226 | + self.logger.debug('Using lzma because installtype is desktop') |
227 | + pipe.append('lzma -9fc ', '--') |
228 | + initrd = os.path.join(tmpdir, 'initrd.lz') |
229 | + else: |
230 | + self.logger.debug('Using gzip because installtype is not desktop') |
231 | + pipe.append('gzip -9fc ', '--') |
232 | + initrd = os.path.join(tmpdir, 'initrd.gz') |
233 | + if pipe.copy('/dev/null', initrd) != 0: |
234 | + raise UTAHProvisioningException('Failed to repack initrd') |
235 | return initrd |
236 | |
237 | def _cmdlinesetup(self): |
238 | |
239 | === modified file 'utah/provisioning/vm.py' |
240 | --- utah/provisioning/vm.py 2017-07-06 18:03:17 +0000 |
241 | +++ utah/provisioning/vm.py 2018-09-10 14:38:14 +0000 |
242 | @@ -220,6 +220,7 @@ |
243 | os.makedirs(self.directory) |
244 | except OSError as err: |
245 | raise UTAHVMProvisioningException(err) |
246 | + self.first_boot = True |
247 | self.logger.debug('CustomVM init finished') |
248 | |
249 | def _createdisks(self, disksizes=None): |
250 | @@ -552,12 +553,26 @@ |
251 | if self.poweroff: |
252 | self.cleanfunction(self.vm.shutdown, force=True) |
253 | |
254 | - def _start(self): |
255 | + def _start(self, retries=6, wait=10): |
256 | """Start the VM.""" |
257 | self.logger.info('Starting CustomVM') |
258 | + attempt = 1 |
259 | if self.vm is not None: |
260 | - if self.vm.isActive() == 0: |
261 | + # For desktop tests the first boot configures the qemu script to run system tests and |
262 | + # shuts down the machine, so we start the machine and wait until it shuts down, |
263 | + # then we start it again and continue |
264 | + if self.image.installtype == 'desktop' and self.first_boot: |
265 | self.vm.create() |
266 | + while self.vm.isActive() == 1 and attempt <= retries: |
267 | + self.logger.info('Waiting for the VM to shut down, attempt number: %s', attempt) |
268 | + time.sleep(wait) |
269 | + attempt += 1 |
270 | + if self.vm.isActive() == 0: |
271 | + self.vm.create() |
272 | + self.first_boot = False |
273 | + else: |
274 | + if self.vm.isActive() == 0: |
275 | + self.vm.create() |
276 | else: |
277 | raise UTAHVMProvisioningException('Failed to provision VM') |
278 |
Looks sane, +1 assuming it works for you