Initial commit of asset key tag security check

This commit is contained in:
Gregory Kurtzer
2022-01-24 00:32:02 +00:00
parent b038a8817b
commit d9c13c3f36
21 changed files with 320 additions and 212 deletions

27
etc/ipxe/arm_image.ipxe Normal file
View File

@@ -0,0 +1,27 @@
#!ipxe
echo
echo ================================================================================
echo Warewulf v4 now booting: {{.Fqdn}}
echo
echo Container: {{.ContainerName}}
echo Kernel: {{.KernelVersion}}
echo KernelArgs: {{.KernelArgs}}
echo
set base http://{{.Ipaddr}}:{{.Port}}
kernel --name kernel ${base}/kernel/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot
initrd --name container ${base}/container/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot
initrd --name kmods ${base}/kmods/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot
initrd --name system ${base}/overlay-system/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot
initrd --name runtime ${base}/overlay-runtime/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot
boot kernel initrd=container initrd=kmods initrd=system initrd=runtime {{.KernelArgs}} || goto reboot
:reboot
echo
echo There was an error, rebooting in 15s...
echo
sleep 15
reboot

View File

@@ -1,26 +0,0 @@
#!ipxe
echo
echo ================================================================================
echo Warewulf v4 now booting: {{.Fqdn}}
echo
echo Container: {{.ContainerName}}
echo Kernel: {{.KernelVersion}}
echo KernelArgs: {{.KernelArgs}}
echo
set base http://{{.Ipaddr}}:{{.Port}}
kernel --name kernel ${base}/kernel/{{.Hwaddr}} || goto reboot
imgextract --name container ${base}/container/{{.Hwaddr}} || goto reboot
imgextract --name kmods ${base}/kmods/{{.Hwaddr}} || goto reboot
imgextract --name system ${base}/overlay-system/{{.Hwaddr}} || goto reboot
boot kernel initrd=container initrd=kmods initrd=system {{.KernelArgs}} || goto reboot
:reboot
echo
echo There was an error, rebooting in 15s...
echo
sleep 15
reboot

View File

@@ -11,11 +11,11 @@ echo
set base http://{{.Ipaddr}}:{{.Port}}
kernel --name kernel ${base}/kernel/{{.Hwaddr}} || goto reboot
initrd --name container ${base}/container/{{.Hwaddr}} || goto reboot
initrd --name kmods ${base}/kmods/{{.Hwaddr}} || goto reboot
initrd --name system ${base}/overlay-system/{{.Hwaddr}} || goto reboot
initrd --name runtime ${base}/overlay-runtime/{{.Hwaddr}} || goto reboot
kernel --name kernel ${base}/kernel/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot
imgextract --name container ${base}/container/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot
imgextract --name kmods ${base}/kmods/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot
imgextract --name system ${base}/overlay-system/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot
imgextract --name runtime ${base}/overlay-runtime/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} || goto reboot
boot kernel initrd=container initrd=kmods initrd=system initrd=runtime {{.KernelArgs}} || goto reboot

View File

@@ -48,6 +48,8 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "Ipxe", node.Ipxe.Source(), node.Ipxe.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "Init", node.Init.Source(), node.Init.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "Root", node.Root.Source(), node.Root.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "AssetKey", node.AssetKey.Source(), node.AssetKey.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiIpaddr", node.IpmiIpaddr.Source(), node.IpmiIpaddr.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiNetmask", node.IpmiNetmask.Source(), node.IpmiNetmask.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiPort", node.IpmiPort.Source(), node.IpmiPort.Print())

View File

@@ -70,6 +70,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
n.Root.Set(SetRoot)
}
if SetAssetKey != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting asset key to: %s\n", n.Id.Get(), SetAssetKey)
n.AssetKey.Set(SetAssetKey)
}
if SetKernel != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting kernel to: %s\n", n.Id.Get(), SetKernel)
n.KernelVersion.Set(SetKernel)

View File

