Merge lp:~heber013/utah/fix-provisioning-function into lp:utah

Proposed by Heber Parrucci
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
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

To post a comment you must log in.
Revision history for this message
Paul Larson (pwlars) wrote : Posted in a previous version of this proposal

Looks sane, +1 assuming it works for you

review: Approve
Revision history for this message
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/run_utah_tests.py", line 132, in <module>
    exitstatus = timeout(config.jobtimeout, run_utah_tests)
  File "/usr/lib/python2.7/dist-packages/utah/timeout.py", line 65, in timeout
    return command(*args, **kw)
  File "/usr/bin/run_utah_tests.py", line 121, in run_utah_tests
    exitstatus, locallogs = run_tests(args, _get_machine(args))
  File "/usr/lib/python2.7/dist-packages/utah/run.py", line 344, in run_tests
    exitstatus, remote_path = _run(machine, args.runlist, extraopts)
  File "/usr/lib/python2.7/dist-packages/utah/run.py", line 256, in _run
    return _install_and_run(machine, runlist_url, extraopts)
  File "/usr/lib/python2.7/dist-packages/utah/run.py", line 174, in _install_and_run
    machine.installclient()
  File "/usr/lib/python2.7/dist-packages/utah/provisioning/provisioning.py", line 315, in installclient
    self.uploadfiles([deb], tmppath)
  File "/usr/lib/python2.7/dist-packages/utah/provisioning/ssh.py", line 202, in uploadfiles
    self.activecheck()
  File "/usr/lib/python2.7/dist-packages/utah/provisioning/ssh.py", line 364, in activecheck
    self.provisioncheck()
  File "/usr/lib/python2.7/dist-packages/utah/provisioning/provisioning.py", line 247, in provisioncheck
    config.installtimeout, self._provision, provision_data)
  File "/usr/lib/python2.7/dist-packages/utah/timeout.py", line 75, in timeout
    retval = command(*args, **kw)
  File "/usr/lib/python2.7/dist-packages/utah/provisioning/provisioning.py", line 364, in _provision
    self._create(provision_data)
  File "/usr/lib/python2.7/dist-packages/utah/provisioning/vm.py", line 522, in _create
    self._copy_qemu_scripts(tmpdir=tmpdir)
  File "/usr/lib/python2.7/dist-packages/utah/provisioning/provisioning.py", line 717, in _copy_qemu_scripts
    self.copy_qemu_scripts_to_path(initrd_work_dir)
  File "/usr/lib/python2.7/dist-packages/utah/provisioning/provisioning.py", line 1010, in copy_qemu_scripts_to_path
    shutil.copy2(src, dst)
  File "/usr/lib/python2.7/shutil.py", line 130, in copy2
    copyfile(src, dst)
  File "/usr/lib/python2.7/shutil.py", line 83, in copyfile
    with open(dst, 'wb') as fdst:
IOError: [Errno 20] Not a directory: '/var/lib/utah/vm/utah_vm_V0OnwPlGppPWxuFE/tmpcIvRKW/initrd/qemu-setup.py'

review: Needs Fixing
Revision history for this message
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/casper-bottom/utah\n[ -e /conf/param.conf ] && . /conf/param.conf /var/lib/utah/vm/utah-21-cosmic-amd64/tmp7jWHqv/initrd.d/scripts/casper-bottom/ORDER) failed with return code: 2

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

