diff --git a/test/case/infix_containers/Readme.adoc b/test/case/infix_containers/Readme.adoc index f17fe3528..a530a6e67 100644 --- a/test/case/infix_containers/Readme.adoc +++ b/test/case/infix_containers/Readme.adoc @@ -23,3 +23,5 @@ include::container_veth/Readme.adoc[] include::container_volume/Readme.adoc[] include::container_firewall_basic/Readme.adoc[] + +include::container_host_commands/Readme.adoc[] diff --git a/test/case/infix_containers/container_host_commands/test.py b/test/case/infix_containers/container_host_commands/test.py new file mode 100755 index 000000000..c7ee45df4 --- /dev/null +++ b/test/case/infix_containers/container_host_commands/test.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +r"""Host Command Execution from Container + +This test verifies that a container running on Infix can execute commands +that affect the host system. Specifically, it confirms that the container +can change the hostname of the host. +""" + +import infamy +from infamy.util import until, to_binary + +with infamy.Test() as test: + cont_image = f"oci-archive:{infamy.Container.NFTABLES_IMAGE}" + cont_name = "cont0" + hostname_init = "container-host" + hostname_new = "coffee" + + with test.step("Set up topology and attach to target DUT"): + env = infamy.Env() + target = env.attach("target", "mgmt") + + if not target.has_model("infix-containers"): + test.skip() + + with test.step("Set initial hostname"): + target.put_config_dict("ietf-system", { + "system": { + "hostname": hostname_init + } + }) + + with test.step("Verify initial hostname in operational"): + oper = target.get_data("/ietf-system:system") + name = oper["system"]["hostname"] + + if name != hostname_init: + print(f"Expected hostname: {hostname_init}, actual hostname: {name}") + test.fail() + + with test.step("Include script in OCI image to modify host hostname"): + commands = to_binary(f"""#!/bin/sh +nsenter -m/1/ns/mnt -u/1/ns/uts -i/1/ns/ipc -n/1/ns/net hostname {hostname_new} +""") + + target.put_config_dict("infix-containers", { + "containers": { + "container": [ + { + "name": cont_name, + "image": cont_image, + "network": { + "host": True + }, + "mount": [ + { + "name": "rc.local", + "content": commands, + "target": "/etc/rc.local", + "mode": "0755" + }, + { + "name": "proc1ns", + "source": "/proc/1/ns", + "target": "/1/ns", + } + ], + "privileged": True + } + ] + } + }) + + with test.step("Verify container has started"): + c = infamy.Container(target) + until(lambda: c.running(cont_name), attempts=10) + + with test.step("Verify the new hostname set by the container"): + oper = target.get_data("/ietf-system:system") + name = oper["system"]["hostname"] + + if name != hostname_new: + print(f"Expected hostname: {hostname_new}, actual hostname: {name}") + test.fail() + + test.succeed() diff --git a/test/case/infix_containers/container_host_commands/topology.dot b/test/case/infix_containers/container_host_commands/topology.dot new file mode 120000 index 000000000..02b788692 --- /dev/null +++ b/test/case/infix_containers/container_host_commands/topology.dot @@ -0,0 +1 @@ +../../../infamy/topologies/1x1.dot \ No newline at end of file diff --git a/test/case/infix_containers/infix_containers.yaml b/test/case/infix_containers/infix_containers.yaml index 40e51a319..484663e8e 100644 --- a/test/case/infix_containers/infix_containers.yaml +++ b/test/case/infix_containers/infix_containers.yaml @@ -18,3 +18,6 @@ - name: container_firewall_basic case: container_firewall_basic/test.py +- name: container_host_commands + case: container_host_commands/test.py +