diff --git a/xCAT-test/provtest/.gitignore b/xCAT-test/provtest/.gitignore new file mode 100644 index 000000000..9b4490b34 --- /dev/null +++ b/xCAT-test/provtest/.gitignore @@ -0,0 +1,6 @@ +# Python leaves these next to the source it imports, and provtest is run in +# place -- from a checkout during development and from +# /opt/xcat/share/xcat/tools/autotest after packaging -- so they appear in the +# tree rather than in a build directory. +__pycache__/ +*.pyc diff --git a/xCAT-test/provtest/conf/discovery-artefacts.conf b/xCAT-test/provtest/conf/discovery-artefacts.conf index c11798636..4f6642a6e 100644 --- a/xCAT-test/provtest/conf/discovery-artefacts.conf +++ b/xCAT-test/provtest/conf/discovery-artefacts.conf @@ -7,10 +7,21 @@ # never fetches them, and the day someone racks a new machine, nothing works and # nothing says why. # +# The name is the network address in hex truncated to the netmask, because that +# is what a loader asks for once it has failed to find a file for its own +# address: 10.99.1.0/24 is 0A6301, six digits and not eight. +# +# Three loader families, three scenarios, and a cluster runs whichever of them +# its architecture reaches: pxelinux and xnba for x86_64, grub2 for the UEFI +# architectures mknb writes a grub2 configuration for. They are selected with +# `-s` rather than skipped from inside, so a scenario that does not run says so +# by its absence and never by a pass. +# # provtest run \ # --set server=10.99.1.1 --set client=10.99.1.11 \ -# --set hexnet=0A630100 --set net=10.99.1.0 \ +# --set hexnet=0A6301 --set netfile=10.99.1.0_24 \ # --set master=10.99.1.1 --set xcatport=3001 \ +# -s pxelinux-discovery-config -s genesis-images-pxelinux \ # conf/discovery-artefacts.conf [defaults] @@ -29,9 +40,7 @@ type = tftp path = boot/grub2/grub.cfg-%(hexnet)s assert = size > 0 - # P-27: the destiny a machine with no definition must be given. - text contains destiny=discover - # P-28: and where to ask for the next one. + # P-28: where to ask for the next destiny. text contains xcatd=%(master)s:%(xcatport)s [step httpentry] @@ -62,14 +71,83 @@ description = The pxelinux discovery config answers under the hex network addres [step pxeconfig] type = tftp path = pxelinux.cfg/%(hexnet)s +# No `destiny=discover` here, deliberately: genesis asks xcatd what to do when +# the kernel command line does not tell it, and a machine nobody has defined is +# answered `discover`. The address it asks is therefore the whole content of +# this file, and a wrong one strands the machine in genesis with no error +# anywhere. +assert = + size > 0 + text contains xcatd=%(master)s:%(xcatport)s + text contains genesis.kernel + +# --- P-29, the other x86_64 loader ------------------------------------------ + +[scenario xnba-discovery-config] +description = The xnba discovery scripts for the network exist and name xcatd + +[step gpxe] +type = tftp +path = xcat/xnba/nets/%(netfile)s +assert = + size > 0 + text contains xcatd=%(master)s:%(xcatport)s + +[step uefi] +type = tftp +path = xcat/xnba/nets/%(netfile)s.uefi +# The UEFI script does say `destiny=discover` where the BIOS one leaves it to +# xcatd, so this is the one place the word itself is assertable. assert = size > 0 text contains destiny=discover + text contains xcatd=%(master)s:%(xcatport)s # --- P-30, P-31 ------------------------------------------------------------- -[scenario genesis-kernel-and-initrd] -description = The genesis kernel and initrd named by the discovery config are fetchable +[scenario genesis-images-pxelinux] +description = The genesis kernel and initrd named by the pxelinux config are fetchable + +[step pconfig] +type = tftp +path = pxelinux.cfg/%(hexnet)s +assert = + size > 0 + +[step pkernelpath] +type = extract +from = $pconfig.text +pattern = ^\s*KERNEL\s+/?(\S+) +assert = + matched == yes + +[step pkernel] +type = tftp +path = $pkernelpath.value +assert = + size > 0 + +[step pinitrdpath] +type = extract +from = $pconfig.text +pattern = \binitrd=(\S+) +assert = + matched == yes + +[step pinitrd] +type = tftp +path = $pinitrdpath.value +# Tens of megabytes over TFTP, which is slow enough to need its own timeout. +# It is fetched rather than merely looked for because a half-written initrd +# from an interrupted mknb is exactly the failure this catches, and a file that +# exists is not the same as a file that transfers. +timeout = 120 +retries = 1 +assert = + size > 0 + +[scenario genesis-images-grub2] +description = The genesis kernel and initrd named by the grub2 config are fetchable [step gconfig] type = tftp @@ -100,10 +178,6 @@ assert = [step initrd] type = tftp path = $initrdpath.value -# Tens of megabytes over TFTP, which is slow enough to need its own timeout. -# It is fetched rather than merely looked for because a half-written initrd -# from an interrupted mknb is exactly the failure this catches, and a file that -# exists is not the same as a file that transfers. timeout = 120 retries = 1 assert = diff --git a/xCAT-test/provtest/conf/dns-removal.conf b/xCAT-test/provtest/conf/dns-removal.conf index e8fa297c0..a566b6741 100644 --- a/xCAT-test/provtest/conf/dns-removal.conf +++ b/xCAT-test/provtest/conf/dns-removal.conf @@ -23,6 +23,10 @@ description = A withdrawn node resolves in neither direction type = dns name = %(node)s.%(domain)s rrtype = A +# NXDOMAIN is the passing result here, and the client calls only NOERROR ok, +# so the step has to say it expects no particular outcome and assert the +# status itself. +expect = any assert = status == NXDOMAIN count == 0 @@ -31,6 +35,7 @@ assert = type = dns name = %(revname)s rrtype = PTR +expect = any # A PTR left behind by a removal is the worse half of the two: the name is # gone, so nothing resolves the node forward, but the address still claims to # be it, and xcatd will act on that claim. diff --git a/xCAT-test/provtest/conf/dns.conf b/xCAT-test/provtest/conf/dns.conf index cfde6444a..470941560 100644 --- a/xCAT-test/provtest/conf/dns.conf +++ b/xCAT-test/provtest/conf/dns.conf @@ -100,8 +100,10 @@ description = An undefined name in the cluster domain is refused, not forwarded type = dns name = %(missing)s.%(domain)s rrtype = A -# NXDOMAIN is the answer under test, and dig reports it with rc=0, so the -# transport still succeeded. `expect` stays at its default. +expect = any +# `expect = any`: NXDOMAIN *is* the answer under test. The query reached the +# server and was answered authoritatively, which is a working resolver and not +# a failed one, so what is asserted is the status and not the fetch. assert = status == NXDOMAIN count == 0 diff --git a/xCAT-test/provtest/conf/http.conf b/xCAT-test/provtest/conf/http.conf index 060b388bd..7f47132fe 100644 --- a/xCAT-test/provtest/conf/http.conf +++ b/xCAT-test/provtest/conf/http.conf @@ -165,3 +165,34 @@ expect = fail # The control: if every port answered, the step above would prove nothing. assert = status == 0 + +# --- P-39, the other half of it --------------------------------------------- + +[scenario default-port-the-node-was-told] +description = A cluster on the default port names no port, and the default one answers + +[step defaultconfig] +type = tftp +path = %(knownfile)s +port = 69 +assert = + size > 0 + +[step configroot] +type = extract +from = $defaultconfig.text +pattern = set root=http,(\S+) +# On site.httpport 80 the plugins write the address alone, and the loader uses +# the protocol default. A port appearing here would be a node told to fetch +# from a port nothing was configured for, which is the same failure as the +# scenario above with the sign reversed -- so the assertion is that there is +# no colon, not that the port is right. +assert = + matched == yes + value matches ^[^:]+$ + +[step defaultserved] +type = http +url = http://$configroot.value/tftpboot/%(knownfile)s +assert = + status == 200 diff --git a/xCAT-test/provtest/conf/ordering.conf b/xCAT-test/provtest/conf/ordering.conf index f9fc65c28..c6af39eaa 100644 --- a/xCAT-test/provtest/conf/ordering.conf +++ b/xCAT-test/provtest/conf/ordering.conf @@ -6,8 +6,11 @@ # from the outside -- the node times out -- and telling them apart means # watching a console during a reboot. # -# P-74 needs the node's PTR removed first, and P-75 needs a second nodeset, so -# the fixture drives them in that order and the scenarios are selected with -s +# P-75 needs a second nodeset and P-74 needs the node's name withdrawn from +# resolution, and that order cannot be reversed: nodeset names the config it +# writes after the node's address, which it gets by resolving the node, so once +# the name is gone there is no second nodeset to be had. The fixture therefore +# drives P-75 first and P-74 last, and the scenarios are selected with -s # rather than all run at once. # # provtest run \ @@ -48,8 +51,14 @@ expect = fail # from the console that looks identical to a protocol fault at a server that # is up. Here the two are told apart without booting anything. assert = - handshake == no - error present + # No handshake and no answer, against a step that got both from the real + # address a moment earlier. `error` is deliberately not asserted: that + # field carries an element the server sent, and a server that was + # never reached sends nothing at all -- which is the distinction being + # drawn, not an omission in the assertion. + handshake == no + ok == no + serverdone == no # --- P-74 ------------------------------------------------------------------- # Run this only after the node's PTR has been removed. @@ -80,7 +89,15 @@ type = tftp path = boot/grub2/grub.cfg-%(hexip)s assert = size > 0 + text starts-with #%(second)s + # P-17 for a genesis state, where it is written on the kernel command line + # as well as on the first line: genesis is what reads it. text contains destiny=%(second)s + # P-16, and this is the only place it can be asserted: xcatd= is written + # for the genesis states and not for an OS install, because it is genesis + # that asks xcatd what to do next. A node put into one of these states + # with the wrong address here waits for an answer that cannot arrive. + text contains xcatd=%(master)s:%(xcatport)s [step stale] type = extract diff --git a/xCAT-test/provtest/conf/tftp-grub2.conf b/xCAT-test/provtest/conf/tftp-grub2.conf index f677def3d..c6501c20d 100644 --- a/xCAT-test/provtest/conf/tftp-grub2.conf +++ b/xCAT-test/provtest/conf/tftp-grub2.conf @@ -1,4 +1,4 @@ -# Stage 3: TFTP, grub2. Spec P-09, P-11 to P-17, P-24, P-70, P-71. +# Stage 3: TFTP, grub2. Spec P-09, P-11 to P-15, P-17, P-24, P-70, P-71. # # grub2 asks for three things in order: its own binary, a per-node config named # after the client, and whatever that config names. Each fetch is by exact @@ -51,13 +51,22 @@ type = tftp path = boot/grub2/grub.cfg-%(hexip)s assert = size > 0 + # P-17: the state nodeset was told to put the node in. xCAT writes it on + # the first line of the file it generates, which is also where nodestat + # reads it back from -- so a config whose first line disagrees with the + # database is a node whose reported state is not the one it will boot. + text starts-with #%(destiny)s # P-15: the installer picks its interface from BOOTIF. A node with two # ports that is handed the wrong one installs onto the wrong network. - text contains BOOTIF=01-%(macdashes)s - # P-16: where to talk xCAT to, and on which port. - text contains xcatd=%(master)s:%(xcatport)s - # P-17: what nodeset was told to make it do. - text contains destiny=%(destiny)s + # grub2 writes $net_default_mac, the variable the loader expands to the + # interface it booted from, rather than the MAC xCAT has on file; either + # is a correct answer and an absent BOOTIF is not. + text matches BOOTIF=(\$net_default_mac|01-%(macdashes)s) + # P-16 is not asserted here: xcatd= and destiny= appear on the kernel + # command line only for the genesis states, and an OS install is booted + # with the distribution installer's command line. The genesis form is + # asserted where a node is put into one -- see the ordering and discovery + # scenarios. # --- P-12 ------------------------------------------------------------------- diff --git a/xCAT-test/provtest/conf/tftp-petitboot.conf b/xCAT-test/provtest/conf/tftp-petitboot.conf index e5d1ee8e6..0c7bed110 100644 --- a/xCAT-test/provtest/conf/tftp-petitboot.conf +++ b/xCAT-test/provtest/conf/tftp-petitboot.conf @@ -26,8 +26,16 @@ type = tftp path = petitboot/%(node)s assert = size > 0 - text contains xcatd=%(master)s:%(xcatport)s - text contains destiny=%(destiny)s + # The state nodeset was told to write, on the first line, as for the other + # loader families. xcatd= and destiny= are not asserted here: they are + # written on the kernel command line only for the genesis states, and an OS + # install is booted with the distribution installer's command line. + text starts-with #%(destiny)s + # petitboot reads one kernel line and one initrd line; without them the + # firmware shows an empty boot menu and waits, which from a console looks + # exactly like a node that never got a config at all. + text contains kernel + text contains initrd [step byhex] type = tftp diff --git a/xCAT-test/provtest/conf/tftp-pxelinux.conf b/xCAT-test/provtest/conf/tftp-pxelinux.conf index a62675fa7..3adb0d115 100644 --- a/xCAT-test/provtest/conf/tftp-pxelinux.conf +++ b/xCAT-test/provtest/conf/tftp-pxelinux.conf @@ -32,8 +32,12 @@ path = pxelinux.cfg/%(node)s assert = size > 0 text contains DEFAULT - text contains xcatd=%(master)s:%(xcatport)s - text contains destiny=%(destiny)s + # The state nodeset was told to write, on the first line, as for grub2. + text starts-with #%(destiny)s + # pxelinux's answer to the question BOOTIF answers for grub2: IPAPPEND 2 + # makes the loader append BOOTIF itself, from the interface it booted on. + # Without it the installer picks an interface of its own choosing. + text contains IPAPPEND 2 [step byhex] type = tftp diff --git a/xCAT-test/provtest/conf/tftp-xnba.conf b/xCAT-test/provtest/conf/tftp-xnba.conf index 084df78a2..50b29da04 100644 --- a/xCAT-test/provtest/conf/tftp-xnba.conf +++ b/xCAT-test/provtest/conf/tftp-xnba.conf @@ -7,7 +7,7 @@ # # provtest run \ # --set server=10.99.1.1 --set client=10.99.1.11 \ -# --set node=provtestcn --set nextserver=10.99.1.1 \ +# --set node=provtestcn --set httpport=80 \ # conf/tftp-xnba.conf [defaults] @@ -33,21 +33,23 @@ assert = [step kernelurl] type = extract from = $script.text -pattern = imgfetch\s+(?:-n\s+\S+\s+)?(\S+) +pattern = imgfetch\s+(?:-n\s+\S+\s+)?https?://[^/\s]+(/\S+) +# The host is deliberately not asserted, because xnba deliberately does not +# write one: the script says ${next-server}, the variable gpxe fills in from +# the DHCP acknowledgement, so the node fetches from whoever booted it -- its +# service node in a hierarchical cluster, and not necessarily the management +# node. Which address arrives in that acknowledgement is dhcptest's subject. +# What is assertable here is the path, and that it is served. assert = matched == yes - # The host in the URL is the address DHCP handed out as next-server. xnba - # builds it from the node's own attributes, so a node in a hierarchical - # cluster that is pointed at the management node instead of its service - # node fetches across a link that may not carry it. - value starts-with http://%(nextserver)s [step kernel] type = http -url = $kernelurl.value -# The assertion that matters: the URL the node was told to use answers. Not a -# URL this file built out of the same parts, which would only prove that two -# copies of the same assumption agree. +path = $kernelurl.value +port = %(httpport)s +# The assertion that matters: the path the node was told to fetch answers. +# Not a path this file built out of the same parts, which would only prove +# that two copies of the same assumption agree. assert = status == 200 size > 0 diff --git a/xCAT-test/provtest/conf/xcatd-credentials.conf b/xCAT-test/provtest/conf/xcatd-credentials.conf index eb3dd265a..1e51861d9 100644 --- a/xCAT-test/provtest/conf/xcatd-credentials.conf +++ b/xCAT-test/provtest/conf/xcatd-credentials.conf @@ -9,9 +9,15 @@ # "a signed cluster certificate", so both halves are asserted: that it is made, # and that a client which cannot answer it gets nothing. # +# The credential asked for is named in , exactly as getcredentials.awk +# names it when remoteshell and xcatserver run on the installing node. Genesis +# asks for x509cert instead and encloses a CSR; that path is not exercised here +# because a CSR is not something a wire test can fabricate meaningfully, and +# the callback is the same callback either way. +# # provtest run \ # --set server=10.99.1.1 --set client=10.99.1.11 \ -# --set xcatport=3001 --set credtype=xcat \ +# --set xcatport=3001 --set credtype=xcat_server_cred \ # conf/xcatd-credentials.conf [defaults] @@ -31,7 +37,7 @@ description = A client that answers the callback is given a signed certificate type = xcatreq command = getcredentials element = - credentials = %(credtype)s + arg = %(credtype)s # The listener goes up on the client's port 300 before the request is sent, # because the server connects back while the request is still open: a listener # started afterwards would be started too late. @@ -42,8 +48,12 @@ assert = # P-63: the callback arrived, and on the port the request named. callback_seen == yes callback_data contains CREDOKBYYOU - # P-62: and the answer carries something signed. - data present + # P-62: and the answer carries the credential that was asked for. The + # payload is wrapped as .... + # (credentials.pm:362), so `content` is where to look and `desc` says + # which of several credentials a reply belongs to. + desc == %(credtype)s + content contains -----BEGIN error absent # --- P-61 ------------------------------------------------------------------- @@ -55,11 +65,33 @@ description = A client with no listener on the callback port is given nothing type = xcatreq command = getcredentials element = - credentials = %(credtype)s + arg = %(credtype)s # No callback_listen: the port is closed, the server's connection is refused, # and the challenge goes unanswered. Anything signed arriving here would mean # an address alone is enough to collect a cluster certificate. expect = any assert = callback_seen == no - data absent + content absent + +# --- P-61 ------------------------------------------------------------------- + +[scenario credentials-nameless] +description = A request that names no credential is refused without a callback + +[step nameless] +type = xcatreq +command = getcredentials +# No : the request is well formed as XML and says nothing about what it +# wants. xcatd used to dereference the missing element and hand the client the +# resulting Perl error, file and line included, over a connection anything on +# the provisioning network can open. It must refuse instead, and must not +# spend a callback on a request it cannot serve. +callback_listen = 300 +callback_reply = CREDOKBYME +callback_wait = 5 +expect = any +assert = + content absent + callback_seen == no + error absent diff --git a/xCAT-test/provtest/conf/xcatd-destiny.conf b/xCAT-test/provtest/conf/xcatd-destiny.conf index df370d50a..527cc219a 100644 --- a/xCAT-test/provtest/conf/xcatd-destiny.conf +++ b/xCAT-test/provtest/conf/xcatd-destiny.conf @@ -61,15 +61,18 @@ description = A known node is told its state, and everything it needs to reach i type = xcatreq command = getdestiny assert = - # P-51 - destiny == %(destiny)s - # P-52: an install destiny that names no kernel is a node that boots - # nothing and reports success. - kernel present - initrd present - # P-53 - kcmdline contains xcatd=%(master)s:%(xcatport)s - kcmdline contains destiny=%(destiny)s + # P-51. The state is the whole chain.currstate string, which for an OS + # install is the word followed by the osimage nodeset resolved -- "install + # rhels9.99-x86_64-compute" and not "install". genesis matches on the + # first word, so that is what is asserted. + destiny starts-with %(destiny)s + # P-52 and P-53 are not asserted here, and the reason is worth writing + # down. getdestiny copies kernel, initrd and kcmdline out of the + # bootparams table (destiny.pm:968-976), and nothing in an ordinary + # install writes a row there: the loader config under $tftpdir is what + # names the kernel, and genesis uses the destiny field alone. bootparams + # is populated by the iSCSI and hypervisor paths instead. Asserting the + # three fields here would fail on every healthy cluster. # P-55: destiny.pm:975-987 tries noderes.tftpserver, then # noderes.xcatmaster, then the network's tftpserver, then site.master. # Four sources, no error if the wrong one wins -- the node boots and then diff --git a/xCAT-test/provtest/conf/xcatd-postscript.conf b/xCAT-test/provtest/conf/xcatd-postscript.conf index 947315e9e..2b85b2acb 100644 --- a/xCAT-test/provtest/conf/xcatd-postscript.conf +++ b/xCAT-test/provtest/conf/xcatd-postscript.conf @@ -3,8 +3,13 @@ # The node fetches the script it is to run after the installer finishes, and it # fetches it over whichever transport it has: TLS 3001 during genesis, # plain 3002 from `xcatdsklspost` inside the installed system. Two paths, one -# script, and the client reads until `#END OF SCRIPT` -- so a body that is -# truncated without the marker is read as a hang, not as an error. +# script, and two framings for it, which is the thing to keep straight when +# reading the assertions below. Over 3001 the body arrives as elements +# and is ended by . Over 3002 there is no envelope at all, so +# xcatd writes `#END OF SCRIPT` after the last line (xcatd:554) and the client +# reads until it -- a body truncated without the marker is read as a hang and +# not as an error. The marker is therefore asserted on the plain transport +# only; asserting it on the TLS one would be asserting the wrong protocol. # # provtest run \ # --set server=10.99.1.1 --set client=10.99.1.11 \ @@ -21,14 +26,18 @@ retries = 2 # --- P-57 ------------------------------------------------------------------- [scenario postscript-terminated] -description = A known node's postscript arrives complete, with its end marker +description = A known node's postscript arrives complete and is ended by the server [step getpostscript] type = xcatreq port = %(xcatport)s command = getpostscript assert = - text contains #END OF SCRIPT + # The envelope's end marker on this transport. A response without it is a + # connection the node is still waiting on. + serverdone == yes + # And the body is this node's: the script is built per node, and a node + # that runs somebody else's sets up somebody else's network and keys. text contains %(node)s # --- P-58 ------------------------------------------------------------------- @@ -63,16 +72,17 @@ type = xcatreq port = %(xcatport)s command = getpostscript assert = - text contains #END OF SCRIPT + serverdone == yes [step marker] type = extract from = $overtls.text -# A line from the body that is specific to this node and to this run, used -# below as the thing the other transport has to agree about. The two framings -# differ -- XML elements on one side, bare lines on the other -- so a byte -# comparison of the responses would compare the envelopes, not the script. -pattern = ^\s*(NODE=\S+|MASTER=\S+)\s*$ +# An assignment from the body that is specific to this node, used below as the +# thing the other transport has to agree about. The two framings differ -- +# XML elements on one side, bare lines on the other -- so a byte comparison of +# the responses would compare the envelopes and not the script. Unanchored for +# the same reason: on this transport the line is wrapped in . +pattern = (NODE=\S+) assert = matched == yes diff --git a/xCAT-test/provtest/src/provtest_lib/machine.py b/xCAT-test/provtest/src/provtest_lib/machine.py index aee839db5..dfd5efb64 100644 --- a/xCAT-test/provtest/src/provtest_lib/machine.py +++ b/xCAT-test/provtest/src/provtest_lib/machine.py @@ -65,7 +65,12 @@ REPLY_FIELDS = { "xcatreq": frozenset(["destiny", "kernel", "initrd", "kcmdline", "imgserver", "name", "error", "serverdone", "elements", "data", "text", "handshake", "ok", - "callback_seen", "callback_data", "raw"]), + "callback_seen", "callback_data", "raw", + # getcredentials wraps its payload one level deeper, + # as , and `desc` is + # how a reply carrying several credentials says + # which one each part is. + "content", "desc"]), "monitor": frozenset(["greeting", "lines", "raw", "text", "ok", "closed", "error"]), "flowrequest": frozenset(["replies", "count", "ok", "error", "raw"]), diff --git a/xCAT-test/provtest/src/provtest_lib/netutil.py b/xCAT-test/provtest/src/provtest_lib/netutil.py index 3642e5227..834c3a293 100644 --- a/xCAT-test/provtest/src/provtest_lib/netutil.py +++ b/xCAT-test/provtest/src/provtest_lib/netutil.py @@ -63,6 +63,26 @@ def hex_ip(address, upper=True): return text if upper else text.lower() +def hex_net(address, prefix, upper=True): + """The name a per-network configuration is written under. + + A loader that finds no file for its own address asks for ever shorter + prefixes of it, so the per-network file is named by as many hex digits as + the netmask covers, rounded up to a whole digit: 10.99.1.0/24 is 0A6301, + six digits and not eight. Anything defined for a network rather than for a + node -- which is everything a machine nobody has defined can reach -- is + named this way. + """ + text = hex_ip(address, upper=upper) + try: + bits = int(prefix) + except (TypeError, ValueError): + raise ValueError("not a prefix length: %r" % (prefix,)) + if not 0 <= bits <= 32: + raise ValueError("not a prefix length: %r" % (prefix,)) + return text[:(bits + 3) // 4] + + def reverse_name(address): """The IN-ADDR.ARPA name a resolver is asked for a PTR by.""" ip = parse_ip(address) diff --git a/xCAT-test/provtest/src/provtest_lib/xcatc.py b/xCAT-test/provtest/src/provtest_lib/xcatc.py index 68a61ab95..679b2fafc 100644 --- a/xCAT-test/provtest/src/provtest_lib/xcatc.py +++ b/xCAT-test/provtest/src/provtest_lib/xcatc.py @@ -33,7 +33,7 @@ from .model import Reply #: The elements a node's own scripts read out of a response. Everything else #: found in the XML is still available through `elements.`. NAMED_ELEMENTS = ("destiny", "kernel", "initrd", "kcmdline", "imgserver", - "name", "data", "error") + "name", "data", "error", "content", "desc") ELEMENT_RE = re.compile(r"<([A-Za-z_][\w.-]*)>([^<]*)") diff --git a/xCAT-test/provtest/tests/test_report.py b/xCAT-test/provtest/tests/test_report.py index ae7f69b43..943dc9000 100644 --- a/xCAT-test/provtest/tests/test_report.py +++ b/xCAT-test/provtest/tests/test_report.py @@ -134,9 +134,22 @@ class AddressTests(unittest.TestCase): self.assertEqual(netutil.hex_ip("10.99.1.11", upper=False), "0a63010b") def test_hex_ip_of_a_network_address(self): - # The per-network discovery config is named by the network's own hex. self.assertEqual(netutil.hex_ip("10.99.1.0"), "0A630100") + def test_a_per_network_config_is_named_by_the_prefix_only(self): + # 10.99.1.0/24 is 0A6301, not 0A630100: the file is named by as many + # digits as the netmask covers. Asking for all eight gets a machine + # with no definition nothing at all, which is the whole failure this + # stage exists to catch. + self.assertEqual(netutil.hex_net("10.99.1.0", 24), "0A6301") + self.assertEqual(netutil.hex_net("10.99.0.0", 16), "0A63") + self.assertEqual(netutil.hex_net("10.99.1.0", 26), "0A63010") + self.assertEqual(netutil.hex_net("10.99.1.0", 24, upper=False), "0a6301") + + def test_a_prefix_that_is_not_one_is_refused(self): + self.assertRaises(ValueError, netutil.hex_net, "10.99.1.0", 33) + self.assertRaises(ValueError, netutil.hex_net, "10.99.1.0", "wide") + def test_hex_ip_rejects_what_is_not_an_address(self): self.assertRaises(ValueError, netutil.hex_ip, "provtestcn")