Merge lp:~nick-schutt/lava-dispatcher/nicks-bootloader-interactive into lp:lava-dispatcher
- nicks-bootloader-interactive
- Merge into trunk
Status: | Rejected |
---|---|
Rejected by: | Neil Williams |
Proposed branch: | lp:~nick-schutt/lava-dispatcher/nicks-bootloader-interactive |
Merge into: | lp:lava-dispatcher |
Diff against target: |
863 lines (+365/-126) (has conflicts) 12 files modified
lava_dispatcher/actions/deploy.py (+6/-3) lava_dispatcher/client/network_master.py (+149/-0) lava_dispatcher/client/targetdevice.py (+5/-5) lava_dispatcher/config.py (+1/-0) lava_dispatcher/default-config/lava-dispatcher/device-defaults.conf (+8/-3) lava_dispatcher/default-config/lava-dispatcher/device-types/highbank.conf (+26/-0) lava_dispatcher/device/fastmodel.py (+2/-2) lava_dispatcher/device/highbank.py (+71/-64) lava_dispatcher/device/master.py (+88/-42) lava_dispatcher/device/qemu.py (+2/-2) lava_dispatcher/device/sdmux.py (+2/-2) lava_dispatcher/device/target.py (+5/-3) Text conflict in lava_dispatcher/device/highbank.py |
To merge this branch: | bzr merge lp:~nick-schutt/lava-dispatcher/nicks-bootloader-interactive |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Linaro Validation Team | Pending | ||
Review via email: mp+165158@code.launchpad.net |
This proposal supersedes a proposal from 2013-05-03.
Commit message
Description of the change
Add interactive boot support for master.py and highbank.py:
1. added bootcmds parameter to deploy.py for all calls to deploy_linaro and deploy_android
2. added sendline and expect support to bootcmds (taken from uefi.py, but removed escape() of special characters)
3. added code to master.py to read boot commands from a file, passed as the bootcmds parameter
Priority: a. json bootcmds
b. image bootcmds
c. device.conf bootcmds
4. added bootcmds support to highbank.py and moved boot sequence to config file
5. added bootcmds master support to highbank.py and moved boot sequence to config file
-> new variable, boot_cmds_master
-----
Example boot.txt:
expect Highbank \#
echo -------
expect Highbank \#
sendline setenv initrd_high "0xffffffff"
expect Highbank \#
sendline setenv fdt_high "0xffffffff"
expect Highbank \#
sendline setenv bootcmd "ext2load scsi 0:1 0x00800000 uImage; ext2load scsi 0:1 0x01000000 uInitrd; bootm 0x00800000 0x01000000 0x00001000"
expect Highbank \#
sendline setenv bootargs "console=
expect Highbank \#
echo -------
expect Highbank \#
sendline boot
Unmerged revisions
- 637. By Nicholas Schutt
-
remove boot_cmds from highbank config (the image takes care of this)
- 636. By Nicholas Schutt
-
remove boot_cmds from highbank config (the image takes care of this)
- 635. By Nicholas Schutt
-
remove boot_cmds from highbank config (the image takes care of this)
- 634. By Nicholas Schutt
-
remove boot_cmds from highbank config (the image takes care of this)
- 633. By Nicholas Schutt
-
merge trunk
- 632. By Nicholas Schutt
-
read file and strip newlines in one line
- 631. By Nicholas Schutt
-
read file and strip newlines in one line
- 630. By Nicholas Schutt
-
map lines without sendline/expect keyword as sendline for backward compatability
- 629. By Nicholas Schutt
-
debug boot_cmds
- 628. By Nicholas Schutt
-
remove carriage returns from boot commands file
Preview Diff
1 | === modified file 'lava_dispatcher/actions/deploy.py' |
2 | --- lava_dispatcher/actions/deploy.py 2013-04-17 08:23:50 +0000 |
3 | +++ lava_dispatcher/actions/deploy.py 2013-05-22 14:07:36 +0000 |
4 | @@ -53,6 +53,7 @@ |
5 | 'hwpack': {'type': 'string', 'optional': True}, |
6 | 'rootfs': {'type': 'string', 'optional': True}, |
7 | 'image': {'type': 'string', 'optional': True}, |
8 | + 'bootcmds': {'type': 'string', 'optional': True}, |
9 | 'rootfstype': {'type': 'string', 'optional': True}, |
10 | 'bootloader': {'type': 'string', 'optional': True, 'default': 'u_boot'}, |
11 | }, |
12 | @@ -70,9 +71,10 @@ |
13 | elif 'image' not in parameters: |
14 | raise ValueError('must specify image if not specifying a hwpack') |
15 | |
16 | - def run(self, hwpack=None, rootfs=None, image=None, rootfstype='ext3', bootloader='u_boot'): |
17 | + def run(self, hwpack=None, rootfs=None, image=None, rootfstype='ext3', bootloader='u_boot', bootcmds=None): |
18 | self.client.deploy_linaro( |
19 | - hwpack=hwpack, rootfs=rootfs, image=image, rootfstype=rootfstype, bootloader=bootloader) |
20 | + hwpack=hwpack, rootfs=rootfs, image=image, rootfstype=rootfstype, |
21 | + bootloader=bootloader, bootcmds=bootcmds) |
22 | |
23 | |
24 | class cmd_deploy_linaro_android_image(BaseAction): |
25 | @@ -83,13 +85,14 @@ |
26 | 'boot': {'type': 'string'}, |
27 | 'system': {'type': 'string'}, |
28 | 'data': {'type': 'string'}, |
29 | + 'bootcmds': {'type': 'string', 'optional': True}, |
30 | 'rootfstype': {'type': 'string', 'optional': True, 'default': 'ext4'}, |
31 | }, |
32 | 'additionalProperties': False, |
33 | } |
34 | |
35 | def run(self, boot, system, data, rootfstype='ext4'): |
36 | - self.client.deploy_linaro_android(boot, system, data, rootfstype) |
37 | + self.client.deploy_linaro_android(boot, system, data, rootfstype, bootcmds=bootcmds) |
38 | |
39 | |
40 | class cmd_dummy_deploy(BaseAction): |
41 | |
42 | === added file 'lava_dispatcher/client/network_master.py' |
43 | --- lava_dispatcher/client/network_master.py 1970-01-01 00:00:00 +0000 |
44 | +++ lava_dispatcher/client/network_master.py 2013-05-22 14:07:36 +0000 |
45 | @@ -0,0 +1,149 @@ |
46 | +# Copyright (C) 2013 Linaro Limited |
47 | +# |
48 | +# Author: Michael Hudson-Doyle <michael.hudson@linaro.org> |
49 | +# Author: Nicholas Schutt <nick.schutt@linaro.org> |
50 | +# |
51 | +# This file is part of LAVA Dispatcher. |
52 | +# |
53 | +# LAVA Dispatcher is free software; you can redistribute it and/or modify |
54 | +# it under the terms of the GNU General Public License as published by |
55 | +# the Free Software Foundation; either version 2 of the License, or |
56 | +# (at your option) any later version. |
57 | +# |
58 | +# LAVA Dispatcher is distributed in the hope that it will be useful, |
59 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
60 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
61 | +# GNU General Public License for more details. |
62 | +# |
63 | +# You should have received a copy of the GNU General Public License |
64 | +# along |
65 | +# with this program; if not, see <http://www.gnu.org/licenses>. |
66 | + |
67 | +import commands |
68 | +import logging |
69 | +import pexpect |
70 | +import sys |
71 | +import time |
72 | +import traceback |
73 | + |
74 | +import lava_dispatcher.utils as utils |
75 | + |
76 | +from lava_dispatcher.client.base import ( |
77 | + NetworkCommandRunner, |
78 | +) |
79 | +from lava_dispatcher.errors import ( |
80 | + NetworkError, |
81 | + OperationFailed, |
82 | + CriticalError, |
83 | +) |
84 | + |
85 | + |
86 | +class NetworkMasterCommandRunner(NetworkCommandRunner): |
87 | + """A CommandRunner to use when the board is booted into the master image. |
88 | + """ |
89 | + _prompt_str_includes_rc = False |
90 | + def __init__(self, target, prompt_str_includes_rc=False): |
91 | + super(NetworkMasterCommandRunner, self).__init__( |
92 | + target, target.MASTER_PS1_PATTERN, prompt_str_includes_rc) |
93 | + self._prompt_str_includes_rc = prompt_str_includes_rc |
94 | + |
95 | + def run(self, cmd, response=None, timeout=-1, failok=False, wait_prompt=True): |
96 | + NetworkCommandRunner.run(self, cmd, response, timeout, failok, wait_prompt) |
97 | + rc = None |
98 | + if wait_prompt and not self._prompt_str_includes_rc: |
99 | + rc = self.get_result() |
100 | + if not failok and rc != 0: |
101 | + raise OperationFailed( |
102 | + "executing %r failed with code %s" % (cmd, rc)) |
103 | + return rc |
104 | + |
105 | + def get_result(self): |
106 | + rc = None |
107 | + match_id, match = self.match_id, self.match |
108 | + NetworkCommandRunner.run(self, "echo x$?x", response='x([0-9]+)x', timeout=5) |
109 | + if self.match_id != 0: |
110 | + raise OperationFailed("") |
111 | + else: |
112 | + rc = int(self.match.group(1)) |
113 | + return rc |
114 | + |
115 | + def get_master_ip(self): |
116 | + logging.info("Waiting for network to come up") |
117 | + try: |
118 | + self.wait_network_up(timeout=20) |
119 | + except NetworkError: |
120 | + logging.exception("Unable to reach LAVA server") |
121 | + raise |
122 | + |
123 | + ip_pat = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' |
124 | + cmd = ("ifconfig %s | grep 'inet addr' | awk -F: '{print $2}' |" |
125 | + "awk '{print \"<\" $1 \">\"}'" % |
126 | + self._client.config.default_network_interface) |
127 | + self.run(cmd, response='(%s)' % ip_pat, wait_prompt=False) |
128 | + if self.match_id != 0: |
129 | + msg = "Unable to determine master image IP address" |
130 | + logging.error(msg) |
131 | + raise CriticalError(msg) |
132 | + ip = self.match.group(1) |
133 | + logging.debug("Master image IP is %s" % ip) |
134 | + self.master_ip = ip |
135 | + return ip |
136 | + |
137 | + def get_device_version(self): |
138 | + pattern = 'device_version=(\d+-\d+/\d+-\d+)' |
139 | + self.run("echo \"device_version=" |
140 | + "$(lava-master-image-info --master-image-hwpack " |
141 | + "| sed 's/[^0-9-]//g; s/^-\+//')" |
142 | + "/" |
143 | + "$(lava-master-image-info --master-image-rootfs " |
144 | + "| sed 's/[^0-9-]//g; s/^-\+//')" |
145 | + "\"", |
146 | + [pattern, pexpect.EOF, pexpect.TIMEOUT], |
147 | + timeout = 5) |
148 | + device_version = None |
149 | + if self.match_id == 0: |
150 | + device_version = self.match.group(1) |
151 | + logging.debug('Master image version (hwpack/rootfs) is %s' % device_version) |
152 | + else: |
153 | + logging.warning('Could not determine image version!') |
154 | + return device_version |
155 | + |
156 | + def has_partition_with_label(self, label): |
157 | + if not label: |
158 | + return False |
159 | + |
160 | + path = '/dev/disk/by-label/%s' % label |
161 | + return self.is_file_exist(path) |
162 | + |
163 | + def is_file_exist(self, path): |
164 | + cmd = 'ls %s > /dev/null' % path |
165 | + rc = self.run(cmd, failok=True) |
166 | + if rc == 0: |
167 | + return True |
168 | + return False |
169 | + |
170 | + def start_http_server(self, port=80): |
171 | + master_ip = self.get_master_ip() |
172 | + # busybox produces no output to parse for, so let it run as a daemon |
173 | + self.run('busybox httpd -v -p %s' % port) |
174 | + url_base = "http://%s:%s" % (master_ip, port) |
175 | + return url_base |
176 | + |
177 | + def stop_http_server(self): |
178 | + self.run('killall busybox') |
179 | + |
180 | + def target_wget_extract(self, tar_url, dest, timeout=-1): |
181 | + decompression_cmd = '' |
182 | + if tar_url.endswith('.gz') or tar_url.endswith('.tgz'): |
183 | + decompression_cmd = '| /bin/gzip -dc' |
184 | + elif tar_url.endswith('.bz2'): |
185 | + decompression_cmd = '| /bin/bzip2 -dc' |
186 | + elif tar_url.endswith('.tar'): |
187 | + decompression_cmd = '' |
188 | + else: |
189 | + raise RuntimeError('bad file extension: %s' % tar_url) |
190 | + |
191 | + self.run('wget -O - %s %s | /bin/tar -C %s -xmf -' |
192 | + % (tar_url, decompression_cmd, dest), |
193 | + timeout=timeout) |
194 | + |
195 | |
196 | === modified file 'lava_dispatcher/client/targetdevice.py' |
197 | --- lava_dispatcher/client/targetdevice.py 2013-04-23 09:06:25 +0000 |
198 | +++ lava_dispatcher/client/targetdevice.py 2013-05-22 14:07:36 +0000 |
199 | @@ -46,11 +46,11 @@ |
200 | super(TargetBasedClient, self).__init__(context, config) |
201 | self.target_device = get_target(context, config) |
202 | |
203 | - def deploy_linaro_android(self, boot, system, data, rootfstype='ext4'): |
204 | - self.target_device.deploy_android(boot, system, data) |
205 | + def deploy_linaro_android(self, boot, system, data, rootfstype='ext4', bootcmds=None): |
206 | + self.target_device.deploy_android(boot, system, data, bootcmds=bootcmds) |
207 | |
208 | def deploy_linaro(self, hwpack=None, rootfs=None, image=None, |
209 | - rootfstype='ext3', bootloader='u_boot'): |
210 | + rootfstype='ext3', bootloader='u_boot', bootcmds=None): |
211 | if image is None: |
212 | if hwpack is None or rootfs is None: |
213 | raise CriticalError( |
214 | @@ -60,9 +60,9 @@ |
215 | "cannot specify hwpack or rootfs when specifying image") |
216 | |
217 | if image is None: |
218 | - self.target_device.deploy_linaro(hwpack, rootfs, bootloader) |
219 | + self.target_device.deploy_linaro(hwpack, rootfs, bootloader, bootcmds=bootcmds) |
220 | else: |
221 | - self.target_device.deploy_linaro_prebuilt(image) |
222 | + self.target_device.deploy_linaro_prebuilt(image, bootcmds=bootcmds) |
223 | |
224 | def _boot_linaro_image(self): |
225 | if self.proc: |
226 | |
227 | === modified file 'lava_dispatcher/config.py' |
228 | --- lava_dispatcher/config.py 2013-05-16 01:53:21 +0000 |
229 | +++ lava_dispatcher/config.py 2013-05-22 14:07:36 +0000 |
230 | @@ -30,6 +30,7 @@ |
231 | android_binary_drivers = schema.StringOption() |
232 | cts_media_url = schema.StringOption() |
233 | boot_cmds = schema.StringOption(fatal=True) # Can do better here |
234 | + boot_cmds_master = schema.StringOption(fatal=True) # And here |
235 | boot_cmds_android = schema.StringOption(fatal=True) # And here |
236 | boot_cmds_oe = schema.StringOption(fatal=True) # And here? |
237 | read_boot_cmds_from_image = schema.BoolOption(default=True) |
238 | |
239 | === modified file 'lava_dispatcher/default-config/lava-dispatcher/device-defaults.conf' |
240 | --- lava_dispatcher/default-config/lava-dispatcher/device-defaults.conf 2013-05-14 18:58:37 +0000 |
241 | +++ lava_dispatcher/default-config/lava-dispatcher/device-defaults.conf 2013-05-22 14:07:36 +0000 |
242 | @@ -16,13 +16,18 @@ |
243 | |
244 | pre_connect_command = |
245 | |
246 | -# The bootloader commands to boot the device into the test image (we |
247 | -# assume that the device boots into the master image without bootloader |
248 | -# intervention). |
249 | +# The bootloader commands to boot the device into the test image. |
250 | # |
251 | # XXX should be called # boot_test_image_commands ? |
252 | boot_cmds = |
253 | |
254 | +# The bootloader commands to boot the device into the master image (if |
255 | +# this is not defined, we assume that the device boots into the master |
256 | +# image without bootloader intervention). |
257 | +# |
258 | +# XXX should be called # boot_master_image_commands ? |
259 | +boot_cmds_master = |
260 | + |
261 | # The bootloader commands to boot the device into an android-based test |
262 | # image. |
263 | # |
264 | |
265 | === modified file 'lava_dispatcher/default-config/lava-dispatcher/device-types/highbank.conf' |
266 | --- lava_dispatcher/default-config/lava-dispatcher/device-types/highbank.conf 2013-02-14 03:14:34 +0000 |
267 | +++ lava_dispatcher/default-config/lava-dispatcher/device-types/highbank.conf 2013-05-22 14:07:36 +0000 |
268 | @@ -1,2 +1,28 @@ |
269 | client_type = highbank |
270 | connection_command = ipmitool -I lanplus -U admin -P admin -H %(ecmeip)s sol activate |
271 | + |
272 | +interrupt_boot_prompt = Hit any key to stop autoboot: |
273 | + |
274 | +boot_cmds_master = expect Highbank \#, |
275 | + sendline dhcp, |
276 | + expect Highbank \#, |
277 | + sendline pxe get, |
278 | + expect Highbank \#, |
279 | + sendline pxe boot, |
280 | + expect Enter choice:, |
281 | + sendline 1, |
282 | + expect \(initramfs\), |
283 | + sendline . /scripts/functions, |
284 | + expect \(initramfs\), |
285 | + sendline DEVICE=eth0 configure_networking, |
286 | + expect \(initramfs\), |
287 | + sendline mkdir -p /var/run /var/lib/dhcp /usr/sbin, |
288 | + expect \(initramfs\), |
289 | + sendline dhclient -v -1, |
290 | + expect \(initramfs\), |
291 | + sendline bash, |
292 | + expect \(initramfs\), |
293 | + sendline /bin/busybox --install -s |
294 | + |
295 | +master_str = \(initramfs\) |
296 | + |
297 | |
298 | === modified file 'lava_dispatcher/device/fastmodel.py' |
299 | --- lava_dispatcher/device/fastmodel.py 2013-03-25 20:23:35 +0000 |
300 | +++ lava_dispatcher/device/fastmodel.py 2013-05-22 14:07:36 +0000 |
301 | @@ -110,7 +110,7 @@ |
302 | |
303 | self._customize_android() |
304 | |
305 | - def deploy_linaro(self, hwpack=None, rootfs=None, bootloader='u_boot'): |
306 | + def deploy_linaro(self, hwpack=None, rootfs=None, bootloader='u_boot', bootcmds=None): |
307 | hwpack = download_image(hwpack, self.context, decompress=False) |
308 | rootfs = download_image(rootfs, self.context, decompress=False) |
309 | odir = os.path.dirname(rootfs) |
310 | @@ -128,7 +128,7 @@ |
311 | |
312 | self._customize_linux(self._sd_image) |
313 | |
314 | - def deploy_linaro_prebuilt(self, image): |
315 | + def deploy_linaro_prebuilt(self, image, bootcmds=None): |
316 | self._sd_image = download_image(image, self.context) |
317 | self._copy_axf(self.config.root_part, 'boot') |
318 | |
319 | |
320 | === modified file 'lava_dispatcher/device/highbank.py' |
321 | --- lava_dispatcher/device/highbank.py 2013-05-15 18:17:02 +0000 |
322 | +++ lava_dispatcher/device/highbank.py 2013-05-22 14:07:36 +0000 |
323 | @@ -24,11 +24,14 @@ |
324 | import os |
325 | import pexpect |
326 | import time |
327 | +import re |
328 | |
329 | from lava_dispatcher import tarballcache |
330 | +from lava_dispatcher.device import boot_options |
331 | |
332 | from lava_dispatcher.device.master import ( |
333 | MasterCommandRunner, |
334 | + MasterImageTarget, |
335 | ) |
336 | from lava_dispatcher.device.target import ( |
337 | Target |
338 | @@ -44,6 +47,7 @@ |
339 | ) |
340 | from lava_dispatcher.utils import ( |
341 | mk_targz, |
342 | + string_to_list, |
343 | rmtree, |
344 | ) |
345 | from lava_dispatcher.client.lmc_utils import ( |
346 | @@ -52,43 +56,53 @@ |
347 | from lava_dispatcher.ipmi import IpmiPxeBoot |
348 | |
349 | |
350 | -class HighbankTarget(Target): |
351 | - |
352 | - MASTER_PS1 = 'root@master [rc=$(echo \$?)]# ' |
353 | - MASTER_PS1_PATTERN = 'root@master \[rc=(\d+)\]# ' |
354 | +class HighbankTarget(MasterImageTarget): |
355 | |
356 | def __init__(self, context, config): |
357 | super(HighbankTarget, self).__init__(context, config) |
358 | - self.proc = self.context.spawn(self.config.connection_command, timeout=1200) |
359 | - self.device_version = None |
360 | + self.bootcontrol = IpmiPxeBoot(context, self.config.ecmeip) |
361 | + Target.ubuntu_deployment_data['boot_cmds_master'] = 'boot_cmds_master' |
362 | + Target.oe_deployment_data['boot_cmds_master'] = 'boot_cmds_master' |
363 | + Target.fedora_deployment_data['boot_cmds_master'] = 'boot_cmds_master' |
364 | + Target.android_deployment_data['boot_cmds_master'] = 'boot_cmds_master' |
365 | + |
366 | + def connect_to_target(self): |
367 | if self.config.ecmeip == None: |
368 | msg = "The ecmeip address is not set for this target" |
369 | logging.error(msg) |
370 | raise CriticalError(msg) |
371 | - self.bootcontrol = IpmiPxeBoot(context, self.config.ecmeip) |
372 | - |
373 | - def get_device_version(self): |
374 | - return self.device_version |
375 | - |
376 | - def power_on(self): |
377 | - self.bootcontrol.power_on_boot_image() |
378 | - return self.proc |
379 | + return self.context.spawn(self.config.connection_command, timeout=1200) |
380 | |
381 | def power_off(self, proc): |
382 | self.bootcontrol.power_off() |
383 | |
384 | - def deploy_linaro(self, hwpack, rfs, bootloader): |
385 | + def _soft_reboot(self): |
386 | + self._hard_reboot() |
387 | + |
388 | + def _hard_reboot(self): |
389 | + self.bootcontrol.ipmitool.power_on() |
390 | + self.bootcontrol.ipmitool.reset() |
391 | + |
392 | + def deploy_linaro(self, hwpack, rfs, bootloader, bootcmds=None): |
393 | image_file = generate_image(self, hwpack, rfs, self.scratch_dir, bootloader, |
394 | extra_boot_args='1', image_size='1G') |
395 | self._customize_linux(image_file) |
396 | - self._deploy_image(image_file, '/dev/sda') |
397 | + if bootcmds != None: |
398 | + self._read_boot_cmds_from_file(bootcmds) |
399 | +# self._read_boot_cmds(boot_tgz=boot_tgz) |
400 | + self._deploy_image_dd(image_file, '/dev/sda') |
401 | |
402 | - def deploy_linaro_prebuilt(self, image): |
403 | + def deploy_linaro_prebuilt(self, image, bootcmds=None): |
404 | image_file = download_image(image, self.context, self.scratch_dir) |
405 | + data = 'ubuntu' |
406 | + self.deployment_data = self.target_map[data] |
407 | self._customize_linux(image_file) |
408 | - self._deploy_image(image_file, '/dev/sda') |
409 | + if bootcmds != None: |
410 | + self._read_boot_cmds_from_file(bootcmds) |
411 | +# self._read_boot_cmds(boot_tgz=boot_tgz) |
412 | + self._deploy_image_dd(image_file, '/dev/sda') |
413 | |
414 | - def _deploy_image(self, image_file, device): |
415 | + def _deploy_image_dd(self, image_file, device): |
416 | with self._as_master() as runner: |
417 | |
418 | # erase the first part of the disk to make sure the new deploy works |
419 | @@ -96,7 +110,7 @@ |
420 | |
421 | # compress the image to reduce the transfer size |
422 | if not image_file.endswith('.bz2') and not image_file.endswith('gz'): |
423 | - os.system('bzip2 -9v ' + image_file) |
424 | + os.system('bzip2 -v ' + image_file) |
425 | image_file += '.bz2' |
426 | |
427 | tmpdir = self.context.config.lava_image_tmpdir |
428 | @@ -137,8 +151,12 @@ |
429 | 'unknown master image partition(%d)' % partition) |
430 | return partition |
431 | |
432 | +<<<<<<< TREE |
433 | def resize_rootfs_partition(self, runner): |
434 | partno = self.config.root_part |
435 | +======= |
436 | + def resize_rootfs_partition(self, runner, partno = '2'): |
437 | +>>>>>>> MERGE-SOURCE |
438 | start = None |
439 | |
440 | runner.run('parted -s /dev/sda print', |
441 | @@ -160,6 +178,7 @@ |
442 | else: |
443 | logging.warning("unknown partition type for resize: %s" % parttype) |
444 | |
445 | +<<<<<<< TREE |
446 | @contextlib.contextmanager |
447 | def file_system(self, partition, directory): |
448 | logging.info('attempting to access master filesystem %r:%s' % |
449 | @@ -228,20 +247,40 @@ |
450 | runner.run('wget -O - %s %s | /bin/tar -C %s -xmf -' |
451 | % (tar_url, decompression_cmd, dest), |
452 | timeout=timeout) |
453 | +======= |
454 | + def _boot_linaro_image(self): |
455 | + self.bootcontrol.ipmitool.set_to_boot_from_disk() |
456 | + super(HighbankTarget,self)._boot_linaro_image() |
457 | + |
458 | +>>>>>>> MERGE-SOURCE |
459 | |
460 | @contextlib.contextmanager |
461 | def _as_master(self): |
462 | - self.bootcontrol.power_on_boot_master() |
463 | - |
464 | - # Two reboots seem to be necessary to ensure that pxe boot is used. |
465 | - # Need to identify the cause and fix it |
466 | - self.proc.expect("Hit any key to stop autoboot:") |
467 | - self.proc.sendline('') |
468 | - self.bootcontrol.power_reset_boot_master() |
469 | - |
470 | - self.proc.expect("\(initramfs\)") |
471 | + """A session that can be used to run commands in the master image.""" |
472 | + self.boot_master_image() |
473 | + yield MasterCommandRunner(self) |
474 | + |
475 | + def boot_master_image(self): |
476 | + boot_cmds_master = self.deployment_data['boot_cmds_master'] |
477 | + |
478 | + options = boot_options.as_dict(self, defaults={'boot_cmds_master': boot_cmds_master}) |
479 | + if 'boot_cmds_master' in options: |
480 | + boot_cmds_master = options['boot_cmds_master'].value |
481 | + |
482 | + boot_cmds_master = self.config.cp.get('__main__', boot_cmds_master) |
483 | + boot_cmds_master = string_to_list(boot_cmds_master.encode('ascii')) |
484 | + |
485 | + logging.info('boot_cmds_master attribute: %s', boot_cmds_master) |
486 | + |
487 | + self.bootcontrol.ipmitool.set_to_boot_from_pxe() |
488 | + |
489 | + self._boot(boot_cmds_master) |
490 | + |
491 | + self.proc.expect(self.config.master_str, timeout=300) |
492 | + |
493 | self.proc.sendline('export PS1="%s"' % self.MASTER_PS1) |
494 | self.proc.expect(self.MASTER_PS1_PATTERN, timeout=180, lava_no_logging=1) |
495 | +<<<<<<< TREE |
496 | runner = HBMasterCommandRunner(self) |
497 | |
498 | runner.run(". /scripts/functions") |
499 | @@ -259,42 +298,10 @@ |
500 | runner.run("mkdir -p /var/lib/dhcp") |
501 | runner.run("dhclient -v -1") |
502 | |
503 | +======= |
504 | + runner = MasterCommandRunner(self) |
505 | +>>>>>>> MERGE-SOURCE |
506 | self.device_version = runner.get_device_version() |
507 | |
508 | - try: |
509 | - yield runner |
510 | - finally: |
511 | - logging.debug("deploy done") |
512 | - |
513 | - |
514 | target_class = HighbankTarget |
515 | |
516 | - |
517 | -class HBMasterCommandRunner(MasterCommandRunner): |
518 | - """A CommandRunner to use when the target is booted into the master image. |
519 | - """ |
520 | - http_pid = None |
521 | - |
522 | - def __init__(self, target): |
523 | - super(HBMasterCommandRunner, self).__init__(target) |
524 | - |
525 | - def start_http_server(self): |
526 | - master_ip = self.get_master_ip() |
527 | - if self.http_pid != None: |
528 | - raise OperationFailed("busybox httpd already running with pid %" % self.http_pid) |
529 | - # busybox produces no output to parse for, so run it in the bg and get its pid |
530 | - self.run('busybox httpd -f &') |
531 | - self.run('echo pid:$!:pid',response="pid:(\d+):pid",timeout=10) |
532 | - if self.match_id != 0: |
533 | - raise OperationFailed("busybox httpd did not start") |
534 | - else: |
535 | - self.http_pid = self.match.group(1) |
536 | - url_base = "http://%s" % (master_ip) |
537 | - return url_base |
538 | - |
539 | - def stop_http_server(self): |
540 | - if self.http_pid == None: |
541 | - raise OperationFailed("busybox httpd not running, but stop_http_server called.") |
542 | - self.run('kill %s' % self.http_pid) |
543 | - self.http_pid = None |
544 | - |
545 | |
546 | === modified file 'lava_dispatcher/device/master.py' |
547 | --- lava_dispatcher/device/master.py 2013-05-20 06:37:29 +0000 |
548 | +++ lava_dispatcher/device/master.py 2013-05-22 14:07:36 +0000 |
549 | @@ -75,7 +75,7 @@ |
550 | Target.ubuntu_deployment_data['boot_cmds'] = 'boot_cmds' |
551 | Target.oe_deployment_data['boot_cmds'] = 'boot_cmds_oe' |
552 | Target.fedora_deployment_data['boot_cmds'] = 'boot_cmds' |
553 | - |
554 | + |
555 | # used for tarballcache logic to get proper boot_cmds |
556 | Target.ubuntu_deployment_data['data_type'] = 'ubuntu' |
557 | Target.oe_deployment_data['data_type'] = 'oe' |
558 | @@ -93,8 +93,11 @@ |
559 | if config.pre_connect_command: |
560 | self.context.run_command(config.pre_connect_command) |
561 | |
562 | - self.proc = connect_to_serial(self.context) |
563 | + self.proc = self.connect_to_target() |
564 | |
565 | + def connect_to_target(self): |
566 | + return connect_to_serial(self.context) |
567 | + |
568 | def get_device_version(self): |
569 | return self.device_version |
570 | |
571 | @@ -106,16 +109,18 @@ |
572 | # we always leave master image devices powered on |
573 | pass |
574 | |
575 | - def deploy_linaro(self, hwpack, rfs, bootloader): |
576 | + def deploy_linaro(self, hwpack, rfs, bootloader, bootcmds=None): |
577 | self.boot_master_image() |
578 | |
579 | image_file = generate_image(self, hwpack, rfs, self.scratch_dir, bootloader) |
580 | (boot_tgz, root_tgz, data) = self._generate_tarballs(image_file) |
581 | |
582 | + if bootcmds != None: |
583 | + self._read_boot_cmds_from_file(bootcmds) |
584 | self._read_boot_cmds(boot_tgz=boot_tgz) |
585 | self._deploy_tarballs(boot_tgz, root_tgz) |
586 | |
587 | - def deploy_android(self, boot, system, userdata): |
588 | + def deploy_android(self, boot, system, userdata, bootcmds=None): |
589 | self.boot_master_image() |
590 | |
591 | sdir = self.scratch_dir |
592 | @@ -123,6 +128,9 @@ |
593 | system = download_image(system, self.context, sdir, decompress=False) |
594 | data = download_image(userdata, self.context, sdir, decompress=False) |
595 | |
596 | + if bootcmds != None: |
597 | + self._read_boot_cmds_from_file(bootcmds) |
598 | + |
599 | with self._as_master() as master: |
600 | self._format_testpartition(master, 'ext4') |
601 | self._deploy_android_tarballs(master, boot, system, data) |
602 | @@ -149,7 +157,7 @@ |
603 | _deploy_linaro_android_system(master, system_url) |
604 | _deploy_linaro_android_data(master, data_url) |
605 | |
606 | - def deploy_linaro_prebuilt(self, image): |
607 | + def deploy_linaro_prebuilt(self, image, bootcmds=None): |
608 | self.boot_master_image() |
609 | |
610 | if self.context.job_data.get('health_check', False): |
611 | @@ -160,6 +168,8 @@ |
612 | image_file = download_image(image, self.context, self.scratch_dir) |
613 | (boot_tgz, root_tgz, data) = self._generate_tarballs(image_file) |
614 | |
615 | + if bootcmds != None: |
616 | + self._read_boot_cmds_from_file(bootcmds) |
617 | self._read_boot_cmds(boot_tgz=boot_tgz) |
618 | self._deploy_tarballs(boot_tgz, root_tgz) |
619 | |
620 | @@ -205,6 +215,15 @@ |
621 | |
622 | return boot_cmds.split('\n') |
623 | |
624 | + def _read_boot_cmds_from_file(self, cmdfile, keyname='boot_cmds_from_file'): |
625 | + # If we have already obtained boot commands dynamically, then return. |
626 | + if self.deployment_data.get(keyname, False): |
627 | + logging.debug("We have already read boot commands from a file") |
628 | + return |
629 | + sdir = self.scratch_dir |
630 | + bootcmd_file = download_image(cmdfile, self.context, sdir, decompress=True) |
631 | + self.deployment_data[keyname] = [line.rstrip('\n') for line in open(bootcmd_file)] |
632 | + |
633 | def _read_boot_cmds(self, image=None, boot_tgz=None): |
634 | boot_file_path = None |
635 | |
636 | @@ -326,6 +345,7 @@ |
637 | assert directory != '/', "cannot mount entire partition" |
638 | |
639 | with self._as_master() as runner: |
640 | + runner.run('mkdir -p /mnt') |
641 | partition = self.get_partition(runner, partition) |
642 | runner.run('mount %s /mnt' % partition) |
643 | try: |
644 | @@ -338,17 +358,10 @@ |
645 | runner.run('tar -czf /tmp/fs.tgz -C %s %s' % |
646 | (parent_dir, target_name)) |
647 | runner.run('cd /tmp') # need to be in same dir as fs.tgz |
648 | - self.proc.sendline('python -m SimpleHTTPServer 0 2>/dev/null') |
649 | - match_id = self.proc.expect([ |
650 | - 'Serving HTTP on 0.0.0.0 port (\d+) \.\.', |
651 | - pexpect.EOF, pexpect.TIMEOUT]) |
652 | - if match_id != 0: |
653 | - msg = "Unable to start HTTP server on master" |
654 | - logging.error(msg) |
655 | - raise CriticalError(msg) |
656 | - port = self.proc.match.groups()[match_id] |
657 | - |
658 | - url = "http://%s:%s/fs.tgz" % (self.master_ip, port) |
659 | + |
660 | + url_base = runner.start_http_server() |
661 | + |
662 | + url = url_base + '/fs.tgz' |
663 | tf = download_with_retry( |
664 | self.context, self.scratch_dir, url, False) |
665 | |
666 | @@ -363,7 +376,7 @@ |
667 | mk_targz(tf, tfdir) |
668 | rmtree(tfdir) |
669 | |
670 | - self.proc.sendcontrol('c') # kill SimpleHTTPServer |
671 | + runner.stop_http_server() |
672 | |
673 | # get the last 2 parts of tf, ie "scratchdir/tf.tgz" |
674 | tf = '/'.join(tf.split('/')[-2:]) |
675 | @@ -372,7 +385,7 @@ |
676 | self.target_extract(runner, url, parent_dir) |
677 | |
678 | finally: |
679 | - self.proc.sendcontrol('c') # kill SimpleHTTPServer |
680 | + runner.stop_http_server() |
681 | runner.run('umount /mnt') |
682 | |
683 | def extract_tarball(self, tarball_url, partition, directory='/'): |
684 | @@ -488,40 +501,52 @@ |
685 | self.proc.sendline(self.config.interrupt_boot_command) |
686 | |
687 | def _boot_linaro_image(self): |
688 | - boot_cmds = self.deployment_data['boot_cmds'] |
689 | - boot_cmds_override = False |
690 | - |
691 | - options = boot_options.as_dict(self, defaults={'boot_cmds': boot_cmds}) |
692 | - if 'boot_cmds' in options: |
693 | - boot_cmds_override = True |
694 | - boot_cmds = options['boot_cmds'].value |
695 | - |
696 | - logging.info('boot_cmds attribute: %s', boot_cmds) |
697 | - |
698 | - # Check if we have already got some values from image's boot file. |
699 | - if self.deployment_data.get('boot_cmds_dynamic') \ |
700 | - and not boot_cmds_override: |
701 | + # Check if we have already got some values from the test or from |
702 | + # the image's boot file. |
703 | + if self.deployment_data.get('boot_cmds_from_file', False): |
704 | + boot_cmds = self.deployment_data['boot_cmds_from_file'] |
705 | + logging.info('boot_cmds_from_file: %s', boot_cmds) |
706 | + elif self.deployment_data.get('boot_cmds_dynamic', False): |
707 | logging.info('Loading boot_cmds from image') |
708 | boot_cmds = self.deployment_data['boot_cmds_dynamic'] |
709 | else: |
710 | + boot_cmds = self.deployment_data['boot_cmds'] |
711 | + options = boot_options.as_dict(self, defaults={'boot_cmds': boot_cmds}) |
712 | + if 'boot_cmds' in options: |
713 | + boot_cmds = options['boot_cmds'].value |
714 | logging.info('Loading boot_cmds from device configuration') |
715 | boot_cmds = self.config.cp.get('__main__', boot_cmds) |
716 | boot_cmds = string_to_list(boot_cmds.encode('ascii')) |
717 | |
718 | + logging.info('boot_cmds attribute: %s', boot_cmds) |
719 | + |
720 | self._boot(boot_cmds) |
721 | |
722 | def _boot(self, boot_cmds): |
723 | - try: |
724 | - self._soft_reboot() |
725 | - self._enter_bootloader() |
726 | - except: |
727 | - logging.exception("_enter_bootloader failed") |
728 | - self._hard_reboot() |
729 | - self._enter_bootloader() |
730 | - self.proc.sendline(boot_cmds[0]) |
731 | - for line in range(1, len(boot_cmds)): |
732 | - self.proc.expect(self.config.bootloader_prompt, timeout=300) |
733 | - self.proc.sendline(boot_cmds[line]) |
734 | + self._soft_reboot() |
735 | + if len(boot_cmds) > 0: |
736 | + try: |
737 | + self._enter_bootloader() |
738 | + except: |
739 | + logging.exception("_enter_bootloader failed") |
740 | + self._hard_reboot() |
741 | + self._enter_bootloader() |
742 | + for line in range(0, len(boot_cmds)): |
743 | + parts = re.match('^(?P<action>sendline|expect)\s*(?P<command>.*)', boot_cmds[line]) |
744 | + try: |
745 | + action = parts.group('action') |
746 | + command = parts.group('command') |
747 | + except AttributeError as e: |
748 | + action = "sendline" |
749 | + command = boot_cmds[line] |
750 | + |
751 | + if action == "expect": |
752 | + self.proc.expect(command, timeout=300) |
753 | + elif action == "sendline": |
754 | + self.proc.empty_buffer() |
755 | + self.proc.sendline(command) |
756 | + else: |
757 | + raise Exception("Unrecognised action in boot_cmds") |
758 | |
759 | |
760 | target_class = MasterImageTarget |
761 | @@ -530,6 +555,7 @@ |
762 | class MasterCommandRunner(NetworkCommandRunner): |
763 | """A CommandRunner to use when the board is booted into the master image. |
764 | """ |
765 | + http_pid = None |
766 | |
767 | def __init__(self, target): |
768 | super(MasterCommandRunner, self).__init__( |
769 | @@ -593,6 +619,26 @@ |
770 | return True |
771 | return False |
772 | |
773 | + def start_http_server(self): |
774 | + master_ip = self.get_master_ip() |
775 | + if self.http_pid != None: |
776 | + raise OperationFailed("busybox httpd already running with pid %" % self.http_pid) |
777 | + # busybox produces no output to parse for, so run it in the bg and get its pid |
778 | + self.run('busybox httpd -f &') |
779 | + self.run('echo pid:$!:pid',response="pid:(\d+):pid",timeout=10) |
780 | + if self.match_id != 0: |
781 | + raise OperationFailed("busybox httpd did not start") |
782 | + else: |
783 | + self.http_pid = self.match.group(1) |
784 | + url_base = "http://%s" % (master_ip) |
785 | + return url_base |
786 | + |
787 | + def stop_http_server(self): |
788 | + if self.http_pid != None: |
789 | + self.run('kill %s' % self.http_pid) |
790 | + self.http_pid = None |
791 | + |
792 | + |
793 | |
794 | def _extract_partition(image, partno, tarfile): |
795 | """Mount a partition and produce a tarball of it |
796 | |
797 | === modified file 'lava_dispatcher/device/qemu.py' |
798 | --- lava_dispatcher/device/qemu.py 2013-02-18 03:06:06 +0000 |
799 | +++ lava_dispatcher/device/qemu.py 2013-05-22 14:07:36 +0000 |
800 | @@ -45,12 +45,12 @@ |
801 | super(QEMUTarget, self).__init__(context, config) |
802 | self._sd_image = None |
803 | |
804 | - def deploy_linaro(self, hwpack=None, rootfs=None, bootloader='u_boot'): |
805 | + def deploy_linaro(self, hwpack=None, rootfs=None, bootloader='u_boot', bootcmds=None): |
806 | odir = self.scratch_dir |
807 | self._sd_image = generate_image(self, hwpack, rootfs, odir, bootloader) |
808 | self._customize_linux(self._sd_image) |
809 | |
810 | - def deploy_linaro_prebuilt(self, image): |
811 | + def deploy_linaro_prebuilt(self, image, bootcmds=None): |
812 | self._sd_image = download_image(image, self.context) |
813 | self._customize_linux(self._sd_image) |
814 | |
815 | |
816 | === modified file 'lava_dispatcher/device/sdmux.py' |
817 | --- lava_dispatcher/device/sdmux.py 2013-04-02 16:16:18 +0000 |
818 | +++ lava_dispatcher/device/sdmux.py 2013-05-22 14:07:36 +0000 |
819 | @@ -88,12 +88,12 @@ |
820 | if config.pre_connect_command: |
821 | self.context.run_command(config.pre_connect_command) |
822 | |
823 | - def deploy_linaro(self, hwpack=None, rootfs=None): |
824 | + def deploy_linaro(self, hwpack=None, rootfs=None, bootcmds=None): |
825 | img = generate_image(self, hwpack, rootfs, self.scratch_dir) |
826 | self._customize_linux(img) |
827 | self._write_image(img) |
828 | |
829 | - def deploy_linaro_prebuilt(self, image): |
830 | + def deploy_linaro_prebuilt(self, image, bootcmds=None): |
831 | img = download_image(image, self.context) |
832 | self._customize_linux(img) |
833 | self._write_image(img) |
834 | |
835 | === modified file 'lava_dispatcher/device/target.py' |
836 | --- lava_dispatcher/device/target.py 2013-04-19 08:40:29 +0000 |
837 | +++ lava_dispatcher/device/target.py 2013-05-22 14:07:36 +0000 |
838 | @@ -40,6 +40,8 @@ |
839 | |
840 | ANDROID_TESTER_PS1 = "root@linaro# " |
841 | |
842 | + _scratch_dir = None |
843 | + |
844 | # The target deployment functions will point self.deployment_data to |
845 | # the appropriate dictionary below. Code such as actions can contribute |
846 | # to these structures with special handling logic |
847 | @@ -85,13 +87,13 @@ |
848 | """ |
849 | raise NotImplementedError('power_on') |
850 | |
851 | - def deploy_linaro(self, hwpack, rfs): |
852 | + def deploy_linaro(self, hwpack, rfs, bootcmds=None): |
853 | raise NotImplementedError('deploy_image') |
854 | |
855 | - def deploy_android(self, boot, system, userdata): |
856 | + def deploy_android(self, boot, system, userdata, bootcmds=None): |
857 | raise NotImplementedError('deploy_android_image') |
858 | |
859 | - def deploy_linaro_prebuilt(self, image): |
860 | + def deploy_linaro_prebuilt(self, image, bootcmds=None): |
861 | raise NotImplementedError('deploy_linaro_prebuilt') |
862 | |
863 | def power_off(self, proc): |