@@ -71,6 +71,7 @@ var (
SetKey string
SetValue string
SetKeyDel bool
SetAssetKey string
)
func init() {
@@ -94,6 +95,7 @@ func init() {
baseCmd.PersistentFlags().StringVar(&SetIpxe, "ipxe", "", "Set the node's iPXE template name")
baseCmd.PersistentFlags().StringVarP(&SetInit, "init", "i", "", "Define the init process to boot the container")
baseCmd.PersistentFlags().StringVar(&SetRoot, "root", "", "Define the rootfs")
baseCmd.PersistentFlags().StringVar(&SetAssetKey, "assetkey", "", "Set the node's Asset tag (key)")
baseCmd.PersistentFlags().StringVarP(&SetInitOverlay, "wwinit", "O", "", "Set the node's initialization overlay")
baseCmd.PersistentFlags().StringVarP(&SetRuntimeOverlay, "runtime", "R", "", "Set the node's runtime overlay")
if err := baseCmd.RegisterFlagCompletionFunc("runtime", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {

View File

@@ -37,6 +37,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "KernelArgs", profile.KernelArgs.Print())
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "Init", profile.Init.Print())
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "Root", profile.Root.Print())
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "AssetKey", profile.AssetKey.Print())
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "SystemOverlay", profile.SystemOverlay.Print())
fmt.Printf("%-20s %-18s %s\n", profile.Id.Get(), "RuntimeOverlay", profile.RuntimeOverlay.Print())

View File

