diff --git a/imgs/base-alpine/bin/wait4network b/imgs/base-alpine/bin/wait4network index f59c447141367a54339890b46d321e399561bbf8..d4fd2d8d45e53a13b41443ea9b53062e326796e5 100755 --- a/imgs/base-alpine/bin/wait4network +++ b/imgs/base-alpine/bin/wait4network @@ -1,8 +1,8 @@ #!/bin/sh # This file is part of NSFarm -# Call this script to block execution untill there is internet connection. +# Call this script to block execution untill there is default route present. echo waiting for network -while ! ping -c 1 nic.cz >/dev/null 2>&1; do +while ! ip route | grep -q default; do sleep 1 done diff --git a/nsfarm/board/_board.py b/nsfarm/board/_board.py index f3375b39277448ed493fa5e492e5e9b56393fedb..b4c9befa2a9ccc8ca25e93289de9ce6421130799 100644 --- a/nsfarm/board/_board.py +++ b/nsfarm/board/_board.py @@ -79,8 +79,9 @@ class Board: # Wait for bootup self._pexpect.expect_exact(["Router Turris successfully started.", ], timeout=120) # Note Shell sends new line which opens terminal for it - # TODO why this flush timeouts? - return cli.Shell(self._pexpect, flush=False) + shell = cli.Shell(self._pexpect, flush=False) # TODO why this flush timeouts? + shell.run("sysctl -w kernel.printk='0 4 1 7'") # disable kernel print to not confuse console flow + return shell def _board_bootup(self, uboot): """Board specific bootup routine. diff --git a/nsfarm/cli.py b/nsfarm/cli.py index 80534a985d48b1d08269ec11a7ac570adc992309..c1fdc30d5d92c4f5bf347ec364cfbd54a66ac672 100644 --- a/nsfarm/cli.py +++ b/nsfarm/cli.py @@ -10,6 +10,7 @@ import base64 def pexpect_flush(pexpect_handle): """Flush all input on pexpect. This effectively reads everything. """ + # TODO fix: this timeouts if there is nothing to flush bufflen = 2048 while len(pexpect_handle.read_nonblocking(bufflen)) == bufflen: pass @@ -95,6 +96,7 @@ class Shell(Cli): r"(\r\n|\n\r|^).+? ($|#) ", r"(\r\n|\n\r|^)bash-.+?($|#) ", r"(\r\n|\n\r|^)root@[a-zA-Z0-9_-]*:", + r"(\r\n|\n\r|^).*root@turris.*#", # TODO this is weird dual prompt from lxd ssh _NSF_PROMPT, ] # TODO compile prompt regexp to increase performance diff --git a/tests/conftest.py b/tests/conftest.py index b68e35078d2924c1308003c9959275472b775b1c..54778378320402ee286bf5d48bdce62849895470 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,6 @@ +import time +import random +import string import pytest import nsfarm.board import nsfarm.cli @@ -34,8 +37,8 @@ def fixture_lan1(request): ######################################################################################################################## ## Boot and setup fixtures ############################################################################################# -@pytest.fixture(scope="session") -def board_shell(request, board, wan): +@pytest.fixture(name="board_serial", scope="session") +def fixture_board_serial(request, board, wan): """Boot board to Shell. Provides instance of nsfarm.cli.Shell() """ @@ -43,11 +46,61 @@ def board_shell(request, board, wan): return board.bootup(wan) +@pytest.fixture(name="board_root_password", scope="session") +def fixture_board_root_password(request, board_serial): + """Sets random password for user root. + Returns configured random password + """ + password = ''.join(random.choice(string.ascii_lowercase) for i in range(16)) + board_serial.run("echo 'root:{}' | chpasswd".format(password)) + request.addfinalizer(lambda: board_serial.run("passwd --delete root")) + return password + + +@pytest.fixture(name="client_board", scope="session") +def fixture_client_board(board, board_serial, board_root_password, lan1): + """Starts client on LAN1 and connect to board using SSH. + Provides instance of nsfarm.cli.Shell() connected to board shell using SSH trough client container. + """ + # Let's have syslog on serial console as well as kernel log + board_serial.command('tail -f /var/log/messages') + # Now spawn client container and connect + with nsfarm.lxd.Container('client', devices=[lan1, ], internet=False) as container: + nsfarm.cli.Shell(container.pexpect()).run('wait4network') + pexp = container.pexpect(['ssh', '192.168.1.1']) + pexp.expect_exact("root@192.168.1.1's password:") + pexp.sendline(board_root_password) + pexp.expect_exact("root@turris:") + yield nsfarm.cli.Shell(pexp, flush=False) # TODO drop this flush disable when it works + # Kill tail -f on serial console + board_serial.send('\x03') + board_serial.prompt() + + ######################################################################################################################## ## Standard configuration ############################################################################################## @pytest.fixture(scope="session") -def basic_config(board_shell, wan, lan1): - """Basic config we consider general. It provides you with configured WAN and one LAN client. +def basic_config(client_board, wan): + """Basic config we consider general. It provides you with configured WAN. + + Returns handle for ISP container on WAN interface. """ - raise NotImplementedError + # TODO what about other settings that are part of guide + with nsfarm.lxd.Container('isp-common', devices=[wan, ]) as container: + client_board.run("uci set network.wan.proto='static'") + client_board.run("uci set network.wan.ipaddr='172.16.1.42'") + client_board.run("uci set network.wan.netmask='255.240.0.0'") + client_board.run("uci set network.wan.gateway='172.16.1.1'") + client_board.run("uci set network.wan.dns='1.1.1.1'") # TODO configure to ISP + client_board.run("uci commit network") + client_board.run("/etc/init.d/network restart") + client_board.run("while ! ip route | grep -q default; do sleep 1; done") # Wait for default route + # TODO this does not ensure that we ping gateway but why? + yield container + client_board.run("uci set network.wan.proto='none'") + client_board.run("uci delete network.wan.ipaddr") + client_board.run("uci delete network.wan.netmask") + client_board.run("uci delete network.wan.gateway") + client_board.run("uci delete network.wan.dns") + client_board.run("uci commit network") diff --git a/tests/network/common.py b/tests/network/common.py index 0f7ce8e7dcdb6df006e29f19c5f0114406a3eb71..bca8fae6e1bb80257818146752469a52066c16d5 100644 --- a/tests/network/common.py +++ b/tests/network/common.py @@ -17,21 +17,21 @@ class InternetTests: "turris.cz", "google.com" ]) - def test_ping(self, board_shell, server): + def test_ping(self, client_board, server): """Ping various IPv4 servers. We send only one ICMP packet to not flood and to be quickly done with it (the success takes less than second) """ - board_shell.run("ping -c 1 '{}'".format(server)) + client_board.run("ping -c 1 '{}'".format(server)) @pytest.mark.parametrize("server", [ "nic.cz", "turris.cz", "google.com" ]) - def test_dns(self, board_shell, server): + def test_dns(self, client_board, server): """Try to resolve verious domain names. """ - board_shell.run("nslookup '{}'".format(server)) + client_board.run("nslookup '{}'".format(server)) # TODO more excessive DNS testing diff --git a/tests/network/test_wan.py b/tests/network/test_wan.py index 72c63d6675fd4e7fe77506267ecb7441a5b89dd9..da09fb660fdf2ef97ececa7c6602664a644104a4 100644 --- a/tests/network/test_wan.py +++ b/tests/network/test_wan.py @@ -11,11 +11,10 @@ from . import common # TODO: add support for IPV6, currently we only test IPv4 -def _apply(board_shell): - board_shell.run("uci commit network") - board_shell.run("/etc/init.d/network restart") - time.sleep(5) # TODO drop this as this is just to prevent problems with kernel log in console - board_shell.run("while ! ip route | grep -q default; do sleep 1; done") # Wait for default route +def _apply(client_board): + client_board.run("uci commit network") + client_board.run("/etc/init.d/network restart") + client_board.run("while ! ip route | grep -q default; do sleep 1; done") # Wait for default route class TestStatic(common.InternetTests): @@ -23,24 +22,24 @@ class TestStatic(common.InternetTests): """ @pytest.fixture(scope="class", autouse=True) - def configure(self, board_shell, wan): + def configure(self, client_board, wan): """Configure WAN to use static IP """ with nsfarm.lxd.Container('isp-common', devices=[wan, ]) as container: # TODO implement some utility class to set and revert uci configs on router - board_shell.run("uci set network.wan.proto='static'") - board_shell.run("uci set network.wan.ipaddr='172.16.1.42'") - board_shell.run("uci set network.wan.netmask='255.240.0.0'") - board_shell.run("uci set network.wan.gateway='172.16.1.1'") - board_shell.run("uci set network.wan.dns='1.1.1.1'") # TODO configure to ISP - _apply(board_shell) + client_board.run("uci set network.wan.proto='static'") + client_board.run("uci set network.wan.ipaddr='172.16.1.42'") + client_board.run("uci set network.wan.netmask='255.240.0.0'") + client_board.run("uci set network.wan.gateway='172.16.1.1'") + client_board.run("uci set network.wan.dns='1.1.1.1'") # TODO configure to ISP + _apply(client_board) yield container - board_shell.run("uci set network.wan.proto='none'") - board_shell.run("uci delete network.wan.ipaddr") - board_shell.run("uci delete network.wan.netmask") - board_shell.run("uci delete network.wan.gateway") - board_shell.run("uci delete network.wan.dns") - board_shell.run("uci commit network") + client_board.run("uci set network.wan.proto='none'") + client_board.run("uci delete network.wan.ipaddr") + client_board.run("uci delete network.wan.netmask") + client_board.run("uci delete network.wan.gateway") + client_board.run("uci delete network.wan.dns") + client_board.run("uci commit network") class TestDHCP(common.InternetTests): @@ -48,13 +47,13 @@ class TestDHCP(common.InternetTests): """ @pytest.fixture(scope="class", autouse=True) - def configure(self, board, board_shell, wan): + def configure(self, board, client_board, wan): """Configure WAN to use DHCP """ with nsfarm.lxd.Container('isp-dhcp', devices=[wan, ]) as container: - board_shell.run("uci set network.wan.proto='dhcp'") - board_shell.run("uci commit network") - _apply(board_shell) + client_board.run("uci set network.wan.proto='dhcp'") + client_board.run("uci commit network") + _apply(client_board) yield container - board_shell.run("uci set network.wan.proto='none'") - board_shell.run("uci commit network") + client_board.run("uci set network.wan.proto='none'") + client_board.run("uci commit network")