diff --git a/xCAT-test/autotest/testcase/dhcptest/dhcpfixture.sh b/xCAT-test/autotest/testcase/dhcptest/dhcpfixture.sh index b62c4bd1d..69e9b5d03 100755 --- a/xCAT-test/autotest/testcase/dhcptest/dhcpfixture.sh +++ b/xCAT-test/autotest/testcase/dhcptest/dhcpfixture.sh @@ -26,6 +26,7 @@ # dhcpfixture.sh run-multimac a node reachable on either of its two ports # dhcpfixture.sh run-iscsi a diskless node is told where its root is # dhcpfixture.sh run-loader-absent a loader that is not on disk is not named +# dhcpfixture.sh run-localboot an installed node is sent no xNBA script # dhcpfixture.sh run-httpport URLs carry a non-default web port # dhcpfixture.sh run-rangecidr a dynamic range written as a CIDR block # dhcpfixture.sh run-removal makedhcp -d stops the address being served @@ -112,6 +113,14 @@ RM_NODE=dhcptestrm RM_IP=10.99.0.71 RM_MAC=02:00:dc:11:00:71 +# A node that has been installed already: chain.currstate says it has an +# operating system and must be left to start it. netboot is xnba rather than +# the fixture's usual grub2 because the script that must not be sent is an +# xNBA second stage, and only netboot=xnba generates one. +LB_NODE=dhcptestboot +LB_IP=10.99.0.81 +LB_MAC=02:00:dc:11:00:61 + # A machine that speaks BOOTP and not DHCP, and the web port a cluster that is # not serving on 80 would use. BOOTP_MAC=02:00:de:ad:b0:07 @@ -817,6 +826,29 @@ do_run_iscsi() { return $rc } +# S-31. A node that has already been installed. chain.currstate is what says +# so, and it is set through chtab because it has no node attribute of its own. +# +# The script that must not be sent is the second stage of an xNBA boot, so the +# node is defined with netboot=xnba and the case asks twice: once as firmware, +# once announcing the user class the first stage sets. Only the second request +# can be answered with the script, so only the second request can catch this. +do_run_localboot() { + local rc=0 + extra_define "$LB_NODE" groups=dhcptest ip="$LB_IP" mac="$LB_MAC" \ + arch=x86_64 netboot=xnba tftpserver="$SRV_IP" xcatmaster="$SRV_IP" + chtab node="$LB_NODE" chain.currstate=boot \ + || die "cannot set chain.currstate for $LB_NODE" + echo done > "$STATE/localboot" + makedhcp "$LB_NODE" || die "makedhcp $LB_NODE failed" + + dhcptest_run \ + --set booted_mac="$LB_MAC" --set booted_ip="$LB_IP" \ + --set booted_script="http://$SRV_IP/tftpboot/xcat/xnba/nodes/$LB_NODE" \ + conf/localboot.conf || rc=1 + return $rc +} + # S-12. One gating loader is taken away and the configuration regenerated -- # both backends decide which boot classes to write by looking at what is on # disk, so the file has to be gone before makedhcp runs, not after. @@ -989,6 +1021,7 @@ dispatch() { run-multimac) do_run_multimac ;; run-iscsi) do_run_iscsi ;; run-loader-absent) do_run_loader_absent ;; + run-localboot) do_run_localboot ;; run-httpport) do_run_httpport ;; run-rangecidr) do_run_rangecidr ;; run-removal) do_run_removal ;; @@ -997,7 +1030,7 @@ dispatch() { run-hierarchy) do_run_hierarchy ;; run-adoption) do_run_adoption ;; teardown) do_teardown ;; - *) die "usage: $0 {check|setup|generate|backends|backend-setup |backend-teardown |run|run-arch|run-netboot|run-lease|run-chainload|run-nextserver|run-multimac|run-iscsi|run-loader-absent|run-httpport|run-rangecidr|run-removal|run-bootp|delegate|run-hierarchy|run-adoption|teardown}" ;; + *) die "usage: $0 {check|setup|generate|backends|backend-setup |backend-teardown |run|run-arch|run-netboot|run-lease|run-chainload|run-nextserver|run-multimac|run-iscsi|run-loader-absent|run-localboot|run-httpport|run-rangecidr|run-removal|run-bootp|delegate|run-hierarchy|run-adoption|teardown}" ;; esac } diff --git a/xCAT-test/dhcptest/conf/discovery-adoption.conf b/xCAT-test/dhcptest/conf/discovery-adoption.conf index 43d111590..2c7fcabea 100644 --- a/xCAT-test/dhcptest/conf/discovery-adoption.conf +++ b/xCAT-test/dhcptest/conf/discovery-adoption.conf @@ -27,7 +27,7 @@ timeout = 3 retries = 3 [scenario machine-is-unknown] -description = Before it is defined, the machine is served out of the pool +description = S-58: Before it is defined, the machine is served out of the pool [step before-discover] type = discover @@ -39,7 +39,7 @@ assert = yiaddr != %(adopt_ip)s [scenario machine-has-been-adopted] -description = Once it is defined, the same MAC is served its own address +description = S-58: Once it is defined, the same MAC is served its own address [step after-discover] type = discover diff --git a/xCAT-test/dhcptest/conf/discovery-bootfile.conf b/xCAT-test/dhcptest/conf/discovery-bootfile.conf index 1b79796e8..3c1e92c54 100644 --- a/xCAT-test/dhcptest/conf/discovery-bootfile.conf +++ b/xCAT-test/dhcptest/conf/discovery-bootfile.conf @@ -17,7 +17,7 @@ # conf/discovery-bootfile.conf [scenario unknown-node-is-told-what-to-boot] -description = A machine the server does not know is still handed a loader +description = S-55, S-56: A machine the server does not know is still handed a loader [step discovery-boot-discover] type = discover diff --git a/xCAT-test/dhcptest/conf/hierarchy-dhcpserver.conf b/xCAT-test/dhcptest/conf/hierarchy-dhcpserver.conf index e736d3d6f..b7c3c929c 100644 --- a/xCAT-test/dhcptest/conf/hierarchy-dhcpserver.conf +++ b/xCAT-test/dhcptest/conf/hierarchy-dhcpserver.conf @@ -23,7 +23,7 @@ # conf/hierarchy-dhcpserver.conf [scenario delegated-pool-is-not-served-here] -description = An unknown MAC gets nothing: the dynamic pool belongs to another server +description = S-40: An unknown MAC gets nothing: the dynamic pool belongs to another server [step delegated-discover] type = discover @@ -35,7 +35,7 @@ assert = offers == 0 [scenario delegated-node-is-pointed-elsewhere] -description = A known machine is still answered, but sent to the delegate to boot +description = S-41: A known machine is still answered, but sent to the delegate to boot [step delegated-node-discover] type = discover diff --git a/xCAT-test/dhcptest/conf/localboot.conf b/xCAT-test/dhcptest/conf/localboot.conf new file mode 100644 index 000000000..df84dd976 --- /dev/null +++ b/xCAT-test/dhcptest/conf/localboot.conf @@ -0,0 +1,64 @@ +# A node that already has an operating system. +# +# Once a node has been installed, chain.currstate is "boot" (or "iscsiboot" for +# a node whose disk is an iSCSI target). From that point the server must stop +# handing it a netboot script: a node that is given one every time it powers on +# reinstalls itself forever, and does so silently, because each individual boot +# looks like a successful boot. +# +# The address is still owned by the node and must still be offered -- this is a +# statement about the boot file, not about the reservation. +# +# The two steps are the two halves of an xNBA boot. Firmware asks first with no +# user class and is answered with the loader binary; the loader then asks again +# announcing user class xNBA, and *that* is the request that would be answered +# with the node's script. A test that only sends the first request cannot see +# the difference, because the script never appears in the first reply. +# +# What is asserted is exactly spec.md S-31: not "no boot file", which would +# forbid a server from handing back the stage-1 binary, but "not the node's +# xNBA script". The script URL is supplied on the command line so this file +# stays a statement about the wire: +# +# dhcptest run -i eth1 \ +# --set booted_mac=02:00:dc:11:00:61 \ +# --set booted_ip=10.0.0.61 \ +# --set booted_script=http://10.0.0.1/tftpboot/xcat/xnba/nodes/dhcptestboot \ +# conf/localboot.conf + +[defaults] +request_options = 1, 3, 6, 43, 54, 60, 66, 67 +timeout = 3 +retries = 3 +expect = offer + +[scenario booted-node-is-not-sent-a-script] +description = S-31: A node that has been installed is offered its address and no xNBA script + +[step firmware-discover] +type = discover +mac = %(booted_mac)s +client_arch = 0x0000 +vendor_class = PXEClient:Arch:00000:UNDI:002001 +assert = + msgtype == OFFER + yiaddr == %(booted_ip)s + bootfile != %(booted_script)s + +[scenario booted-node-is-not-sent-a-script-on-the-second-stage] +description = S-31: And is not sent one when the loader asks again as xNBA + +# The same node, same MAC, announcing the user class the first stage sets. This +# is the request the script is keyed on, so it is the one that decides whether +# an installed node reinstalls itself. +[step second-stage-discover] +type = discover +mac = %(booted_mac)s +client_arch = 0x0000 +vendor_class = PXEClient:Arch:00000:UNDI:002001 +user_class = xNBA +user_class_form = raw +assert = + msgtype == OFFER + yiaddr == %(booted_ip)s + bootfile != %(booted_script)s diff --git a/xCAT-test/dhcptest/conf/nak-foreign-address.conf b/xCAT-test/dhcptest/conf/nak-foreign-address.conf index b97c5689e..fb719d605 100644 --- a/xCAT-test/dhcptest/conf/nak-foreign-address.conf +++ b/xCAT-test/dhcptest/conf/nak-foreign-address.conf @@ -12,7 +12,7 @@ # dhcptest run -i eth1 --set foreign_ip=192.0.2.77 conf/nak-foreign-address.conf [scenario foreign-address-is-refused] -description = A request for an address off this network is refused, not ignored +description = S-53: A request for an address off this network is refused, not ignored [step reboot-request] type = request diff --git a/xCAT-test/dhcptest/conf/provision-vs-discovery.conf b/xCAT-test/dhcptest/conf/provision-vs-discovery.conf index 5aa33ed90..7a86b790e 100644 --- a/xCAT-test/dhcptest/conf/provision-vs-discovery.conf +++ b/xCAT-test/dhcptest/conf/provision-vs-discovery.conf @@ -38,7 +38,7 @@ timeout = 3 retries = 3 [scenario known-node-is-provisioned] -description = A machine the server knows gets its own address and its own boot file +description = S-01: A machine the server knows gets its own address and its own boot file [step known-discover] type = discover @@ -65,7 +65,7 @@ assert = option:1 present [scenario known-node-gets-a-usable-network] -description = The node is told how to route, resolve and keep time, not just its address +description = S-44, S-49, S-50: The node is told how to route, resolve and keep time, not just its address # An address on its own does not install an operating system. The installer has # to route off the provisioning network, resolve the server it fetches from, @@ -151,7 +151,7 @@ assert = yiaddr == %(node_ip)s [scenario unknown-node-is-discovered] -description = A machine the server does not know gets an address out of the pool +description = S-03: A machine the server does not know gets an address out of the pool [step unknown-discover] type = discover diff --git a/xCAT-test/dhcptest/conf/pxe-arch-matrix.conf b/xCAT-test/dhcptest/conf/pxe-arch-matrix.conf index 58b52f0bd..a2e57331b 100644 --- a/xCAT-test/dhcptest/conf/pxe-arch-matrix.conf +++ b/xCAT-test/dhcptest/conf/pxe-arch-matrix.conf @@ -88,7 +88,7 @@ assert = bootfile == %(uefi_loader)s [scenario pxe-aarch64] -description = S-11: An aarch64 UEFI client is offered the aarch64 loader +description = S-11, S-57: An aarch64 UEFI client is offered the aarch64 loader [step aarch64-discover] type = discover diff --git a/xCAT-test/dhcptest/conf/static-vs-dynamic.conf b/xCAT-test/dhcptest/conf/static-vs-dynamic.conf index 66953a2ba..a57986eb3 100644 --- a/xCAT-test/dhcptest/conf/static-vs-dynamic.conf +++ b/xCAT-test/dhcptest/conf/static-vs-dynamic.conf @@ -20,7 +20,7 @@ # conf/static-vs-dynamic.conf [scenario reserved-mac] -description = A reserved MAC is offered and acknowledged its reserved address +description = S-01: A reserved MAC is offered and acknowledged its reserved address [step reserved-discover] type = discover @@ -42,7 +42,7 @@ assert = yiaddr == %(reserved_ip)s [scenario unreserved-mac-gets-pool-address] -description = An unreserved MAC is offered an address out of the dynamic pool +description = S-03: An unreserved MAC is offered an address out of the dynamic pool [step pool-discover] type = discover