Revision history for this message
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/utah/vm/utah-74865-cosmic-server-amd64/disk0.qcow2'
2018-09-10 03:00:05,890 cleanup WARNING: OSError when changing directory permissions: [Errno 1] Operation not permitted: '/var/lib/utah/vm/utah-74865-cosmic-server-amd64/tmpBBkVPS/initrd.gz'
2018-09-10 03:00:05,891 cleanup WARNING: OSError when changing directory permissions: [Errno 1] Operation not permitted: '/var/lib/utah/vm/utah-74865-cosmic-server-amd64/tmpBBkVPS/kernel'
2018-09-10 03:00:05,891 cleanup WARNING: OSError when changing directory permissions: [Errno 1] Operation not permitted: '/var/lib/utah/vm/utah-74865-cosmic-server-amd64/tmpBBkVPS/cosmic-server-amd64.iso'
Unhandled error in UTAH:
Traceback (most recent call last):
  File "/usr/bin/run_utah_tests.py", line 132, in <module>
    exitstatus = timeout(config.jobtimeout, run_utah_tests)
  File "/usr/lib/python2.7/dist-packages/utah/timeout.py", line 65, in timeout
    return command(*args, **kw)
  File "/usr/bin/run_utah_tests.py", line 121, in run_utah_tests
    exitstatus, locallogs = run_tests(args, _get_machine(args))
  File "/usr/lib/python2.7/dist-packages/utah/run.py", line 344, in run_tests
    exitstatus, remote_path = _run(machine, args.runlist, extraopts)
  File "/usr/lib/python2.7/dist-packages/utah/run.py", line 256, in _run
    return _install_and_run(machine, runlist_url, extraopts)
  File "/usr/lib/python2.7/dist-packages/utah/run.py", line 174, in _install_and_run
    machine.installclient()
  File "/usr/lib/python2.7/dist-packages/utah/provisioning/provisioning.py", line 316, in installclient
    self.uploadfiles([deb], tmppath)
  File "/usr/lib/python2.7/dist-packages/utah/provisioning/ssh.py", line 202, in uploadfiles
    self.activecheck()
  File "/usr/lib/python2.7/dist-packages/utah/provisioning/ssh.py", line 366, in activecheck
    self._start()
  File "/usr/lib/python2.7/dist-packages/utah/provisioning/vm.py", line 570, in _start
    self.vm.create()
  File "/usr/lib/python2.7/dist-packages/libvirt.py", line 1035, in create
    if ret == -1: raise libvirtError ('virDomainCreate() failed', dom=self)
libvirtError: Requested operation is not valid: domain is already running

+ RETCODE=4

review: Needs Fixing
1134. By Heber Parrucci

Fixing start vm function

Revision history for this message
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/utah/vm/utah-74865
> -cosmic-server-amd64/disk0.qcow2'
> 2018-09-10 03:00:05,890 cleanup WARNING: OSError when changing directory
> permissions: [Errno 1] Operation not permitted: '/var/lib/utah/vm/utah-74865
> -cosmic-server-amd64/tmpBBkVPS/initrd.gz'
> 2018-09-10 03:00:05,891 cleanup WARNING: OSError when changing directory
> permissions: [Errno 1] Operation not permitted: '/var/lib/utah/vm/utah-74865
> -cosmic-server-amd64/tmpBBkVPS/kernel'
> 2018-09-10 03:00:05,891 cleanup WARNING: OSError when changing directory
> permissions: [Errno 1] Operation not permitted: '/var/lib/utah/vm/utah-74865
> -cosmic-server-amd64/tmpBBkVPS/cosmic-server-amd64.iso'
> Unhandled error in UTAH:
> Traceback (most recent call last):
> File "/usr/bin/run_utah_tests.py", line 132, in <module>
> exitstatus = timeout(config.jobtimeout, run_utah_tests)
> File "/usr/lib/python2.7/dist-packages/utah/timeout.py", line 65, in timeout
> return command(*args, **kw)
> File "/usr/bin/run_utah_tests.py", line 121, in run_utah_tests
> exitstatus, locallogs = run_tests(args, _get_machine(args))
> File "/usr/lib/python2.7/dist-packages/utah/run.py", line 344, in run_tests
> exitstatus, remote_path = _run(machine, args.runlist, extraopts)
> File "/usr/lib/python2.7/dist-packages/utah/run.py", line 256, in _run
> return _install_and_run(machine, runlist_url, extraopts)
> File "/usr/lib/python2.7/dist-packages/utah/run.py", line 174, in
> _install_and_run
> machine.installclient()
> File "/usr/lib/python2.7/dist-packages/utah/provisioning/provisioning.py",
> line 316, in installclient
> self.uploadfiles([deb], tmppath)
> File "/usr/lib/python2.7/dist-packages/utah/provisioning/ssh.py", line 202,
> in uploadfiles
> self.activecheck()
> File "/usr/lib/python2.7/dist-packages/utah/provisioning/ssh.py", line 366,
> in activecheck
> self._start()
> File "/usr/lib/python2.7/dist-packages/utah/provisioning/vm.py", line 570,
> in _start
> self.vm.create()
> File "/usr/lib/python2.7/dist-packages/libvirt.py", line 1035, in create
> 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!

Revision history for this message
Jean-Baptiste Lallement (jibel) wrote :

Thanks. Tested on Xenial with cosmic and bionic images of Desktop and server.

review: Approve

Preview Diff

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

Subscribers

People subscribed via source and target branches