@@ -70,6 +70,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
p.Root.Set(SetRoot)
}
if SetAssetKey != "" {
wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting asset key to: %s\n", p.Id.Get(), SetAssetKey)
p.AssetKey.Set(SetAssetKey)
}
if SetKernel != "" {
wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting Kernel to: %s\n", p.Id.Get(), SetKernel)
p.KernelVersion.Set(SetKernel)

View File

@@ -67,6 +67,7 @@ var (
SetKey string
SetValue string
SetKeyDel bool
SetAssetKey string
)
func init() {
@@ -90,6 +91,7 @@ func init() {
baseCmd.PersistentFlags().StringVarP(&SetIpxe, "ipxe", "P", "", "Set the node's iPXE template name")
baseCmd.PersistentFlags().StringVarP(&SetInit, "init", "i", "", "Define the init process to boot the container")
baseCmd.PersistentFlags().StringVar(&SetRoot, "root", "", "Define the rootfs")
baseCmd.PersistentFlags().StringVar(&SetAssetKey, "assetkey", "", "Set the node's Asset tag (key)")
baseCmd.PersistentFlags().StringVarP(&SetRuntimeOverlay, "runtime", "R", "", "Set the node's runtime overlay")
if err := baseCmd.RegisterFlagCompletionFunc("runtime", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {

View File

@@ -87,6 +87,7 @@ func (config *nodeYaml) FindAllNodes() ([]NodeInfo, error) {
n.SystemOverlay.Set(node.SystemOverlay)
n.RuntimeOverlay.Set(node.RuntimeOverlay)
n.Root.Set(node.Root)
n.AssetKey.Set(node.AssetKey)
n.Discoverable.SetB(node.Discoverable)
@@ -142,11 +143,11 @@ func (config *nodeYaml) FindAllNodes() ([]NodeInfo, error) {
n.IpmiInterface.SetAlt(config.NodeProfiles[p].IpmiInterface, p)
n.SystemOverlay.SetAlt(config.NodeProfiles[p].SystemOverlay, p)
n.RuntimeOverlay.SetAlt(config.NodeProfiles[p].RuntimeOverlay, p)
n.Root.SetAlt(config.NodeProfiles[p].Root, p)
n.AssetKey.SetAlt(config.NodeProfiles[p].AssetKey, p)
n.Discoverable.SetAltB(config.NodeProfiles[p].Discoverable, p)
n.Root.SetAlt(config.NodeProfiles[p].Root, p)
for devname, netdev := range config.NodeProfiles[p].NetDevs {
if _, ok := n.NetDevs[devname]; !ok {
var netdev NetDevEntry
@@ -216,6 +217,7 @@ func (config *nodeYaml) FindAllProfiles() ([]NodeInfo, error) {
p.RuntimeOverlay.Set(profile.RuntimeOverlay)
p.SystemOverlay.Set(profile.SystemOverlay)
p.Root.Set(profile.Root)
p.AssetKey.Set(profile.AssetKey)
p.Discoverable.SetB(profile.Discoverable)

View File

@@ -32,6 +32,7 @@ type NodeConf struct {
SystemOverlay string `yaml:"system overlay,omitempty"`
Init string `yaml:"init,omitempty"`
Root string `yaml:"root,omitempty"`
AssetKey string `yaml:"asset key,omitempty"`
Discoverable bool `yaml:"discoverable,omitempty"`
Profiles []string `yaml:"profiles,omitempty"`
NetDevs map[string]*NetDevs `yaml:"network devices,omitempty"`
@@ -85,6 +86,7 @@ type NodeInfo struct {
Root Entry
Discoverable Entry
Init Entry //TODO: Finish adding this...
AssetKey Entry
Profiles []string
GroupProfiles []string
NetDevs map[string]*NetDevEntry

View File

@@ -72,6 +72,7 @@ func (config *nodeYaml) NodeUpdate(node NodeInfo) error {
config.Nodes[nodeID].RuntimeOverlay = node.RuntimeOverlay.GetReal()
config.Nodes[nodeID].SystemOverlay = node.SystemOverlay.GetReal()
config.Nodes[nodeID].Root = node.Root.GetReal()
config.Nodes[nodeID].AssetKey = node.AssetKey.GetReal()
config.Nodes[nodeID].Discoverable = node.Discoverable.GetRealB()
@@ -159,6 +160,7 @@ func (config *nodeYaml) ProfileUpdate(profile NodeInfo) error {
config.NodeProfiles[profileID].RuntimeOverlay = profile.RuntimeOverlay.GetReal()
config.NodeProfiles[profileID].SystemOverlay = profile.SystemOverlay.GetReal()
config.NodeProfiles[profileID].Root = profile.Root.GetReal()
config.NodeProfiles[profileID].AssetKey = profile.AssetKey.GetReal()
config.NodeProfiles[profileID].Discoverable = profile.Discoverable.GetRealB()

View File

@@ -8,12 +8,25 @@ import (
)
func ContainerSend(w http.ResponseWriter, req *http.Request) {
node, err := getSanity(req)
rinfo, err := parseReq(req)
if err != nil {
w.WriteHeader(404)
daemonLogf("ERROR: %s\n", err)
return
}
node, err := GetNode(rinfo.hwaddr)
if err != nil {
w.WriteHeader(403)
daemonLogf("ERROR(%s): %s\n", rinfo.hwaddr, err)
return
}
if node.AssetKey.Defined() && node.AssetKey.Get() != rinfo.assetkey {
w.WriteHeader(404)
daemonLogf("ERROR: Incorrect asset key for node: %s\n", node.Id.Get())
updateStatus(node.Id.Get(), "CONTAINER", "BAD_ASSET", rinfo.ipaddr)
return
}
if node.ContainerName.Defined() {
containerImage := container.ImageFile(node.ContainerName.Get())

View File

@@ -3,13 +3,17 @@ package warewulfd
import (
"fmt"
"io/ioutil"
"log"
"log/syslog"
"os"
"os/exec"
"strconv"
"syscall"
"time"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/version"
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
"github.com/pkg/errors"
)
@@ -18,6 +22,39 @@ const (
WAREWULFD_LOGFILE = "/var/log/warewulfd.log"
)
var logwriter *syslog.Writer
var loginit bool
func daemonLogf(message string, a ...interface{}) {
conf, err := warewulfconf.New()
if err != nil {
fmt.Printf("ERROR: Could not read Warewulf configuration file: %s\n", err)
return
}
if conf.Warewulf.Syslog {
if !loginit {
var err error
logwriter, err = syslog.New(syslog.LOG_NOTICE, "warewulfd")
if err != nil {
return
}
log.SetOutput(logwriter)
loginit = true
log.SetFlags(0)
log.SetPrefix("")
}
log.Printf(message, a...)
} else {
prefix := fmt.Sprintf("[%s] ", time.Now().Format(time.UnixDate))
fmt.Printf(prefix+message, a...)
}
}
func DaemonStart() error {
if os.Getenv("WAREWULFD_BACKGROUND") == "1" {
err := RunServer()

View File

@@ -8,7 +8,7 @@ import (
"text/template"
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
"github.com/hpcng/warewulf/internal/pkg/node"
nodepkg "github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/overlay"
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
@@ -30,18 +30,6 @@ type iPxeTemplate struct {
}
func IpxeSend(w http.ResponseWriter, req *http.Request) {
url := strings.Split(req.URL.Path, "/")
var unconfiguredNode bool
if url[2] == "" {
daemonLogf("ERROR: Bad iPXE request from %s\n", req.RemoteAddr)
w.WriteHeader(404)
return
}
hwaddr := strings.ReplaceAll(url[2], "-", ":")
conf, err := warewulfconf.New()
if err != nil {
daemonLogf("ERROR: Could not open Warewulf configuration: %s\n", err)
@@ -49,44 +37,51 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) {
return
}
nodeobj, err := GetNode(hwaddr)
rinfo, err := parseReq(req)
if err != nil {
w.WriteHeader(404)
daemonLogf("ERROR: %s\n", err)
return
}
node, err := GetNode(rinfo.hwaddr)
if err != nil {
// If we failed to find a node, let's see if we can add one...
var netdev string
var unconfiguredNode bool
nodeDB, err := node.New()
daemonLogf("IPXEREQ: %s (node not configured)\n", rinfo.hwaddr)
nodeDB, err := nodepkg.New()
if err != nil {
daemonLogf("Could not read node configuration file: %s\n", err)
w.WriteHeader(503)
return
}
daemonLogf("IPXEREQ: %s (node not configured)\n", hwaddr)
n, netdev, err := nodeDB.FindDiscoverableNode()
if err != nil {
unconfiguredNode = true
} else {
n.NetDevs[netdev].Hwaddr.Set(hwaddr)
n.NetDevs[netdev].Hwaddr.Set(rinfo.hwaddr)
n.Discoverable.SetB(false)
err := nodeDB.NodeUpdate(n)
if err != nil {
daemonLogf("IPXEREQ: %s (failed to set node configuration)\n", hwaddr)
daemonLogf("IPXEREQ: %s (failed to set node configuration)\n", rinfo.hwaddr)
unconfiguredNode = true
} else {
err := nodeDB.Persist()
if err != nil {
daemonLogf("IPXEREQ: %s (failed to persist node configuration)\n", hwaddr)
daemonLogf("IPXEREQ: %s (failed to persist node configuration)\n", rinfo.hwaddr)
unconfiguredNode = true
} else {
nodeobj = n
_ = overlay.BuildAllOverlays([]node.NodeInfo{n})
node = n
_ = overlay.BuildAllOverlays([]nodepkg.NodeInfo{n})
daemonLogf("IPXEREQ: %s (node automatically configured)\n", hwaddr)
daemonLogf("IPXEREQ: %s (node automatically configured)\n", rinfo.hwaddr)
err := LoadNodeDB()
if err != nil {
@@ -96,10 +91,8 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) {
}
}
}
}
if unconfiguredNode {
daemonLogf("IPXEREQ: %s (unknown/unconfigured node)\n", hwaddr)
daemonLogf("IPXEREQ: %s (unknown/unconfigured node)\n", rinfo.hwaddr)
tmpl, err := template.ParseFiles(path.Join(buildconfig.SYSCONFDIR(), "/warewulf/ipxe/unconfigured.ipxe"))
if err != nil {
@@ -109,7 +102,7 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) {
var replace iPxeTemplate
replace.Hwaddr = hwaddr
replace.Hwaddr = rinfo.hwaddr
err = tmpl.Execute(w, replace)
if err != nil {
@@ -118,10 +111,17 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) {
}
return
}
}
} else {
if node.AssetKey.Defined() && node.AssetKey.Get() != rinfo.assetkey {
w.WriteHeader(404)
daemonLogf("ERROR: Incorrect asset key for node: %s\n", node.Id.Get())
updateStatus(node.Id.Get(), "IPXE", "BAD_ASSET", rinfo.ipaddr)
return
}
ipxeTemplate := path.Join(buildconfig.SYSCONFDIR(), "warewulf/ipxe/"+nodeobj.Ipxe.Get()+".ipxe")
ipxeTemplate := path.Join(buildconfig.SYSCONFDIR(), "warewulf/ipxe/"+node.Ipxe.Get()+".ipxe")
tmpl, err := template.ParseFiles(ipxeTemplate)
if err != nil {
@@ -131,16 +131,16 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) {
var replace iPxeTemplate
replace.Id = nodeobj.Id.Get()
replace.Cluster = nodeobj.ClusterName.Get()
replace.Fqdn = nodeobj.Id.Get()
replace.Id = node.Id.Get()
replace.Cluster = node.ClusterName.Get()
replace.Fqdn = node.Id.Get()
replace.Ipaddr = conf.Ipaddr
replace.Port = strconv.Itoa(conf.Warewulf.Port)
replace.Hostname = nodeobj.Id.Get()
replace.Hwaddr = url[2]
replace.ContainerName = nodeobj.ContainerName.Get()
replace.KernelArgs = nodeobj.KernelArgs.Get()
replace.KernelVersion = nodeobj.KernelVersion.Get()
replace.Hostname = node.Id.Get()
replace.Hwaddr = rinfo.hwaddr
replace.ContainerName = node.ContainerName.Get()
replace.KernelArgs = node.KernelArgs.Get()
replace.KernelVersion = node.KernelVersion.Get()
err = tmpl.Execute(w, replace)
if err != nil {
@@ -148,8 +148,8 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) {
return
}
daemonLogf("SEND: %15s: %s\n", nodeobj.Id.Get(), ipxeTemplate)
daemonLogf("SEND: %15s: %s\n", node.Id.Get(), ipxeTemplate)
updateStatus(node.Id.Get(), "IPXE", node.Ipxe.Get()+".ipxe", strings.Split(req.RemoteAddr, ":")[0])
updateStatus(nodeobj.Id.Get(), "IPXE_TEMPLATE", nodeobj.Ipxe.Get()+".ipxe", strings.Split(req.RemoteAddr, ":")[0])
}
}

View File

@@ -8,12 +8,25 @@ import (
)
func KernelSend(w http.ResponseWriter, req *http.Request) {
node, err := getSanity(req)
rinfo, err := parseReq(req)
if err != nil {
w.WriteHeader(404)
daemonLogf("ERROR: %s\n", err)
return
}
node, err := GetNode(rinfo.hwaddr)
if err != nil {
w.WriteHeader(403)
daemonLogf("ERROR(%s): %s\n", rinfo.hwaddr, err)
return
}
if node.AssetKey.Defined() && node.AssetKey.Get() != rinfo.assetkey {
w.WriteHeader(404)
daemonLogf("ERROR: Incorrect asset key for node: %s\n", node.Id.Get())
updateStatus(node.Id.Get(), "KERNEL", "BAD_ASSET", rinfo.ipaddr)
return
}
if node.KernelVersion.Defined() {
fileName := kernel.KernelImage(node.KernelVersion.Get())

View File

@@ -8,13 +8,25 @@ import (
)
func KmodsSend(w http.ResponseWriter, req *http.Request) {
node, err := getSanity(req)
rinfo, err := parseReq(req)
if err != nil {
w.WriteHeader(404)
daemonLogf("ERROR: %s\n", err)
return
}
node, err := GetNode(rinfo.hwaddr)
if err != nil {
w.WriteHeader(403)
daemonLogf("ERROR(%s): %s\n", rinfo.hwaddr, err)
return
}
if node.AssetKey.Defined() && node.AssetKey.Get() != rinfo.assetkey {
w.WriteHeader(404)
daemonLogf("ERROR: Incorrect asset key for node: %s\n", node.Id.Get())
updateStatus(node.Id.Get(), "KMODS_OVERLAY", "BAD_ASSET", rinfo.ipaddr)
return
}
if node.KernelVersion.Defined() {
fileName := kernel.KmodsImage(node.KernelVersion.Get())

View File

@@ -0,0 +1,50 @@
package warewulfd
import (
"net/http"
"strconv"
"strings"
"github.com/pkg/errors"
)
type parserInfo struct {
hwaddr string
ipaddr string
remoteport int
assetkey string
uuid string
}
func parseReq(req *http.Request) (parserInfo, error) {
var ret parserInfo
url := strings.Split(req.URL.Path, "?")[0]
hwaddr := strings.Split(url, "/")[2]
hwaddr = strings.ReplaceAll(hwaddr, "-", ":")
hwaddr = strings.ToUpper(hwaddr)
ret.hwaddr = hwaddr
ret.ipaddr = strings.Split(req.RemoteAddr, ":")[0]
ret.remoteport, _ = strconv.Atoi(strings.Split(req.RemoteAddr, ":")[1])
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 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
}

View File

@@ -2,16 +2,35 @@ package warewulfd
import (
"net/http"
"strconv"
"strings"
"github.com/hpcng/warewulf/internal/pkg/node"
nodepkg "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/warewulfconf"
)
func RuntimeOverlaySend(w http.ResponseWriter, req *http.Request) {
rinfo, err := parseReq(req)
if err != nil {
w.WriteHeader(404)
daemonLogf("ERROR: %s\n", err)
return
}
node, err := GetNode(rinfo.hwaddr)
if err != nil {
w.WriteHeader(403)
daemonLogf("ERROR(%s): %s\n", rinfo.hwaddr, err)
return
}
if node.AssetKey.Defined() && node.AssetKey.Get() != rinfo.assetkey {
w.WriteHeader(404)
daemonLogf("ERROR: Incorrect asset key for node: %s\n", node.Id.Get())
updateStatus(node.Id.Get(), "RUNTIME_OVERLAY", "BAD_ASSET", rinfo.ipaddr)
return
}
conf, err := warewulfconf.New()
if err != nil {
daemonLogf("ERROR: Could not read Warewulf configuration file: %s\n", err)
@@ -19,68 +38,33 @@ func RuntimeOverlaySend(w http.ResponseWriter, req *http.Request) {
return
}
nodes, err := node.New()
if err != nil {
daemonLogf("ERROR: Could not read node configuration file: %s\n", err)
w.WriteHeader(503)
return
}
remote := strings.Split(req.RemoteAddr, ":")
port, err := strconv.Atoi(remote[1])
if err != nil {
daemonLogf("ERROR: Could not convert port to integer: %s\n", remote[1])
w.WriteHeader(503)
return
}
if err != nil {
daemonLogf("ERROR: Could not load configuration file: %s\n", err)
return
}
if conf.Warewulf.Secure {
if port >= 1024 {
if rinfo.remoteport >= 1024 {
daemonLogf("DENIED: Connection coming from non-privledged port: %s\n", req.RemoteAddr)
w.WriteHeader(401)
return
}
}
n, err := nodes.FindByIpaddr(remote[0])
if err != nil {
daemonLogf("WARNING: Could not find node by IP address: %s\n", remote[0])
w.WriteHeader(404)
return
}
if !n.Id.Defined() {
daemonLogf("REQ: %15s: %s (unknown/unconfigured node)\n", n.Id.Get(), req.URL.Path)
w.WriteHeader(404)
return
} else {
daemonLogf("REQ: %15s: %s\n", n.Id.Get(), req.URL.Path)
}
if n.RuntimeOverlay.Defined() {
fileName := overlay.OverlayImage(n.Id.Get(), n.RuntimeOverlay.Get())
if node.RuntimeOverlay.Defined() {
fileName := overlay.OverlayImage(node.Id.Get(), node.RuntimeOverlay.Get())
if conf.Warewulf.AutobuildOverlays {
if !util.IsFile(fileName) || util.PathIsNewer(fileName, node.ConfigFile) || util.PathIsNewer(fileName, overlay.OverlaySourceDir(n.RuntimeOverlay.Get())) {
daemonLogf("BUILD: %15s: Runtime Overlay\n", n.Id.Get())
_ = overlay.BuildOverlay(n, n.RuntimeOverlay.Get())
if !util.IsFile(fileName) || util.PathIsNewer(fileName, nodepkg.ConfigFile) || util.PathIsNewer(fileName, overlay.OverlaySourceDir(node.RuntimeOverlay.Get())) {
daemonLogf("BUILD: %15s: Runtime Overlay\n", node.Id.Get())
_ = overlay.BuildOverlay(node, node.RuntimeOverlay.Get())
}
}
err := sendFile(w, fileName, n.Id.Get())
err := sendFile(w, fileName, node.Id.Get())
if err != nil {
daemonLogf("ERROR: %s\n", err)
}
updateStatus(n.Id.Get(), "RUNTIME_OVERLAY", n.RuntimeOverlay.Get()+".img", strings.Split(req.RemoteAddr, ":")[0])
updateStatus(node.Id.Get(), "RUNTIME_OVERLAY", node.RuntimeOverlay.Get()+".img", strings.Split(req.RemoteAddr, ":")[0])
} else {
w.WriteHeader(503)
daemonLogf("WARNING: No 'runtime system-overlay' set for node %s\n", n.Id.Get())
daemonLogf("WARNING: No 'runtime overlay' set for node %s\n", node.Id.Get())
}
}

View File

@@ -4,13 +4,33 @@ import (
"net/http"
"strings"
"github.com/hpcng/warewulf/internal/pkg/node"
nodepkg "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/warewulfconf"
)
func SystemOverlaySend(w http.ResponseWriter, req *http.Request) {
rinfo, err := parseReq(req)
if err != nil {
w.WriteHeader(404)
daemonLogf("ERROR: %s\n", err)
return
}
node, err := GetNode(rinfo.hwaddr)
if err != nil {
w.WriteHeader(403)
daemonLogf("ERROR(%s): %s\n", rinfo.hwaddr, err)
return
}
if node.AssetKey.Defined() && node.AssetKey.Get() != rinfo.assetkey {
w.WriteHeader(404)
daemonLogf("ERROR: Incorrect asset key for node: %s\n", node.Id.Get())
updateStatus(node.Id.Get(), "SYSTEM_OVERLAY", "BAD_ASSET", rinfo.ipaddr)
return
}
conf, err := warewulfconf.New()
if err != nil {
daemonLogf("ERROR: Could not read Warewulf configuration file: %s\n", err)
@@ -18,32 +38,25 @@ func SystemOverlaySend(w http.ResponseWriter, req *http.Request) {
return
}
n, err := getSanity(req)
if err != nil {
w.WriteHeader(404)
daemonLogf("ERROR: %s\n", err)
return
}
if n.SystemOverlay.Defined() {
fileName := overlay.OverlayImage(n.Id.Get(), n.SystemOverlay.Get())
if node.SystemOverlay.Defined() {
fileName := overlay.OverlayImage(node.Id.Get(), node.SystemOverlay.Get())
if conf.Warewulf.AutobuildOverlays {
if !util.IsFile(fileName) || util.PathIsNewer(fileName, node.ConfigFile) || util.PathIsNewer(fileName, overlay.OverlaySourceDir(n.SystemOverlay.Get())) {
daemonLogf("BUILD: %15s: System Overlay\n", n.Id.Get())
_ = overlay.BuildOverlay(n, n.SystemOverlay.Get())
if !util.IsFile(fileName) || util.PathIsNewer(fileName, nodepkg.ConfigFile) || util.PathIsNewer(fileName, overlay.OverlaySourceDir(node.SystemOverlay.Get())) {
daemonLogf("BUILD: %15s: System Overlay\n", node.Id.Get())
_ = overlay.BuildOverlay(node, node.SystemOverlay.Get())
}
}
err := sendFile(w, fileName, n.Id.Get())
err := sendFile(w, fileName, node.Id.Get())
if err != nil {
daemonLogf("ERROR: %s\n", err)
}
updateStatus(n.Id.Get(), "SYSTEM_OVERLAY", n.SystemOverlay.Get()+".img", strings.Split(req.RemoteAddr, ":")[0])
updateStatus(node.Id.Get(), "SYSTEM_OVERLAY", node.SystemOverlay.Get()+".img", strings.Split(req.RemoteAddr, ":")[0])
} else {
w.WriteHeader(503)
daemonLogf("WARNING: No 'system system-overlay' set for node %s\n", n.Id.Get())
daemonLogf("WARNING: No 'system system-overlay' set for node %s\n", node.Id.Get())
}
}

View File

@@ -1,54 +1,16 @@
package warewulfd
import (
"fmt"
"io"
"log"
"log/syslog"
"net/http"
"os"
"strconv"
"strings"
"time"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
"github.com/pkg/errors"
)
var logwriter *syslog.Writer
var loginit bool
func daemonLogf(message string, a ...interface{}) {
conf, err := warewulfconf.New()
if err != nil {
fmt.Printf("ERROR: Could not read Warewulf configuration file: %s\n", err)
return
}
if conf.Warewulf.Syslog {
if !loginit {
var err error
logwriter, err = syslog.New(syslog.LOG_NOTICE, "warewulfd")
if err != nil {
return
}
log.SetOutput(logwriter)
loginit = true
log.SetFlags(0)
log.SetPrefix("")
}
log.Printf(message, a...)
} else {
prefix := fmt.Sprintf("[%s] ", time.Now().Format(time.UnixDate))
fmt.Printf(prefix+message, a...)
}
}
func getSanity(req *http.Request) (node.NodeInfo, error) {
url := strings.Split(req.URL.Path, "/")