Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 36 additions & 45 deletions test/case/infix_containers/container_environment/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,32 @@
Container environment variables

Verify that environment variables can be set in container configuration
and are available inside the running container. Tests the 'env' list
functionality by:
and are available inside the running container.

1. Creating a container with multiple environment variables
2. Using a custom script to extract env vars and serve them via HTTP
3. Fetching the served content to verify environment variables are set correctly

Uses the nftables container image with custom rc.local script.
1 Set up a container config with multiple environment variables
2. Serve variables back to host using a CGI script in container
3. Verify served content against environment variables
"""
import infamy
from infamy.util import until, to_binary


with infamy.Test() as test:
ENV_VARS = [
{"key": "TEST_VAR", "value": "hello-world"},
{"key": "APP_PORT", "value": "8080"},
{"key": "DEBUG_MODE", "value": "true"},
{"key": "PATH_WITH_SPACES", "value": "/path with spaces/test"}
]
NAME = "web-env"
DUTIP = "10.0.0.2"
OURIP = "10.0.0.1"
url = infamy.Furl(f"http://{DUTIP}:8080/cgi-bin/env.cgi")

with test.step("Set up topology and attach to target DUT"):
env = infamy.Env()
target = env.attach("target", "mgmt")
_, hport = env.ltop.xlate("host", "data")

if not target.has_model("infix-containers"):
test.skip()
Expand All @@ -44,44 +49,33 @@
}
})

with test.step("Create container with environment variables"):
script = to_binary("""#!/bin/sh
# Create HTTP response with environment variables
printf "HTTP/1.1 200 OK\\r\\n" > /var/www/response.txt
printf "Content-Type: text/plain\\r\\n" >> /var/www/response.txt
printf "Connection: close\\r\\n\\r\\n" >> /var/www/response.txt

# Add environment variables using printf to control encoding
printf "TEST_VAR=\\"%s\\"\\n" "$TEST_VAR" >> /var/www/response.txt
printf "APP_PORT=%s\\n" "$APP_PORT" >> /var/www/response.txt
printf "DEBUG_MODE=\\"%s\\"\\n" "$DEBUG_MODE" >> /var/www/response.txt
printf "PATH_WITH_SPACES=\\"%s\\"\\n" "$PATH_WITH_SPACES" >> /var/www/response.txt
with test.step("Set up container with environment variables"):
cgi = [
'#!/bin/sh',
'# CGI script to output environment variables',
'echo "Content-Type: text/plain"',
'echo ""'
]

