enable grub boot for all nodes
Signed-off-by: Christian Goll <cgoll@suse.com>
This commit is contained in:
committed by
Jonathon Anderson
parent
03ef7447e9
commit
60dc8f6251
2
Makefile
2
Makefile
@@ -96,6 +96,7 @@ install: build docs
|
||||
install -d -m 0755 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/$(WWCLIENTDIR)
|
||||
install -d -m 0755 $(DESTDIR)$(WWCONFIGDIR)/examples
|
||||
install -d -m 0755 $(DESTDIR)$(WWCONFIGDIR)/ipxe
|
||||
install -d -m 0755 $(DESTDIR)$(WWCONFIGDIR)/grub
|
||||
install -d -m 0755 $(DESTDIR)$(BASHCOMPDIR)
|
||||
install -d -m 0755 $(DESTDIR)$(MANDIR)/man1
|
||||
install -d -m 0755 $(DESTDIR)$(MANDIR)/man5
|
||||
@@ -112,6 +113,7 @@ install: build docs
|
||||
test -f $(DESTDIR)$(DATADIR)/warewulf/defaults.conf || install -m 0644 etc/defaults.conf $(DESTDIR)$(DATADIR)/warewulf/defaults.conf
|
||||
for f in etc/examples/*.ww; do install -m 0644 $$f $(DESTDIR)$(WWCONFIGDIR)/examples/; done
|
||||
for f in etc/ipxe/*.ipxe; do install -m 0644 $$f $(DESTDIR)$(WWCONFIGDIR)/ipxe/; done
|
||||
for f in etc/grub/*; do install -m 0644 $$f $(DESTDIR)$(WWCONFIGDIR)/grub/; done
|
||||
(cd overlays && find * -type f -exec install -D -m 0644 {} $(DESTDIR)$(WWOVERLAYDIR)/{} \;)
|
||||
(cd overlays && find * -type d -exec mkdir -pv $(DESTDIR)$(WWOVERLAYDIR)/{} \;)
|
||||
(cd overlays && find * -type l -exec cp -av {} $(DESTDIR)$(WWOVERLAYDIR)/{} \;)
|
||||
|
||||
@@ -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 ""
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{{if .Dhcp.Enabled -}}
|
||||
{{if $.Dhcp.Enabled -}}
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{.BuildHost}}
|
||||
# Time: {{.BuildTime}}
|
||||
@@ -15,52 +15,56 @@ option space ipxe;
|
||||
option ipxe.no-pxedhcp code 176 = unsigned integer 8;
|
||||
option ipxe.no-pxedhcp 1;
|
||||
|
||||
option space PXE;
|
||||
option PXE.mtftp-ip code 1 = ip-address;
|
||||
option PXE.mtftp-cport code 2 = unsigned integer 16;
|
||||
option PXE.mtftp-sport code 3 = unsigned integer 16;
|
||||
option PXE.mtftp-tmout code 4 = unsigned integer 8;
|
||||
option PXE.mtftp-delay code 5 = unsigned integer 8;
|
||||
|
||||
option architecture-type code 93 = unsigned integer 16;
|
||||
|
||||
{{- if eq $.ProfileMap.default.BootMethod.Get "grub" }}
|
||||
if substring (option vendor-class-identifier, 0, 9) = "PXEClient" {
|
||||
next-server {{ $.Ipaddr }};
|
||||
filename "warewulf/shim.efi";
|
||||
} elsif substring (option vendor-class-identifier, 0, 10) = "HTTPClient" {
|
||||
filename "http://{{$.Ipaddr}}:{{$.Warewulf.Port}}/grub/shim.efi";
|
||||
}
|
||||
{{- else }}
|
||||
if exists user-class and option user-class = "iPXE" {
|
||||
filename "http://{{$.Ipaddr}}:{{$.Warewulf.Port}}/ipxe/${mac:hexhyp}";
|
||||
} else {
|
||||
{{- if .BoothMethod == "ipxe" }}
|
||||
{{range $type,$name := $.Tftp.IpxeBinaries }}
|
||||
if option architecture-type = {{ $type }} {
|
||||
filename "/warewulf/{{ basename $name }}";
|
||||
}
|
||||
{{- end }}{{/* range IpxeBinaries */}}
|
||||
{{ else }}
|
||||
filename "warewulf/shim.efi"
|
||||
}
|
||||
{{- end }}{{/* BootMethod */}}
|
||||
}
|
||||
|
||||
{{if eq .Dhcp.Template "static" -}}
|
||||
subnet {{$.Network}} netmask {{$.Netmask}} {
|
||||
next-server {{$.Ipaddr}};
|
||||
max-lease-time 120;
|
||||
range {{$.Dhcp.RangeStart}} {{$.Dhcp.RangeEnd}};
|
||||
next-server {{.Ipaddr}};
|
||||
}
|
||||
{{range $nodes := .AllNodes}}
|
||||
{{- range $nodes := $.AllNodes}}
|
||||
{{- range $netname, $netdevs := $nodes.NetDevs}}
|
||||
host {{$nodes.Id.Get}}-{{if $netdevs.Device.Defined}}{{$netdevs.Device.Get}}{{else}}{{$netname}}{{end}} {
|
||||
host {{$nodes.Id.Get}}-{{$netdevs.Device.Get}}
|
||||
{
|
||||
{{- if $netdevs.Primary.GetB}}
|
||||
{{- if $netdevs.Hwaddr.Defined}}
|
||||
hardware ethernet {{$netdevs.Hwaddr.Get}};
|
||||
{{- end }}
|
||||
{{- if $netdevs.Ipaddr.Defined}}
|
||||
fixed-address {{$netdevs.Ipaddr.Get}};
|
||||
{{- end }}
|
||||
{{- if $netdevs.Primary.GetB}}
|
||||
option host-name "{{$nodes.Id.Get}}";
|
||||
{{else}}
|
||||
option host-name "{{$nodes.Id.Get}}-{{if $netdevs.Device.Defined}}{{$netdevs.Device.Get}}{{else}}{{$netname}}{{end}}";
|
||||
{{- end }}
|
||||
}
|
||||
{{end -}}
|
||||
{{end -}}
|
||||
|
||||
{{else -}}
|
||||
subnet {{$.Network}} netmask {{$.Netmask}} {
|
||||
max-lease-time 120;
|
||||
range {{$.Dhcp.RangeStart}} {{$.Dhcp.RangeEnd}};
|
||||
next-server {{$.Ipaddr}};
|
||||
}
|
||||
{{end}}
|
||||
{{end -}}{{/* range NetDevs */}}
|
||||
{{end -}}{{/* range AllNodes */}}
|
||||
|
||||
{{- else}}
|
||||
{{abort}}
|
||||
{{- end}}
|
||||
{{- end}}{{/* dhcp enabled */}}
|
||||
|
||||
Reference in New Issue
Block a user