Merge pull request #1184 from kernelkit/releng

Release prep for v25.08.1
This commit is contained in:
Joachim Wiberg
2025-10-03 16:22:07 +02:00
committed by GitHub
14 changed files with 286 additions and 149 deletions
+4 -9
View File
@@ -39,7 +39,7 @@ env:
jobs:
test:
name: Regression Test ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.name || inputs.name }} ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.target || inputs.target }}
runs-on: [ self-hosted, regression ]
runs-on: [self-hosted, regression]
steps:
- name: Checkout infix repo
uses: actions/checkout@v4
@@ -87,7 +87,7 @@ jobs:
fi
make test
- name: Publish Test Result for ${{ env.TARGET }}
- name: Publish Test Result for ${{ env.TARGET }}
# Ensure this runs even if Regression Test fails
if: always()
run: cat $TEST_PATH/.log/last/result-gh.md >> $GITHUB_STEP_SUMMARY
@@ -96,15 +96,10 @@ jobs:
# Ensure this runs even if Regression Test fails
if: always()
run: |
asciidoctor-pdf \
--theme $TEST_PATH/9pm/report/theme.yml \
-a pdf-fontsdir=$TEST_PATH/9pm/report/fonts \
$TEST_PATH/.log/last/report.adoc \
-o $TEST_PATH/.log/last/report.pdf
make test-dir="$(pwd)/$TEST_PATH" test-report
- name: Upload Test Report as Artifact
uses: actions/upload-artifact@v4
with:
name: test-report
path: ${{ env.TEST_PATH }}/.log/last/report.pdf
path: output/images/test-report.pdf
+1 -1
View File
@@ -37,6 +37,6 @@ jobs:
name: "infix"
test-publish-x86_64:
if: startsWith(github.repository, 'kernelkit/')
if: ${{ github.repository_owner == 'kernelkit' && github.ref_name == 'main' }}
needs: test-run-x86_64
uses: ./.github/workflows/publish.yml
+2 -2
View File
@@ -83,7 +83,7 @@ genboot()
{
if [ -d "$bootdata" ]; then
bootimg=$(cat <<EOF
image efi-part.vfat {
image $BINARIES_DIR/efi-part.vfat {
size = $bootsize
vfat {
file EFI {
@@ -98,7 +98,7 @@ EOF
offset = $bootoffs
partition-type-uuid = U
bootable = true
image = efi-part.vfat
image = $BINARIES_DIR/efi-part.vfat
}
EOF
)
+3 -3
View File
@@ -3,7 +3,7 @@ Change Log
All notable changes to the project are documented in this file.
[v25.08.1][] - 2025-09-30
[v25.08.1][] - 2025-10-03
-------------------------
### Changes
@@ -12,8 +12,8 @@ All notable changes to the project are documented in this file.
### Fixes
- Fix #1150: `show-legacy` wrapper permissions
- Fix #1155: `show ospf` commands regression
- Fix #1169: Expected neighbors not shown in sysrepocfg
- Various test stability improvments
- Fix #1169: Expected OSPF neighbors not shown in `sysrepocfg` when the
system has at least one non-OSPF interface
[v25.08.0][] - 2025-09-01
-------------------------
@@ -1,7 +1,13 @@
=== OSPF Basic
==== Description
Very basic OSPF test just test that OSPF sends HELLO packets between the DUTs
and that they exchange routes, ending with a simple connectivity check.
Verifies basic OSPF functionality by configuring two routers (R1 and R2)
with OSPF on their interconnecting link. The test ensures OSPF
neighbors are established, routes are exchanged between the routers, and
end-to-end connectivity is achieved.
An end-device (HOST) is connected to R2 on an interface without OSPF enabled.
This verifies that OSPF status information remains accessible when a router
has non-OSPF interfaces.
==== Topology
ifdef::topdoc[]
@@ -19,6 +25,7 @@ endif::topdoc[]
. Set up topology and attach to target DUTs
. Configure targets
. Wait for OSPF routes
. Verify R2 OSPF neighbors with non-OSPF interface
. Test connectivity from PC:data to 192.168.200.1
+105 -63
View File
@@ -1,15 +1,24 @@
#!/usr/bin/env python3
"""
OSPF Basic
"""OSPF Basic
Verifies basic OSPF functionality by configuring two routers (R1 and R2)
with OSPF on their interconnecting link. The test ensures OSPF
neighbors are established, routes are exchanged between the routers, and
end-to-end connectivity is achieved.
An end-device (HOST) is connected to R2 on an interface without OSPF enabled.
This verifies that OSPF status information remains accessible when a router
has non-OSPF interfaces.
Very basic OSPF test just test that OSPF sends HELLO packets between the DUTs
and that they exchange routes, ending with a simple connectivity check.
"""
# TODO: Remove HOST node once Infamy supports unconnected ports in topologies
import infamy
import infamy.route as route
from infamy.util import until, parallel
def config_target1(target, data, link):
target.put_config_dict("ietf-interfaces", {
"interfaces": {
@@ -30,8 +39,8 @@ def config_target1(target, data, link):
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.50.1",
"prefix-length": 24
"ip": "192.168.50.1",
"prefix-length": 24
}]
}
},
@@ -40,8 +49,8 @@ def config_target1(target, data, link):
"enabled": True,
"ipv4": {
"address": [{
"ip": "192.168.100.1",
"prefix-length": 32
"ip": "192.168.100.1",
"prefix-length": 32
}]
}
}
@@ -56,38 +65,34 @@ def config_target1(target, data, link):
target.put_config_dict("ietf-routing", {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [
{
"type": "infix-routing:static",
"name": "default",
"static-routes": {
"ipv4": {
"route": [{
"destination-prefix": "192.168.33.1/32",
"next-hop": {
"special-next-hop": "blackhole"
}
}]
}
"control-plane-protocol": [{
"type": "infix-routing:static",
"name": "default",
"static-routes": {
"ipv4": {
"route": [{
"destination-prefix": "192.168.33.1/32",
"next-hop": {
"special-next-hop": "blackhole"
}
}]
}
},
{
}
}, {
"type": "infix-routing:ospfv2",
"name": "default",
"ospf": {
"redistribute": {
"redistribute": [{
"protocol": "static"
},
{
}, {
"protocol": "connected"
}]
},
"areas": {
"area": [{
"area-id": "0.0.0.0",
"interfaces":
{
"interfaces": {
"interface": [{
"enabled": True,
"name": link,
@@ -103,35 +108,43 @@ def config_target1(target, data, link):
}
})
def config_target2(target, link):
def config_target2(target, link, data):
target.put_config_dict("ietf-interfaces", {
"interfaces": {
"interface": [
{
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.50.2",
"prefix-length": 24
}]
}
},
{
"name": "lo",
"enabled": True,
"forwarding": True,
"ipv4": {
"address": [{
"ip": "192.168.200.1",
"prefix-length": 32
}]
}
}
]
}
})
"interfaces": {
"interface": [{
"name": link,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.50.2",
"prefix-length": 24
}]
}
}, {
"name": data,
"enabled": True,
"ipv4": {
"forwarding": True,
"address": [{
"ip": "192.168.60.1",
"prefix-length": 24
}]
}
}, {
"name": "lo",
"enabled": True,
"forwarding": True,
"ipv4": {
"address": [{
"ip": "192.168.200.1",
"prefix-length": 32
}]
}
}]
}
})
target.put_config_dict("ietf-system", {
"system": {
@@ -141,8 +154,7 @@ def config_target2(target, link):
target.put_config_dict("ietf-routing", {
"routing": {
"control-plane-protocols": {
"control-plane-protocol": [
{
"control-plane-protocol": [{
"type": "infix-routing:ospfv2",
"name": "default",
"ospf": {
@@ -154,7 +166,7 @@ def config_target2(target, link):
"areas": {
"area": [{
"area-id": "0.0.0.0",
"interfaces":{
"interfaces": {
"interface": [{
"enabled": True,
"name": link,
@@ -165,31 +177,61 @@ def config_target2(target, link):
}]
}
}
}
]
}]
}
}
})
def config_host(target, link):
target.put_config_dict("ietf-interfaces", {
"interfaces": {
"interface": [{
"name": link,
"enabled": True,
"ipv4": {
"address": [{
"ip": "192.168.60.2",
"prefix-length": 24
}]
}
}]
}
})
target.put_config_dict("ietf-system", {
"system": {
"hostname": "HOST"
}
})
with infamy.Test() as test:
with test.step("Set up topology and attach to target DUTs"):
env = infamy.Env()
R1 = env.attach("R1", "mgmt")
R2 = env.attach("R2", "mgmt")
HOST = env.attach("HOST", "mgmt")
with test.step("Configure targets"):
_, R1data = env.ltop.xlate("R1", "data")
_, R2link = env.ltop.xlate("R2", "link")
_, R1link= env.ltop.xlate("R1", "link")
_, R1link = env.ltop.xlate("R1", "link")
_, R2data = env.ltop.xlate("R2", "data")
_, HOSTlink = env.ltop.xlate("HOST", "link")
parallel(config_target1(R1, R1data, R1link),
config_target2(R2, R2link))
config_target2(R2, R2link, R2data),
config_host(HOST, HOSTlink))
with test.step("Wait for OSPF routes"):
print("Waiting for OSPF routes..")
until(lambda: route.ipv4_route_exist(R1, "192.168.200.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
until(lambda: route.ipv4_route_exist(R2, "192.168.100.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
until(lambda: route.ipv4_route_exist(R2, "192.168.33.1/32", proto="ietf-ospf:ospfv2"), attempts=200)
with test.step("Verify R2 OSPF neighbors with non-OSPF interface"):
# Regression test for #1169
assert route.ospf_has_neighbors(R2)
with test.step("Test connectivity from PC:data to 192.168.200.1"):
_, hport0 = env.ltop.xlate("PC", "data")
with infamy.IsolatedMacVlan(hport0) as ns0:
+14 -6
View File
@@ -8,26 +8,34 @@ graph "2x2" {
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
PC [
label="PC | { <mgmt1> mgmt1 | <data> data | <mgmt2> mgmt2 }",
pos="20,80!",
label="PC | { <mgmt1> mgmt1 | <data> data | <mgmt2> mgmt2 | <mgmt3> mgmt3 }",
pos="20,30!",
requires="controller",
];
R1 [
label="{ <mgmt> mgmt | <data> data | <link> link} | R1 \n 192.168.100.1/32 \n(lo)",
pos="250,80!",
pos="160,60!",
requires="infix",
];
R2 [
label="{ <link> link | <mgmt> mgmt | <data> data } | R2 \n 192.168.200.1/32 \n(lo)",
pos="250,30!",
pos="160,30!",
requires="infix",
];
HOST [
label="{ <link> link | <mgmt> mgmt } | HOST \n end-device",
pos="153,0!",
requires="infix",
];
PC:mgmt1 -- R1:mgmt [requires="mgmt", color="lightgray"]
PC:mgmt2 -- R2:mgmt [requires="mgmt", color="lightgray"]
PC:data -- R1:data [color="black", headlabel="192.168.10.1/24", taillabel="192.168.10.2/24", fontcolor="black"]
PC:mgmt3 -- HOST:mgmt [requires="mgmt", color="lightgray"]
PC:data -- R1:data [color="black", headlabel="192.168.10.1/24", taillabel="192.168.10.2/24", labeldistance=6, fontcolor="black"]
R1:link -- R2:link [headlabel="192.168.50.2/24", taillabel="192.168.50.1/24", labeldistance=1, fontcolor="black", color="black"]
R2:data -- HOST:link [headlabel="192.168.60.2/24", taillabel="192.168.60.1/24", labeldistance=1, fontcolor="black", color="black"]
}
+62 -37
View File
@@ -3,74 +3,99 @@
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Title: 2x2 Pages: 1 -->
<svg width="713pt" height="198pt"
viewBox="0.00 0.00 713.06 198.01" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 194.01)">
<svg width="720pt" height="306pt"
viewBox="0.00 0.00 720.00 306.08" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 302.52)">
<title>2x2</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-194.01 709.06,-194.01 709.06,4 -4,4"/>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-302.52 717.06,-302.52 717.06,4 -4,4"/>
<!-- PC -->
<g id="node1" class="node">
<title>PC</title>
<polygon fill="none" stroke="black" points="0,-120.51 0,-189.51 91,-189.51 91,-120.51 0,-120.51"/>
<text text-anchor="middle" x="16.5" y="-151.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">PC</text>
<polyline fill="none" stroke="black" points="33,-120.51 33,-189.51 "/>
<polygon fill="none" stroke="black" points="0,-97.51 0,-189.51 91,-189.51 91,-97.51 0,-97.51"/>
<text text-anchor="middle" x="16.5" y="-139.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">PC</text>
<polyline fill="none" stroke="black" points="33,-97.51 33,-189.51 "/>
<text text-anchor="middle" x="62" y="-174.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt1</text>
<polyline fill="none" stroke="black" points="33,-166.51 91,-166.51 "/>
<text text-anchor="middle" x="62" y="-151.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="33,-143.51 91,-143.51 "/>
<text text-anchor="middle" x="62" y="-128.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt2</text>
<polyline fill="none" stroke="black" points="33,-120.51 91,-120.51 "/>
<text text-anchor="middle" x="62" y="-105.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt3</text>
</g>
<!-- R1 -->
<g id="node2" class="node">
<title>R1</title>
<polygon fill="none" stroke="black" points="490.06,-120.51 490.06,-189.51 705.06,-189.51 705.06,-120.51 490.06,-120.51"/>
<text text-anchor="middle" x="515.06" y="-174.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="490.06,-166.51 540.06,-166.51 "/>
<text text-anchor="middle" x="515.06" y="-151.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="490.06,-143.51 540.06,-143.51 "/>
<text text-anchor="middle" x="515.06" y="-128.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="540.06,-120.51 540.06,-189.51 "/>
<text text-anchor="middle" x="622.56" y="-166.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">R1 </text>
<text text-anchor="middle" x="622.56" y="-151.31" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 192.168.100.1/32 </text>
<text text-anchor="middle" x="622.56" y="-136.31" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo)</text>
<polygon fill="none" stroke="black" points="498.06,-229.02 498.06,-298.02 713.06,-298.02 713.06,-229.02 498.06,-229.02"/>
<text text-anchor="middle" x="523.06" y="-282.82" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="498.06,-275.02 548.06,-275.02 "/>
<text text-anchor="middle" x="523.06" y="-259.82" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="498.06,-252.02 548.06,-252.02 "/>
<text text-anchor="middle" x="523.06" y="-236.82" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="548.06,-229.02 548.06,-298.02 "/>
<text text-anchor="middle" x="630.56" y="-274.82" font-family="DejaVu Sans Mono, Book" font-size="14.00">R1 </text>
<text text-anchor="middle" x="630.56" y="-259.82" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 192.168.100.1/32 </text>
<text text-anchor="middle" x="630.56" y="-244.82" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo)</text>
</g>
<!-- PC&#45;&#45;R1 -->
<g id="edge1" class="edge">
<title>PC:mgmt1&#45;&#45;R1:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-178.01C91.5,-178.01 489.56,-178.01 489.56,-178.01"/>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-178.51C91.5,-178.51 497.56,-286.52 497.56,-286.52"/>
</g>
<!-- PC&#45;&#45;R1 -->
<g id="edge3" class="edge">
<g id="edge4" class="edge">
<title>PC:data&#45;&#45;R1:data</title>
<path fill="none" stroke="black" stroke-width="2" d="M91.5,-155.01C91.5,-155.01 489.56,-155.01 489.56,-155.01"/>
<text text-anchor="middle" x="430.56" y="-158.81" font-family="DejaVu Serif, Book" font-size="14.00">192.168.10.1/24</text>
<text text-anchor="middle" x="150.5" y="-158.81" font-family="DejaVu Serif, Book" font-size="14.00">192.168.10.2/24</text>
<path fill="none" stroke="black" stroke-width="2" d="M91.5,-155.51C91.5,-155.51 497.56,-263.52 497.56,-263.52"/>
<text text-anchor="middle" x="438.49" y="-270.35" font-family="DejaVu Serif, Book" font-size="14.00">192.168.10.1/24</text>
<text text-anchor="middle" x="150.57" y="-141.29" font-family="DejaVu Serif, Book" font-size="14.00">192.168.10.2/24</text>
</g>
<!-- R2 -->
<g id="node3" class="node">
<title>R2</title>
<polygon fill="none" stroke="black" points="490.06,-0.5 490.06,-69.5 705.06,-69.5 705.06,-0.5 490.06,-0.5"/>
<text text-anchor="middle" x="515.06" y="-54.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="490.06,-46.5 540.06,-46.5 "/>
<text text-anchor="middle" x="515.06" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="490.06,-23.5 540.06,-23.5 "/>
<text text-anchor="middle" x="515.06" y="-8.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="540.06,-0.5 540.06,-69.5 "/>
<text text-anchor="middle" x="622.56" y="-46.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">R2 </text>
<text text-anchor="middle" x="622.56" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 192.168.200.1/32 </text>
<text text-anchor="middle" x="622.56" y="-16.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo)</text>
<polygon fill="none" stroke="black" points="498.06,-109.01 498.06,-178.01 713.06,-178.01 713.06,-109.01 498.06,-109.01"/>
<text text-anchor="middle" x="523.06" y="-162.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="498.06,-155.01 548.06,-155.01 "/>
<text text-anchor="middle" x="523.06" y="-139.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="498.06,-132.01 548.06,-132.01 "/>
<text text-anchor="middle" x="523.06" y="-116.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">data</text>
<polyline fill="none" stroke="black" points="548.06,-109.01 548.06,-178.01 "/>
<text text-anchor="middle" x="630.56" y="-154.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">R2 </text>
<text text-anchor="middle" x="630.56" y="-139.81" font-family="DejaVu Sans Mono, Book" font-size="14.00"> 192.168.200.1/32 </text>
<text text-anchor="middle" x="630.56" y="-124.81" font-family="DejaVu Sans Mono, Book" font-size="14.00">(lo)</text>
</g>
<!-- PC&#45;&#45;R2 -->
<g id="edge2" class="edge">
<title>PC:mgmt2&#45;&#45;R2:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-132.01C91.5,-132.01 489.56,-35 489.56,-35"/>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-131.51C91.5,-131.51 497.56,-143.51 497.56,-143.51"/>
</g>
<!-- HOST -->
<g id="node4" class="node">
<title>HOST</title>
<polygon fill="none" stroke="black" points="499.05,-0.5 499.05,-46.5 656.05,-46.5 656.05,-0.5 499.05,-0.5"/>
<text text-anchor="middle" x="524.05" y="-31.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">link</text>
<polyline fill="none" stroke="black" points="499.05,-23.5 549.05,-23.5 "/>
<text text-anchor="middle" x="524.05" y="-8.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="549.05,-0.5 549.05,-46.5 "/>
<text text-anchor="middle" x="602.55" y="-27.3" font-family="DejaVu Sans Mono, Book" font-size="14.00">HOST </text>
<text text-anchor="middle" x="602.55" y="-12.3" font-family="DejaVu Sans Mono, Book" font-size="14.00"> end&#45;device</text>
</g>
<!-- PC&#45;&#45;HOST -->
<g id="edge3" class="edge">
<title>PC:mgmt3&#45;&#45;HOST:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M91.5,-108.51C91.5,-108.51 498.55,-11.5 498.55,-11.5"/>
</g>
<!-- R1&#45;&#45;R2 -->
<g id="edge4" class="edge">
<g id="edge5" class="edge">
<title>R1:link&#45;&#45;R2:link</title>
<path fill="none" stroke="black" stroke-width="2" d="M514.56,-120.01C514.56,-120.01 514.56,-70 514.56,-70"/>
<text text-anchor="middle" x="518.78" y="-75.36" font-family="DejaVu Serif, Book" font-size="14.00">192.168.50.2/24</text>
<text text-anchor="middle" x="510.33" y="-107.25" font-family="DejaVu Serif, Book" font-size="14.00">192.168.50.1/24</text>
<path fill="none" stroke="black" stroke-width="2" d="M522.56,-228.52C522.56,-228.52 522.56,-178.51 522.56,-178.51"/>
<text text-anchor="middle" x="526.78" y="-183.88" font-family="DejaVu Serif, Book" font-size="14.00">192.168.50.2/24</text>
<text text-anchor="middle" x="518.33" y="-215.76" font-family="DejaVu Serif, Book" font-size="14.00">192.168.50.1/24</text>
</g>
<!-- R2&#45;&#45;HOST -->
<g id="edge6" class="edge">
<title>R2:data&#45;&#45;HOST:link</title>
<path fill="none" stroke="black" stroke-width="2" d="M522.56,-108.51C522.56,-108.51 523.55,-46.5 523.55,-46.5"/>
<text text-anchor="middle" x="527.63" y="-51.93" font-family="DejaVu Serif, Book" font-size="14.00">192.168.60.2/24</text>
<text text-anchor="middle" x="518.48" y="-95.68" font-family="DejaVu Serif, Book" font-size="14.00">192.168.60.1/24</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

@@ -26,7 +26,6 @@ endif::topdoc[]
. Set hostname to 'container-host'
. Create enabled container from bundled OCI image
. Verify container has started
. Let container settle
. Disable container
. Verify container has stopped
. Re-enable container
@@ -1,14 +1,11 @@
=== Container environment variables
==== Description
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
==== Topology
ifdef::topdoc[]
@@ -25,11 +22,10 @@ endif::topdoc[]
==== Test sequence
. Set up topology and attach to target DUT
. Configure data interface with static IPv4
. Create container with environment variables
. Set up container with environment variables
. Verify container has started
. Verify environment variables are available via HTTP
. Verify basic connectivity to data interface
. Verify environment variables in HTTP response
. Verify environment variables in CGI response
<<<
+55 -9
View File
@@ -1,26 +1,72 @@
"""Fugly URL fetcher"""
"""Simple HTTP URL fetcher and content checker
This module provides the a lightweight wrapper around urllib for testing
HTTP endpoints. It's designed specifically for test scenarios where you
need to:
- Fetch HTTP content and verify it contains expected strings
- Perform checks from within network namespaces
- Validate multiple content patterns in a single request
- Handle network errors gracefully in test environments
Example usage:
# Single needle check
url = Furl("http://example.com/api")
if url.check("success"):
print("API returned success")
# Multiple needle check (all must match)
if url.check(["user: alice", "status: active", "role: admin"]):
print("All user details found")
# Check from network namespace
with IsolatedMacVlan("eth0") as ns:
if url.nscheck(ns, "expected content"):
print("Content verified from namespace")
"""
import urllib.error
import urllib.parse
import urllib.request
class Furl:
"""Furl wraps urllib in a way similar to curl"""
def __init__(self, url):
"""Create new URL checker"""
self.url = urllib.parse.quote(url, safe='/:')
def check(self, needle, timeout=10):
"""Connect to web server URL, fetch body and check for needle"""
def check(self, needles, timeout=10):
"""Connect to web server URL, fetch body and check for needle(s)
Args:
needles: String or list of strings to search for in response
timeout: Request timeout in seconds
Returns:
bool: True if all needles found in response, False otherwise
"""
# Backwards compat, make needles a list for uniform processing
if isinstance(needles, str):
needles = [needles]
try:
with urllib.request.urlopen(self.url, timeout=timeout) as response:
text = response.read().decode('utf-8')
#print(text)
return needle in text
except urllib.error.URLError as _:
return all(needle in text for needle in needles)
except urllib.error.URLError:
return False
except ConnectionResetError:
return False
def nscheck(self, netns, needle):
""""Call check() from netns"""
return netns.call(lambda: self.check(needle))
def nscheck(self, netns, needles):
""""Call check() from netns
Args:
netns: Network namespace to call from
needles: String or list of strings to search for in response
Returns:
bool: True if all needles found in response, False otherwise
"""
return netns.call(lambda: self.check(needles))
-1
View File
@@ -150,7 +150,6 @@ class Device(Transport):
url = f"{self.yang_url}/{schema_name}"
data = self._get_raw(url=url, parse=False)
sys.stdout.write(f"Downloading YANG model {schema_name} ...\r\033[K")
data = data.decode('utf-8')
with open(f"{yangdir}/{schema_name}", 'w') as json_file:
json_file.write(data)
+10
View File
@@ -114,3 +114,13 @@ def ospf_is_area_nssa(target, area_id):
return True
return False
def ospf_has_neighbors(target):
ospf = _get_ospf_status(target)
for area in ospf.get("areas", {}).get("area", []):
for interface in area.get("interfaces", {}).get("interface", []):
if interface.get("neighbors"):
return True
return False
+15 -5
View File
@@ -1,9 +1,10 @@
base-dir := $(lastword $(subst :, ,$(BR2_EXTERNAL)))
test-dir := $(BR2_EXTERNAL_INFIX_PATH)/test
test-dir ?= $(BR2_EXTERNAL_INFIX_PATH)/test
ninepm := $(BR2_EXTERNAL_INFIX_PATH)/test/9pm/9pm.py
NINEPM_PROJ_CONF ?= $(BR2_EXTERNAL_INFIX_PATH)/test/9pm-proj.yaml
spec-dir := $(test-dir)/spec
test-specification := $(O)/images/test-specification.pdf
test-specification := $(BINARIES_DIR)/test-specification.pdf
test-report := $(BINARIES_DIR)/test-report.pdf
UNIT_TESTS ?= $(test-dir)/case/all-repo.yaml $(test-dir)/case/all-unit.yaml
TESTS ?= $(test-dir)/case/all.yaml
@@ -33,9 +34,18 @@ test-sh:
test-spec:
@esc_infix_name="$(echo $(INFIX_NAME) | sed 's/\//\\\//g')"; \
sed 's/{REPLACE}/$(subst ",,$(esc_infix_name)) $(INFIX_VERSION)/' $(spec-dir)/Readme.adoc.in > $(spec-dir)/Readme.adoc
sed 's/{REPLACE}/$(subst ",,$(esc_infix_name)) $(INFIX_VERSION)/' \
$(spec-dir)/Readme.adoc.in > $(spec-dir)/Readme.adoc
@$(spec-dir)/generate_spec.py -s $(test-dir)/case/all.yaml -r $(BR2_EXTERNAL_INFIX_PATH)
@asciidoctor-pdf --failure-level INFO --theme $(spec-dir)/theme.yml -a pdf-fontsdir=$(spec-dir)/fonts -o $(test-specification) $(spec-dir)/Readme.adoc
@asciidoctor-pdf --failure-level INFO --theme $(spec-dir)/theme.yml \
-a pdf-fontsdir=$(spec-dir)/fonts \
-o $(test-specification) $(spec-dir)/Readme.adoc
test-report:
asciidoctor-pdf --theme $(spec-dir)/theme.yml \
-a logo="image:$(LOGO)" \
-a pdf-fontsdir=$(spec-dir)/fonts \
-o $(test-report) $(test-dir)/.log/last/report.adoc
# Unit tests run with random (-r) hostname and container name to
# prevent race conditions when running in CI environments.