diff --git a/imgs/boot.sh b/imgs/boot.sh index f1a1adcfcc89c609fb8780124d1a42cac71a5f3f..0b6c909cc58f5adf2aff85fff73af4a5fa7336a4 100755 --- a/imgs/boot.sh +++ b/imgs/boot.sh @@ -4,3 +4,22 @@ # This is image used to boot medkit. It provides TFTP server with prepared image # for u-boot. ################################################################################## +set -e + +# Make prepare script executable so we can later run it +chmod +x "/bin/prepare_turris_image" + +# Configure WAN interface for static local network +cat >> /etc/network/interfaces <<EOF +auto wan +iface wan inet static + address 192.168.1.1 + netmask 255.255.255.0 +EOF + +# Install utilities we need to repack image +apk add uboot-tools + +# Install and enable TFTP server +apk add tftp-hpa +rc-update add "in.tftpd" default diff --git a/imgs/boot/bin/prepare_turris_image b/imgs/boot/bin/prepare_turris_image new file mode 100755 index 0000000000000000000000000000000000000000..a5e8d6eb81f83f3f1df87b18fdfb6ae59bd4a48a --- /dev/null +++ b/imgs/boot/bin/prepare_turris_image @@ -0,0 +1,27 @@ +#!/bin/bash +set -e +TFTP_ROOT="/var/tftpboot" + +# TODO use this +BOARD="$1" +MODE="$2" +TARGET="$3" +# TODO + +# Get appropriate medkit +wait4network +wget "https://repo.turris.cz/hbk/medkit/omnia-medkit-latest.tar.gz" -O medkit.tar.gz + +# Repack as CPIO +mkdir root +tar -xzf medkit.tar.gz -C root +( cd root && find . | cpio -H newc -o > ../root.cpio ) +mkimage -A arm -O linux -T ramdisk -C none -d root.cpio root.uimage + +# Prepare to TFTP +cp root/boot/zImage "$TFTP_ROOT/zImage" +cp -L root/boot/dtb "$TFTP_ROOT/dtb" +mv root.uimage "$TFTP_ROOT/root.uimage" + +# Clean after ourself +rm -rf root root.cpio medkit.tar.gz diff --git a/nsfarm/board.py b/nsfarm/board.py index 4f5d09ddecd2402c46918a2ea0f111398bd640f4..49e0c939f2fb60659e6eaa82e003528d67065f60 100644 --- a/nsfarm/board.py +++ b/nsfarm/board.py @@ -7,6 +7,7 @@ import serial import serial.tools.miniterm from pexpect import fdpexpect from . import cli +from .lxd import Container MINITERM_DEFAULT_EXIT = '\x1d' # Ctrl+] MINITERM_DEFAULT_MENU = '\x14' # Ctrl+T @@ -50,15 +51,28 @@ class Board(): self.pexpect.sendline("") return cli.Uboot(self.pexpect) - def bootup(self): + def bootup(self, device_wan): """Boot board using TFTP boot. This ensures that board is booted up and ready to accept commands. + device_wan: Wan device to board. This is instance of nsfarm.lxd.NetInterface. + Returns instance of cli.Shell """ # First get U-Boot prompt uboot = self.uboot() - # Now load FIT image from TFTP - # TODO + # Now load image from TFTP + with Container("boot", devices=[device_wan, ]) as cont: + ccli = cli.Shell(cont.pexpect()) + ccli.run("prepare_turris_image") + assert uboot.batch([ + 'setenv ipaddr 192.168.1.142', + 'setenv serverip 192.168.1.1', + 'tftpboot 0x01000000 192.168.1.1:zImage', + 'tftpboot 0x02000000 192.168.1.1:dtb', + 'tftpboot 0x03000000 192.168.1.1:root.uimage', + 'setenv bootargs "earlyprintk console=ttyS0,115200 rootfstype=ramfs initrd=0x03000000"', + ], timeout=120) + self.pexpect.sendline('bootz 0x01000000 0x03000000 0x02000000') # Wait for bootup self.pexpect.expect_exact(["Router Turris successfully started.", ]) # Note Shell sends new line which opens terminal for it diff --git a/nsfarm/cli.py b/nsfarm/cli.py index 3017c2917724dd6c556f2fcc5d379e539bf8741d..6e95b41867e3bf603ea8d768d0f2e0adf42ba2b6 100644 --- a/nsfarm/cli.py +++ b/nsfarm/cli.py @@ -68,7 +68,7 @@ class Console: command from output. """ self.sendline(cmd) - if not self.sexpect_exact(cmd + '\r\n'): + if not self.sexpect_exact(cmd) or not self.sexpect("(\r\n|\n\r)"): # TODO better exception raise Exception("cmd used but terminal probably does not echoes.") @@ -129,11 +129,11 @@ class Shell(Cli): This is tested to handle busybox and bash. """ _SET_NSF_PROMPT = r"export PS1='nsfprompt:$(echo -n $?)\$ '" - _NSF_PROMPT = r"(\r\n|^)nsfprompt:([0-9]+)($|#) " + _NSF_PROMPT = r"(\r\n|\n\r|^)nsfprompt:([0-9]+)($|#) " _INITIAL_PROMPTS = [ - r"(\r\n|^).+? ($|#) ", - r"(\r\n|^)bash-.+?($|#) ", - r"(\r\n|^)root@[a-zA-Z0-9_-]*:", + r"(\r\n|\n\r|^).+? ($|#) ", + r"(\r\n|\n\r|^)bash-.+?($|#) ", + r"(\r\n|\n\r|^)root@[a-zA-Z0-9_-]*:", _NSF_PROMPT, ] # TODO compile prompt regexp to increase performance @@ -143,7 +143,6 @@ class Shell(Cli): # Firt check if we are on some sort of shell prompt self.cmd() if not self.sexpect(self._INITIAL_PROMPTS): - print(self.before) # TODO better exception raise Exception("Initial shell prompt not found") # Now sanitize prompt format @@ -164,7 +163,7 @@ class Shell(Cli): class Uboot(Cli): """U-boot prompt support class. """ - _PROMPT = "(\r\n|^)=> " + _PROMPT = "(\r\n|\n\r|^)=> " _EXIT_CODE_ECHO = "echo $?" def __init__(self, pexpect_handle, flush=True): @@ -190,3 +189,9 @@ class Uboot(Cli): @property def output(self): return self._output + + +# Notest on some of the hacks in this file +# +# There are new line character matches in regular expressions. Correct one is \r\n but some serial controlles for some +# reason also use \n\r so we match both alternatives. diff --git a/nsfarm/lxd/container.py b/nsfarm/lxd/container.py index 519a2a0578b11bc5c441dea0e0d58ceaadd296ef..535c5255ece1e602236dcccfd4adb2c73d588cfd 100644 --- a/nsfarm/lxd/container.py +++ b/nsfarm/lxd/container.py @@ -203,6 +203,7 @@ class Container(): def pexpect(self, shell="/bin/sh"): """Returns pexpect handle for shell in container. """ + # TODO some logging of this session assert self._lxd_container is not None return pexpect.spawn('lxc', ["exec", self._lxd_container.name, shell]) @@ -247,16 +248,8 @@ class Container(): """ return self._hash + @property def image_alias(self): """Alias of image for this container. """ return self._image_alias - - -class BootContainer(Container): - """Extension for Container handling specific tasks for container used to boot medkit on board. - """ - - # TODO branch or build to pull? - def __init__(self, *args, **kwargs): - super().__init__("boot", *args, **kwargs) diff --git a/tests/conftest.py b/tests/conftest.py index 53b6a17e392ccca70e16474d605225ebc551bfd9..e04bc6308558d2620749a7441f9cee4be878670a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,7 @@ import pytest import nsfarm.board import nsfarm.cli +import nsfarm.lxd @pytest.fixture(scope="session", name="board", params=[pytest.param(None, marks=pytest.mark.serial)]) @@ -23,11 +24,17 @@ def board_uboot(request, board): return board.uboot() +@pytest.fixture(scope="session", name="wan", params=[pytest.param(None, marks=pytest.mark.wan)]) +def fixture_wan(request): + """Top level fixture used to share WAN interface handler. + """ + return nsfarm.lxd.NetInterface("wan", request.config.target_config['wan']) + + @pytest.fixture(scope="session") -def board_shell(request, board): +def board_shell(request, board, wan): """Boot board to Shell. Provides instance of nsfarm.cli.Shell() """ request.addfinalizer(lambda: board.reset(True)) - # TODO prepare wan container with appropriate medkit - return board.bootup() + return board.bootup(wan) diff --git a/tests/test_experiments.py b/tests/test_experiments.py index e8ad30c636cde7924876bce34f5e1c3b9a2285bb..27b137ecf859b7c765bad8d8856afa01d8016217 100644 --- a/tests/test_experiments.py +++ b/tests/test_experiments.py @@ -1,11 +1,11 @@ import pytest -def no_test_help(board, board_uboot): +def test_terminal(board, board_shell): board.serial_miniterm() -def test_cpu_env(board, board_uboot): +def no_test_cpu_env(board, board_uboot): assert board_uboot.run("printenv cpu") assert board_uboot.output == "cpu=armv7"