enable grub boot for all nodes

Signed-off-by: Christian Goll <cgoll@suse.com>
This commit is contained in:
Christian Goll
2023-07-25 15:19:16 +02:00
committed by Jonathon Anderson
parent 03ef7447e9
commit 60dc8f6251
8 changed files with 191 additions and 39 deletions

View File

@@ -28,7 +28,7 @@ func shimNames() []string {
find the path of the shim binary
*/
func ShimFind(container string) string {
wwlog.Debug("Finding shim")
wwlog.Debug("Finding shim for container %s", container)
container_path := RootFsDir(container)
if container_path == "" {
return ""

View File

@@ -6,6 +6,9 @@ import (
"strings"
)
/*
get node by its hardware/MAC address, return error otherwise
*/
func (config *NodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) {
if _, err := net.ParseMAC(hwa); err != nil {
return NodeInfo{}, errors.New("invalid hardware address: " + hwa)
@@ -26,6 +29,9 @@ func (config *NodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) {
return ret, errors.New("No nodes found with HW Addr: " + hwa)
}
/*
get node by its ip address, return error otherwise
*/
func (config *NodeYaml) FindByIpaddr(ipaddr string) (NodeInfo, error) {
if addr := net.ParseIP(ipaddr); addr == nil {
return NodeInfo{}, errors.New("invalid IP:" + ipaddr)

View File

@@ -34,6 +34,7 @@ type TemplateStruct struct {
Tftp warewulfconf.TFTPConf
Paths warewulfconf.BuildConfig
AllNodes []node.NodeInfo
ProfileMap map[string]*node.NodeInfo
node.NodeConf
// backward compatiblity
Container string
@@ -49,19 +50,19 @@ func InitStruct(nodeInfo *node.NodeInfo) TemplateStruct {
controller := warewulfconf.Get()
nodeDB, err := node.New()
if err != nil {
wwlog.Error("%s", err)
os.Exit(1)
wwlog.Warn("Problems opening nodes.conf: %s", err)
}
allNodes, err := nodeDB.FindAllNodes()
tstruct.AllNodes, err = nodeDB.FindAllNodes()
if err != nil {
wwlog.Error("%s", err)
os.Exit(1)
wwlog.Warn("couldn't get all nodes: %s", err)
}
tstruct.ProfileMap, err = nodeDB.MapAllProfiles()
if err != nil {
wwlog.Warn("couldn't get all profiles: %s", err)
}
// init some convenience vars
tstruct.Id = nodeInfo.Id.Get()
tstruct.Hostname = nodeInfo.Id.Get()
// Backwards compatibility for templates using "Keys"
tstruct.AllNodes = allNodes
tstruct.Nfs = *controller.NFS
tstruct.Dhcp = *controller.DHCP
tstruct.Tftp = *controller.TFTP

View File

@@ -3,20 +3,28 @@ package warewulfd
import (
"bytes"
"errors"
"fmt"
"net/http"
"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 {
Message string
WaitTime string
@@ -262,3 +270,109 @@ 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)
}
}

View File

@@ -1,8 +1,10 @@
package warewulfd
import (
"bufio"
"net/http"
"os"
"strings"
"github.com/hpcng/warewulf/internal/pkg/node"
nodepkg "github.com/hpcng/warewulf/internal/pkg/node"
@@ -70,3 +72,25 @@ func getOverlayFile(
return
}
/*
returns the mac address if it has an entry in the arp cache
*/
func ArpFind(ip string) (mac string) {
arpCache, err := os.Open("/proc/net/arp")
if err != nil {
return
}
defer arpCache.Close()
scanner := bufio.NewScanner(arpCache)
scanner.Scan()
for scanner.Scan() {
fields := strings.Fields(scanner.Text())
if strings.EqualFold(fields[0], ip) {
return fields[3]
}
}
return
}

View File

@@ -56,6 +56,7 @@ func RunServer() error {
http.HandleFunc("/provision/", ProvisionSend)
http.HandleFunc("/ipxe/", ProvisionSend)
http.HandleFunc("/grub/", GrubSend)
http.HandleFunc("/kernel/", ProvisionSend)
http.HandleFunc("/kmods/", ProvisionSend)
http.HandleFunc("/container/", ProvisionSend)