From 5147d0970ea9239b17a2d00e90122d47d410bc95 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Tue, 10 Mar 2026 15:17:40 -0600 Subject: [PATCH] Simplify warewulfd parser Signed-off-by: Jonathon Anderson --- internal/pkg/warewulfd/parser.go | 127 ++++++++++++++----------------- 1 file changed, 57 insertions(+), 70 deletions(-) diff --git a/internal/pkg/warewulfd/parser.go b/internal/pkg/warewulfd/parser.go index 47efe6f4..1fdbeda1 100644 --- a/internal/pkg/warewulfd/parser.go +++ b/internal/pkg/warewulfd/parser.go @@ -90,76 +90,85 @@ type parsedRequest struct { compress string } +func parseHwaddr(hwaddr string) string { + hwaddr = strings.ReplaceAll(hwaddr, "-", ":") + hwaddr = strings.ToLower(hwaddr) + return hwaddr +} + func parseRequest(req *http.Request) (parsedRequest, error) { var ret parsedRequest - url := strings.Split(req.URL.Path, "?")[0] - path_parts := strings.Split(url, "/") + path_parts := strings.Split(req.URL.Path, "/") - if len(path_parts) < 3 { - return ret, errors.New("unknown path components in GET") + // initial stage passed in the url path /[stage]/hwaddr + if len(path_parts) < 2 { + return ret, errors.New("path missing initial stage: " + req.URL.Path) + } + ret.stage = path_parts[1] + + // prefer stage from query string for provision stage + if ret.stage == "provision" && len(req.URL.Query()["stage"]) > 0 { + ret.stage = req.URL.Query()["stage"][0] } - // handle when stage was passed in the url path /[stage]/hwaddr - stage := path_parts[1] - hwaddr := "" - switch stage { - case "efiboot": - // /efiboot/{file}: no hwaddr in path; identified via ARP - if len(path_parts) > 3 { + // map the requested stage to a known stage + switch ret.stage { + case "provision": + ret.stage = "ipxe" + case "container": + ret.stage = "image" + case "overlay-system": + ret.stage = "system" + case "overlay-runtime": + ret.stage = "runtime" + } + + if ret.stage == "" { + return ret, errors.New("no stage specified: " + req.URL.RawQuery) + } + + if len(path_parts) > 2 { + if ret.stage == "efiboot" { + // /efiboot/{file}: no wwid in path; identified via ARP ret.efifile = strings.Join(path_parts[2:], "/") } else { - ret.efifile = path_parts[2] + ret.hwaddr = parseHwaddr(path_parts[2]) } - case "grub": - // /grub/{hwaddr}: hwaddr explicit in path - hwaddr = path_parts[2] - hwaddr = strings.ReplaceAll(hwaddr, "-", ":") - hwaddr = strings.ToLower(hwaddr) - default: - hwaddr = path_parts[2] - hwaddr = strings.ReplaceAll(hwaddr, "-", ":") - hwaddr = strings.ToLower(hwaddr) } - ret.hwaddr = hwaddr + remoteAddrPort, err := netip.ParseAddrPort(req.RemoteAddr) if err != nil { return ret, errors.New("could not parse remote address") } ret.ipaddr = remoteAddrPort.Addr().String() + if ret.ipaddr == "" { + return ret, errors.New("could not obtain ipaddr from HTTP request") + } ret.remoteport = int(remoteAddrPort.Port()) + if ret.remoteport == 0 { + return ret, errors.New("could not obtain remote port from HTTP request: " + req.RemoteAddr) + } + + if ret.hwaddr == "" && len(req.URL.Query()["wwid"]) > 0 { + ret.hwaddr = parseHwaddr(req.URL.Query()["wwid"][0]) + } + if ret.hwaddr == "" { + if hwaddr := parseHwaddr(ArpFind(ret.ipaddr)); hwaddr != "" { + ret.hwaddr = hwaddr + wwlog.Verbose("using %s from arp cache for %s", ret.hwaddr, ret.ipaddr) + } + } + if ret.hwaddr == "" { + return ret, errors.New("unable to determine wwid: " + req.URL.RawQuery) + } + if len(req.URL.Query()["assetkey"]) > 0 { ret.assetkey = req.URL.Query()["assetkey"][0] } - if len(req.URL.Query()["uuid"]) > 0 { ret.uuid = req.URL.Query()["uuid"][0] } - - if len(req.URL.Query()["stage"]) > 0 { - ret.stage = req.URL.Query()["stage"][0] - } else { - - switch stage { - case "ipxe", "provision": - ret.stage = "ipxe" - case "kernel": - ret.stage = "kernel" - case "image", "container": - ret.stage = "image" - case "overlay-system", "system": - ret.stage = "system" - case "overlay-runtime", "runtime": - ret.stage = "runtime" - case "efiboot": - ret.stage = "efiboot" - case "grub": - ret.stage = "grub" - case "initramfs": - ret.stage = "initramfs" - } - } - if len(req.URL.Query()["overlay"]) > 0 { ret.overlay = req.URL.Query()["overlay"][0] } @@ -169,28 +178,6 @@ func parseRequest(req *http.Request) (parsedRequest, error) { if ret.efifile == "" && len(req.URL.Query()["file"]) > 0 { ret.efifile = req.URL.Query()["file"][0] } - if ret.stage == "" { - return ret, errors.New("no stage encoded in GET") - } - if ret.hwaddr == "" { - if len(req.URL.Query()["wwid"]) > 0 { - ret.hwaddr = req.URL.Query()["wwid"][0] - ret.hwaddr = strings.ReplaceAll(ret.hwaddr, "-", ":") - ret.hwaddr = strings.ToLower(ret.hwaddr) - } else { - ret.hwaddr = ArpFind(ret.ipaddr) - wwlog.Verbose("node mac not encoded, arp cache got %s for %s", ret.hwaddr, ret.ipaddr) - if ret.hwaddr == "" { - return ret, errors.New("no hwaddr encoded in GET") - } - } - } - if ret.ipaddr == "" { - return ret, errors.New("could not obtain ipaddr from HTTP request") - } - if ret.remoteport == 0 { - return ret, errors.New("could not obtain remote port from HTTP request: " + req.RemoteAddr) - } return ret, nil }