using ProvisionSend instean of GrubSend
Signed-off-by: Christian Goll <cgoll@suse.com>
This commit is contained in:
committed by
Jonathon Anderson
parent
60dc8f6251
commit
0c9bf78cd0
@@ -20,6 +20,9 @@ func grubNames() []string {
|
||||
`grub-tpm.efi`,
|
||||
`grub.efi`,
|
||||
`grubx64.efi`,
|
||||
`grubia32.efi`,
|
||||
`grubaa64.efi`,
|
||||
`grubarm.efi`,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -16,6 +17,7 @@ type parserInfo struct {
|
||||
uuid string
|
||||
stage string
|
||||
overlay string
|
||||
efifile string
|
||||
compress string
|
||||
}
|
||||
|
||||
@@ -25,16 +27,22 @@ func parseReq(req *http.Request) (parserInfo, error) {
|
||||
url := strings.Split(req.URL.Path, "?")[0]
|
||||
path_parts := strings.Split(url, "/")
|
||||
|
||||
if len(path_parts) != 3 {
|
||||
if len(path_parts) < 3 {
|
||||
return ret, errors.New("unknown path components in GET")
|
||||
}
|
||||
|
||||
// handle when stage was passed in the url path /[stage]/hwaddr
|
||||
stage := path_parts[1]
|
||||
hwaddr := path_parts[2]
|
||||
hwaddr = strings.ReplaceAll(hwaddr, "-", ":")
|
||||
hwaddr = strings.ToLower(hwaddr)
|
||||
|
||||
hwaddr := ""
|
||||
if stage != "efiboot" {
|
||||
hwaddr = path_parts[2]
|
||||
hwaddr = strings.ReplaceAll(hwaddr, "-", ":")
|
||||
hwaddr = strings.ToLower(hwaddr)
|
||||
} else if len(path_parts) > 3 {
|
||||
ret.efifile = strings.Join(path_parts[2:], "/")
|
||||
} else {
|
||||
ret.efifile = path_parts[2]
|
||||
}
|
||||
ret.hwaddr = hwaddr
|
||||
ret.ipaddr = strings.Split(req.RemoteAddr, ":")[0]
|
||||
ret.remoteport, _ = strconv.Atoi(strings.Split(req.RemoteAddr, ":")[1])
|
||||
@@ -63,6 +71,8 @@ func parseReq(req *http.Request) (parserInfo, error) {
|
||||
ret.stage = "system"
|
||||
} else if stage == "overlay-runtime" {
|
||||
ret.stage = "runtime"
|
||||
} else if stage == "efiboot" {
|
||||
ret.stage = "efiboot"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +86,11 @@ func parseReq(req *http.Request) (parserInfo, error) {
|
||||
return ret, errors.New("no stage encoded in GET")
|
||||
}
|
||||
if ret.hwaddr == "" {
|
||||
return ret, errors.New("no hwaddr encoded in GET")
|
||||
ret.hwaddr = ArpFind(ret.ipaddr)
|
||||
wwlog.Verbose("node mac 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")
|
||||
|
||||
@@ -8,24 +8,17 @@ import (
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/template"
|
||||
|
||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||
"github.com/hpcng/warewulf/internal/pkg/container"
|
||||
"github.com/hpcng/warewulf/internal/pkg/kernel"
|
||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
var sentMap = make(map[string]string)
|
||||
|
||||
// define a mutex lock
|
||||
var mu sync.Mutex
|
||||
|
||||
type iPxeTemplate struct {
|
||||
type templateVars struct {
|
||||
Message string
|
||||
WaitTime string
|
||||
Hostname string
|
||||
@@ -40,20 +33,13 @@ type iPxeTemplate struct {
|
||||
KernelOverride string
|
||||
}
|
||||
|
||||
var status_stages = map[string]string{
|
||||
"ipxe": "IPXE",
|
||||
"kernel": "KERNEL",
|
||||
"kmods": "KMODS_OVERLAY",
|
||||
"system": "SYSTEM_OVERLAY",
|
||||
"runtime": "RUNTIME_OVERLAY"}
|
||||
|
||||
func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
wwlog.Debug("Requested URL: %s", req.URL.String())
|
||||
conf := warewulfconf.Get()
|
||||
|
||||
rinfo, err := parseReq(req)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
wwlog.ErrorExc(err, "")
|
||||
wwlog.ErrorExc(err, "Bad status")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -67,6 +53,14 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
status_stages := map[string]string{
|
||||
"efiboot": "EFI",
|
||||
"ipxe": "IPXE",
|
||||
"kernel": "KERNEL",
|
||||
"kmods": "KMODS_OVERLAY",
|
||||
"system": "SYSTEM_OVERLAY",
|
||||
"runtime": "RUNTIME_OVERLAY"}
|
||||
|
||||
status_stage := status_stages[rinfo.stage]
|
||||
var stage_file string
|
||||
|
||||
@@ -91,26 +85,13 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
wwlog.Error("%s (unknown/unconfigured node)", rinfo.hwaddr)
|
||||
if rinfo.stage == "ipxe" {
|
||||
stage_file = path.Join(conf.Paths.Sysconfdir, "/warewulf/ipxe/unconfigured.ipxe")
|
||||
tmpl_data = iPxeTemplate{
|
||||
tmpl_data = templateVars{
|
||||
Hwaddr: rinfo.hwaddr}
|
||||
}
|
||||
|
||||
} else if rinfo.stage == "ipxe" {
|
||||
stage_file = path.Join(conf.Paths.Sysconfdir, "warewulf/ipxe/"+node.Ipxe.Get()+".ipxe")
|
||||
tmpl_data = iPxeTemplate{
|
||||
Id: node.Id.Get(),
|
||||
Cluster: node.ClusterName.Get(),
|
||||
Fqdn: node.Id.Get(),
|
||||
Ipaddr: conf.Ipaddr,
|
||||
Port: strconv.Itoa(conf.Warewulf.Port),
|
||||
Hostname: node.Id.Get(),
|
||||
Hwaddr: rinfo.hwaddr,
|
||||
ContainerName: node.ContainerName.Get(),
|
||||
KernelArgs: node.Kernel.Args.Get(),
|
||||
KernelOverride: node.Kernel.Override.Get()}
|
||||
} else if rinfo.stage == "grub.cfg" {
|
||||
stage_file = path.Join(conf.Paths.Sysconfdir, "warewulf/grub/"+node.Grub.Get()+".ipxe")
|
||||
tmpl_data = iPxeTemplate{
|
||||
tmpl_data = templateVars{
|
||||
Id: node.Id.Get(),
|
||||
Cluster: node.ClusterName.Get(),
|
||||
Fqdn: node.Id.Get(),
|
||||
@@ -157,7 +138,6 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
} else {
|
||||
context = rinfo.stage
|
||||
}
|
||||
|
||||
stage_file, err = getOverlayFile(
|
||||
node,
|
||||
context,
|
||||
@@ -174,6 +154,45 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
wwlog.ErrorExc(err, "")
|
||||
return
|
||||
}
|
||||
} else if rinfo.stage == "efiboot" {
|
||||
wwlog.Debug("requested method: %s", req.Method)
|
||||
containerName := node.ContainerName.Get()
|
||||
switch rinfo.efifile {
|
||||
case "shim.efi":
|
||||
stage_file = container.ShimFind(containerName)
|
||||
if stage_file == "" {
|
||||
wwlog.ErrorExc(fmt.Errorf("could't find shim.efi"), containerName)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
case "grub.efi", "grub-tpm.efi", "grubx64.efi", "grubia32.efi", "grubaa64.efi", "grubarm.efi":
|
||||
stage_file = container.GrubFind(containerName)
|
||||
if stage_file == "" {
|
||||
wwlog.ErrorExc(fmt.Errorf("could't find grub.efi"), containerName)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
case "grub.cfg":
|
||||
stage_file = path.Join(conf.Paths.Sysconfdir, "warewulf/grub/grub.cfg.ww")
|
||||
tmpl_data = templateVars{
|
||||
Id: node.Id.Get(),
|
||||
Cluster: node.ClusterName.Get(),
|
||||
Fqdn: node.Id.Get(),
|
||||
Ipaddr: conf.Ipaddr,
|
||||
Port: strconv.Itoa(conf.Warewulf.Port),
|
||||
Hostname: node.Id.Get(),
|
||||
Hwaddr: rinfo.hwaddr,
|
||||
ContainerName: node.ContainerName.Get(),
|
||||
KernelArgs: node.Kernel.Args.Get(),
|
||||
KernelOverride: node.Kernel.Override.Get()}
|
||||
if stage_file == "" {
|
||||
wwlog.ErrorExc(fmt.Errorf("could't find grub.cfg template"), containerName)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
default:
|
||||
wwlog.ErrorExc(fmt.Errorf("could't find efiboot file: %s", rinfo.efifile), "")
|
||||
}
|
||||
} else if rinfo.stage == "shim" {
|
||||
if node.ContainerName.Defined() {
|
||||
stage_file = container.ShimFind(node.ContainerName.Get())
|
||||
@@ -270,109 +289,3 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
simple handler for sending only out grub to the nodes, parses the
|
||||
GET request, so that for "/grub/shim.efi" the "shim.efi" from the
|
||||
container of the default profile will be sent and for "/grub/shim.efi?$container" the
|
||||
shim of $container will be sent
|
||||
*/
|
||||
func GrubSend(w http.ResponseWriter, req *http.Request) {
|
||||
req.Close = true
|
||||
wwlog.Debug("Grub send called with url: %s host: %s", req.URL, req.Host)
|
||||
url := strings.Split(req.URL.Path, "?")[0]
|
||||
path_parts := strings.Split(path.Join(url), "/")
|
||||
remoteIP := strings.Split(req.RemoteAddr, ":")[0]
|
||||
mu.Lock()
|
||||
if last_sent, ok := sentMap[remoteIP]; ok {
|
||||
wwlog.Debug("last sent is: %s", last_sent)
|
||||
}
|
||||
mu.Unlock()
|
||||
if len(path_parts) != 3 {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
wwlog.ErrorExc(fmt.Errorf("unknown path components in GET: %s", req.URL.Path), remoteIP)
|
||||
return
|
||||
}
|
||||
requested_file := path_parts[2]
|
||||
nodeDB, err := node.New()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
profiles, _ := nodeDB.MapAllProfiles()
|
||||
containerName := ""
|
||||
if profile, ok := profiles["default"]; ok {
|
||||
containerName = profile.ContainerName.Get()
|
||||
}
|
||||
remoteNode, err := nodeDB.FindByIpaddr(remoteIP)
|
||||
if err == nil {
|
||||
containerName = remoteNode.ContainerName.Get()
|
||||
} else {
|
||||
if mac := ArpFind(remoteIP); mac != "" {
|
||||
remoteNode, err := nodeDB.FindByHwaddr(mac)
|
||||
if err != nil {
|
||||
containerName = remoteNode.ContainerName.Get()
|
||||
} else if remoteNode, err = GetNodeOrSetDiscoverable(mac); err == nil {
|
||||
containerName = remoteNode.ContainerName.Get()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(url) == 2 {
|
||||
containerName = strings.Split(req.URL.Path, "?")[1]
|
||||
}
|
||||
mu.Lock()
|
||||
if last_sent, ok := sentMap[remoteIP]; ok && last_sent == "shim.efi" {
|
||||
requested_file = "grub.efi"
|
||||
}
|
||||
mu.Unlock()
|
||||
wwlog.Recv("remoteIP: %s, container: %s, filename: %s", remoteIP, containerName, requested_file)
|
||||
var stage_file string
|
||||
switch requested_file {
|
||||
case "shim.efi":
|
||||
stage_file = container.ShimFind(containerName)
|
||||
if stage_file == "" {
|
||||
wwlog.ErrorExc(fmt.Errorf("could't find shim.efi"), containerName)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
mu.Lock()
|
||||
sentMap[remoteIP] = "shim.efi"
|
||||
mu.Unlock()
|
||||
case "grub.efi", "grubx86.efi":
|
||||
stage_file = container.GrubFind(containerName)
|
||||
if stage_file == "" {
|
||||
wwlog.ErrorExc(fmt.Errorf("could't find grub.efi"), containerName)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
mu.Lock()
|
||||
sentMap[remoteIP] = "grub.efi"
|
||||
mu.Unlock()
|
||||
}
|
||||
wwlog.Serv("stage_file '%s'", stage_file)
|
||||
|
||||
if util.IsFile(stage_file) {
|
||||
/*
|
||||
fd, err := os.Open(stage_file)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer fd.Close()
|
||||
*/
|
||||
/*
|
||||
stat, err := fd.Stat()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.ServeContent(w, req, stage_file, stat.ModTime(), fd)
|
||||
io.Copy(w, fd)
|
||||
req.Close = true
|
||||
*/
|
||||
http.ServeFile(w, req, stage_file)
|
||||
wwlog.Send("%15s: %s", remoteIP, stage_file)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ func sendFile(
|
||||
fd)
|
||||
|
||||
wwlog.Send("%15s: %s", sendto, filename)
|
||||
|
||||
req.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||
@@ -14,6 +15,21 @@ import (
|
||||
|
||||
// TODO: https://github.com/danderson/netboot/blob/master/pixiecore/dhcp.go
|
||||
// TODO: https://github.com/pin/tftp
|
||||
/*
|
||||
wrapper type for the server mux as him requests http://efiboot//grub.efi which is filtered out by http to `301 Moved Permanently` which
|
||||
which shim.fi can't handle. So filter out `//` before they hit http
|
||||
*/
|
||||
type slashFix struct {
|
||||
mux http.Handler
|
||||
}
|
||||
|
||||
/*
|
||||
Filter out the '//'
|
||||
*/
|
||||
func (h *slashFix) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
r.URL.Path = strings.Replace(r.URL.Path, "//", "/", -1)
|
||||
h.mux.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func RunServer() error {
|
||||
err := DaemonInitLogging()
|
||||
@@ -53,23 +69,33 @@ func RunServer() error {
|
||||
if err != nil {
|
||||
wwlog.Warn("couldn't copy default shim: %s", err)
|
||||
}
|
||||
|
||||
http.HandleFunc("/provision/", ProvisionSend)
|
||||
http.HandleFunc("/ipxe/", ProvisionSend)
|
||||
http.HandleFunc("/grub/", GrubSend)
|
||||
http.HandleFunc("/kernel/", ProvisionSend)
|
||||
http.HandleFunc("/kmods/", ProvisionSend)
|
||||
http.HandleFunc("/container/", ProvisionSend)
|
||||
http.HandleFunc("/overlay-system/", ProvisionSend)
|
||||
http.HandleFunc("/overlay-runtime/", ProvisionSend)
|
||||
http.HandleFunc("/status", StatusSend)
|
||||
var wwHandler http.ServeMux
|
||||
wwHandler.HandleFunc("/provision/", ProvisionSend)
|
||||
wwHandler.HandleFunc("/ipxe/", ProvisionSend)
|
||||
wwHandler.HandleFunc("/efiboot/", ProvisionSend)
|
||||
wwHandler.HandleFunc("/kernel/", ProvisionSend)
|
||||
wwHandler.HandleFunc("/kmods/", ProvisionSend)
|
||||
wwHandler.HandleFunc("/container/", ProvisionSend)
|
||||
wwHandler.HandleFunc("/overlay-system/", ProvisionSend)
|
||||
wwHandler.HandleFunc("/overlay-runtime/", ProvisionSend)
|
||||
wwHandler.HandleFunc("/status", StatusSend)
|
||||
|
||||
conf := warewulfconf.Get()
|
||||
|
||||
daemonPort := conf.Warewulf.Port
|
||||
wwlog.Serv("Starting HTTPD REST service on port %d", daemonPort)
|
||||
/*
|
||||
wwlog.Serv("Starting HTTPD REST service on port %d", daemonPort)
|
||||
s := &http.Server{
|
||||
Addr: ":" + strconv.Itoa(daemonPort),
|
||||
Handler: &slashFix{&wwHandler},
|
||||
ReadTimeout: 10 * time.Second,
|
||||
IdleTimeout: 10 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
}
|
||||
err = s.ListenAndServe()
|
||||
*/
|
||||
err = http.ListenAndServe(":"+strconv.Itoa(daemonPort), &slashFix{&wwHandler})
|
||||
|
||||
err = http.ListenAndServe(":"+strconv.Itoa(daemonPort), nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not start listening service")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user