while true; do
nc -l -p 8080 < /var/www/response.txt 2>>/var/www/debug.log || sleep 1
done
""")
for var in ENV_VARS:
cgi.append(f'echo "{var["key"]}=${var["key"]}"')

target.put_config_dict("infix-containers", {
"containers": {
"container": [
{
"name": f"{NAME}",
"image": f"oci-archive:{infamy.Container.NFTABLES_IMAGE}",
"env": [
{"key": "TEST_VAR", "value": "hello-world"},
{"key": "APP_PORT", "value": "8080"},
{"key": "DEBUG_MODE", "value": "true"},
{"key": "PATH_WITH_SPACES", "value": "/path with spaces/test"}
],
"image": f"oci-archive:{infamy.Container.HTTPD_IMAGE}",
"command": "/usr/sbin/httpd -f -v -p 8080",
"env": ENV_VARS,
"network": {
"host": True
},
"mount": [
{
"name": "rc.local",
"content": script,
"target": "/etc/rc.local",
"name": "env.cgi",
"content": to_binary('\n'.join(cgi) + '\n'),
"target": "/var/www/cgi-bin/env.cgi",
"mode": "0755"
}
],
Expand All @@ -98,20 +92,17 @@
c = infamy.Container(target)
until(lambda: c.running(NAME), attempts=60)

with test.step("Verify environment variables are available via HTTP"):
_, hport = env.ltop.xlate("host", "data")
url = infamy.Furl(f"http://{DUTIP}:8080/env.html")
with infamy.IsolatedMacVlan(hport) as ns:
ns.addip(OURIP)

with infamy.IsolatedMacVlan(hport) as ns:
ns.addip(OURIP)
with test.step("Verify basic connectivity to data interface"):
ns.must_reach(DUTIP)

with test.step("Verify basic connectivity to data interface"):
ns.must_reach(DUTIP)
with test.step("Verify environment variables in CGI response"):
expected_strings = []
for var in ENV_VARS:
expected_strings.append(f'{var["key"]}={var["value"]}')

with test.step("Verify environment variables in HTTP response"):
until(lambda: url.nscheck(ns, "TEST_VAR=\"hello-world\""), attempts=10)
until(lambda: url.nscheck(ns, "APP_PORT=8080"), attempts=10)
until(lambda: url.nscheck(ns, "DEBUG_MODE=\"true\""), attempts=10)
until(lambda: url.nscheck(ns, "PATH_WITH_SPACES=\"/path with spaces/test\""), attempts=10)
until(lambda: url.nscheck(ns, expected_strings))

test.succeed()
5 changes: 2 additions & 3 deletions test/case/infix_containers/infix_containers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@
- name: container_enabled
case: container_enabled/test.py

# Disabled for v25.08, new/unstable
# - name: container_environment
# case: container_environment/test.py
- name: container_environment
case: container_environment/test.py

- name: container_bridge
case: container_bridge/test.py
Expand Down
5 changes: 2 additions & 3 deletions test/case/infix_services/mdns/mdns.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@
- name: mdns_enable_disable
case: mdns_enable_disable/test.py

# Disabled for v25.08, unstable
# - name: mdns_allow_deny
# case: mdns_allow_deny/test.py
- name: mdns_allow_deny
case: mdns_allow_deny/test.py
173 changes: 77 additions & 96 deletions test/case/infix_services/mdns/mdns_allow_deny/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,37 @@


def mdns_scan(tgt):
"""Trigger Avahi to send traffic on allowed interfaces"""
time.sleep(2)
"""Trigger mDNS scan with initial delay for listener setup"""
time.sleep(1) # Give listeners time to start
tgt.runsh("logger -t scan 'calling avahi-browse ...'")
tgt.runsh("avahi-browse -lat")


def check(ns, expr, must):
"""Wrap netns.must_receive() with common defaults"""
return ns.must_receive(expr, timeout=3, must=must)
def mdns_recv(ns, expr, must):
"""Check for mDNS traffic with proper timing"""
return ns.must_receive(expr, timeout=6, must=must)


def check(dut, ssh, listeners_config, allow=None, deny=None):
"""Execute complete mDNS test scenario with proper sequencing"""
dut.delete_xpath("/infix-services:mdns/interfaces")

mdns_config = {"mdns": {"interfaces": {}}}
if allow:
mdns_config["mdns"]["interfaces"]["allow"] = allow
if deny:
mdns_config["mdns"]["interfaces"]["deny"] = deny

dut.put_config_dict("infix-services", mdns_config)

# Create parallel tasks for traffic generation and listening
tasks = [lambda: mdns_scan(ssh)]
for ns, expr, should_receive in zip(*listeners_config):
tasks.append(lambda ns=ns, expr=expr, should_receive=should_receive:
mdns_recv(ns, expr, should_receive))

# Execute all tasks in parallel with proper timing
parallel(*tasks)


with infamy.Test() as test:
Expand All @@ -45,116 +67,75 @@ def check(ns, expr, must):
{
"ietf-interfaces": {
"interfaces": {
"interface": [
{
"name": p1,
"enabled": True,
"ipv4": {
"address": [
{
"ip": "10.0.1.1",
"prefix-length": 24
}
]
}

},
{
"name": p2,
"enabled": True,
"ipv4": {
"address": [
{
"ip": "10.0.2.1",
"prefix-length": 24
}
]
}

},
{
"name": p3,
"enabled": True,
"ipv4": {
"address": [
{
"ip": "10.0.3.1",
"prefix-length": 24
}
]
}

},
]
}
"interface": [{
"name": p1,
"enabled": True,
"ipv4": {
"address": [{
"ip": "10.0.1.1",
"prefix-length": 24
}]
}
}, {
"name": p2,
"enabled": True,
"ipv4": {
"address": [{
"ip": "10.0.2.1",
"prefix-length": 24
}]
}
}, {
"name": p3,
"enabled": True,
"ipv4": {
"address": [{
"ip": "10.0.3.1",
"prefix-length": 24
}]
}
}]
}
},
"ietf-system": {
"system": {
"hostname": "dut"
}
"system": {"hostname": "dut"}
},
"infix-services": {
"mdns": {
"enabled": True
}
"mdns": {"enabled": True}
}
}
)

with infamy.IsolatedMacVlan(eth1) as ns1, \
infamy.IsolatedMacVlan(eth2) as ns2, \
infamy.IsolatedMacVlan(eth3) as ns3:
expressions = [
"host 10.0.1.1 and port 5353",
"host 10.0.2.1 and port 5353",
"host 10.0.3.1 and port 5353"
]
namespaces = [ns1, ns2, ns3]

ns1.addip("10.0.1.2")
ns2.addip("10.0.2.2")
ns3.addip("10.0.3.2")

EXPR1 = "host 10.0.1.1 and port 5353"
EXPR2 = "host 10.0.2.1 and port 5353"
EXPR3 = "host 10.0.3.1 and port 5353"

with test.step("Allow mDNS on a single interface: p2"):
dut.put_config_dict("infix-services", {
"mdns": {
"interfaces": {
"allow": [p2],
}
}
})

parallel(lambda: mdns_scan(ssh),
lambda: check(ns1, EXPR1, False),
lambda: check(ns2, EXPR2, True),
lambda: check(ns3, EXPR3, False))
# p1:no, p2:yes, p3:no
expect = [False, True, False]
config = (namespaces, expressions, expect)
check(dut, ssh, config, allow=[p2])

with test.step("Deny mDNS on a single interface: p2"):
dut.delete_xpath("/infix-services:mdns/interfaces")
dut.put_config_dict("infix-services", {
"mdns": {
"interfaces": {
"deny": [p2],
}
}
})

parallel(lambda: mdns_scan(ssh),
lambda: check(ns1, EXPR1, True),
lambda: check(ns2, EXPR2, False),
lambda: check(ns3, EXPR3, True))
# p1:yes, p2:no, p3:yes
expect = [True, False, True]
config = (namespaces, expressions, expect)
check(dut, ssh, config, deny=[p2])

with test.step("Allow mDNS on p1, p3 deny on p2, p3"):
dut.delete_xpath("/infix-services:mdns/interfaces")
dut.put_config_dict("infix-services", {
"mdns": {
"interfaces": {
"allow": [p1, p3],
"deny": [p2, p3],
}
}
})

parallel(lambda: mdns_scan(ssh),
lambda: check(ns1, EXPR1, True),
lambda: check(ns2, EXPR2, False),
lambda: check(ns3, EXPR3, False))
# p1:yes, p2:no, p3:no (deny overrides allow)
expect = [True, False, False]
config = (namespaces, expressions, expect)
check(dut, ssh, config, allow=[p1, p3], deny=[p2, p3])

test.succeed()
Loading
Loading