added warewulfconf as command line parameter

the environment variable WAREWULFCONF is also recognized

Signed-off-by: Christian Goll <cgoll@suse.de>
This commit is contained in:
Christian Goll
2023-03-03 11:18:49 +01:00
parent 29a6d39a24
commit 6b510865fe
15 changed files with 151 additions and 186 deletions

View File

@@ -290,11 +290,7 @@ func NodeStatus(nodeNames []string) (nodeStatusResponse *wwapiv1.NodeStatusRespo
Nodes map[string]*nodeStatusInternal `json:"nodes"`
}
controller, err := warewulfconf.New()
if err != nil {
wwlog.Error("%s", err)
return
}
controller := warewulfconf.New()
if controller.Ipaddr == "" {
err = fmt.Errorf("the Warewulf Server IP Address is not properly configured")

View File

@@ -15,13 +15,9 @@ import (
Configures the dhcpd server, when show is set to false, else the
dhcp configuration is checked.
*/
func Dhcp() error {
func Dhcp() (err error) {
controller, err := warewulfconf.New()
if err != nil {
wwlog.Error("%s", err)
os.Exit(1)
}
controller := warewulfconf.New()
if !controller.Dhcp.Enabled {
wwlog.Info("This system is not configured as a Warewulf DHCP controller")
@@ -51,5 +47,5 @@ func Dhcp() error {
return errors.Wrap(err, "failed to start")
}
return nil
return
}

View File

@@ -2,7 +2,6 @@ package configure
import (
"fmt"
"os"
"github.com/hpcng/warewulf/internal/pkg/overlay"
"github.com/hpcng/warewulf/internal/pkg/util"
@@ -17,18 +16,11 @@ nfs server.
*/
func NFS() error {
controller, err := warewulfconf.New()
if err != nil {
wwlog.Error("%s", err)
os.Exit(1)
}
controller := warewulfconf.New()
if controller.Nfs.Enabled {
if err != nil {
fmt.Println(err)
}
if controller.Warewulf.EnableHostOverlay {
err = overlay.BuildHostOverlay()
err := overlay.BuildHostOverlay()
if err != nil {
wwlog.Warn("host overlay could not be built: %s", err)
}

View File

@@ -13,13 +13,9 @@ import (
func TFTP() error {
var tftpdir string = path.Join(buildconfig.TFTPDIR(), "warewulf")
controller, err := warewulfconf.New()
if err != nil {
wwlog.Error("%s", err)
return err
}
controller := warewulfconf.New()
err = os.MkdirAll(tftpdir, 0755)
err := os.MkdirAll(tftpdir, 0755)
if err != nil {
wwlog.Error("%s", err)
return err

View File

@@ -43,11 +43,7 @@ Initialize an TemplateStruct with the given node.NodeInfo
*/
func InitStruct(nodeInfo node.NodeInfo) TemplateStruct {
var tstruct TemplateStruct
controller, err := warewulfconf.New()
if err != nil {
wwlog.Error("%s", err)
os.Exit(1)
}
controller := warewulfconf.New()
nodeDB, err := node.New()
if err != nil {
wwlog.Error("%s", err)

View File

@@ -11,7 +11,6 @@ import (
"github.com/creasty/defaults"
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"gopkg.in/yaml.v2"
)
@@ -31,91 +30,107 @@ func init() {
}
}
func New() (ControllerConf, error) {
var ret ControllerConf
var warewulfconf WarewulfConf
var dhpdconf DhcpConf
var tftpconf TftpConf
var nfsConf NfsConf
ret.Warewulf = &warewulfconf
ret.Dhcp = &dhpdconf
ret.Tftp = &tftpconf
ret.Nfs = &nfsConf
err := defaults.Set(&ret)
// ipxe binaries are merged not overwritten, store defaults separate
defIpxe := make(map[string]string)
for k, v := range ret.Tftp.IpxeBinaries {
defIpxe[k] = v
delete(ret.Tftp.IpxeBinaries, k)
}
if err != nil {
wwlog.Error("Could initialize default variables")
return ret, err
}
// Check if cached config is old before re-reading config file
/*
Creates a new empty ControllerConf object, returns a cached
one if called in a nother context.
*/
func New() (ret ControllerConf) {
// NOTE: This function can be called before any log level is set
// so using wwlog.Verbose or wwlog.Debug won't work
if !cachedConf.current {
wwlog.Debug("Opening Warewulf configuration file: %s", ConfigFile)
data, err := os.ReadFile(ConfigFile)
ret.Warewulf = new(WarewulfConf)
ret.Dhcp = new(DhcpConf)
ret.Tftp = new(TftpConf)
ret.Nfs = new(NfsConf)
err := defaults.Set(&ret)
if err != nil {
wwlog.Warn("Error reading Warewulf configuration file, falling back on defaults")
ret.setDynamicDefaults()
}
wwlog.Debug("Unmarshaling the Warewulf configuration")
err = yaml.Unmarshal(data, &ret)
if err != nil {
return ret, err
}
if len(ret.Tftp.IpxeBinaries) == 0 {
ret.Tftp.IpxeBinaries = defIpxe
}
if ret.Ipaddr == "" || ret.Netmask == "" {
conn, error := net.Dial("udp", "8.8.8.8:80")
if error != nil {
return ret, err
}
defer conn.Close()
localIp := conn.LocalAddr().(*net.UDPAddr)
if ret.Ipaddr == "" {
ret.Ipaddr = localIp.IP.String()
wwlog.Verbose("IP address is not configured in warewulfd.conf, using %s", ret.Ipaddr)
}
if ret.Netmask == "" {
mask := localIp.IP.DefaultMask()
ret.Netmask = fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3])
wwlog.Verbose("Netmask address is not configured in warewulfd.conf, using %s", ret.Netmask)
}
}
if ret.Network == "" {
mask := net.IPMask(net.ParseIP(ret.Netmask).To4())
size, _ := mask.Size()
sub := ipsubnet.SubnetCalculator(ret.Ipaddr, size)
ret.Network = sub.GetNetworkPortion()
}
// check validity of ipv6 net
if ret.Ipaddr6 != "" {
_, ipv6net, err := net.ParseCIDR(ret.Ipaddr6)
if err != nil {
wwlog.Error("Invalid ipv6 address specified, mut be CIDR notation: %s", ret.Ipaddr6)
return ret, errors.New("invalid ipv6 network")
}
if msize, _ := ipv6net.Mask.Size(); msize > 64 {
wwlog.Error("ipv6 mask size must be smaller than 64")
return ret, errors.New("invalid ipv6 network size")
}
}
wwlog.Debug("Returning warewulf config object")
cachedConf = ret
cachedConf.current = true
} else {
wwlog.Debug("Returning cached warewulf config object")
// If cached struct isn't empty, use it as the return value
ret = cachedConf
}
return ret, nil
return ret
}
/*
Populate the configuration with the values from the configuration file.
*/
func (conf *ControllerConf) ReadConf(confFileName string) (err error) {
fileHandle, err := os.ReadFile(confFileName)
if err != nil {
return err
}
return conf.Read(fileHandle)
}
/*
Populate the configuration with the values from the given yaml information
*/
func (conf *ControllerConf) Read(data []byte) (err error) {
// ipxe binaries are merged not overwritten, store defaults separate
defIpxe := make(map[string]string)
for k, v := range conf.Tftp.IpxeBinaries {
defIpxe[k] = v
delete(conf.Tftp.IpxeBinaries, k)
}
err = yaml.Unmarshal(data, &conf)
if err != nil {
return
}
if len(conf.Tftp.IpxeBinaries) == 0 {
conf.Tftp.IpxeBinaries = defIpxe
}
cachedConf = *conf
cachedConf.current = true
return
}
/*
Set the runtime defaults like IP address of running system to the config
*/
func (ret *ControllerConf) setDynamicDefaults() (err error) {
if ret.Ipaddr == "" || ret.Netmask == "" {
conn, error := net.Dial("udp", "8.8.8.8:80")
if error != nil {
return err
}
defer conn.Close()
localIp := conn.LocalAddr().(*net.UDPAddr)
if ret.Ipaddr == "" {
ret.Ipaddr = localIp.IP.String()
wwlog.Verbose("IP address is not configured in warewulfd.conf, using %s", ret.Ipaddr)
}
if ret.Netmask == "" {
mask := localIp.IP.DefaultMask()
ret.Netmask = fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3])
wwlog.Verbose("Netmask address is not configured in warewulfd.conf, using %s", ret.Netmask)
}
}
if ret.Network == "" {
mask := net.IPMask(net.ParseIP(ret.Netmask).To4())
size, _ := mask.Size()
sub := ipsubnet.SubnetCalculator(ret.Ipaddr, size)
ret.Network = sub.GetNetworkPortion()
}
// check validity of ipv6 net
if ret.Ipaddr6 != "" {
_, ipv6net, err := net.ParseCIDR(ret.Ipaddr6)
if err != nil {
wwlog.Error("Invalid ipv6 address specified, mut be CIDR notation: %s", ret.Ipaddr6)
return errors.New("invalid ipv6 network")
}
if msize, _ := ipv6net.Mask.Size(); msize > 64 {
wwlog.Error("ipv6 mask size must be smaller than 64")
return errors.New("invalid ipv6 network size")
}
}
return
}

View File

@@ -2,7 +2,6 @@ package warewulfconf
import (
"github.com/creasty/defaults"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
)
type ControllerConf struct {
@@ -78,15 +77,9 @@ func (s *NfsConf) Unmarshal(unmarshal func(interface{}) error) error {
return nil
}
func init() {
_, err := New()
if err != nil {
wwlog.Warn("Could not get any Warewulf configuration: %s", err)
}
}
// Waste processor cycles to make code more readable
func DataStore() string {
_ = New()
return cachedConf.Warewulf.DataStore
}

View File

@@ -44,10 +44,7 @@ func DaemonInitLogging() error {
wwlog.SetLogLevel(wwlog.SERV)
}
conf, err := warewulfconf.New()
if err != nil {
return errors.Wrap(err, "Could not read Warewulf configuration file")
}
conf := warewulfconf.New()
if conf.Warewulf.Syslog {

View File

@@ -31,12 +31,7 @@ type iPxeTemplate struct {
}
func ProvisionSend(w http.ResponseWriter, req *http.Request) {
conf, err := warewulfconf.New()
if err != nil {
wwlog.Error("Could not open Warewulf configuration: %s", err)
w.WriteHeader(http.StatusServiceUnavailable)
return
}
conf := warewulfconf.New()
rinfo, err := parseReq(req)
if err != nil {
@@ -45,7 +40,7 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
return
}
wwlog.Recv("hwaddr: %s, ipaddr: %s, stage: %s", rinfo.hwaddr, req.RemoteAddr, rinfo.stage )
wwlog.Recv("hwaddr: %s, ipaddr: %s, stage: %s", rinfo.hwaddr, req.RemoteAddr, rinfo.stage)
if rinfo.stage == "runtime" && conf.Warewulf.Secure {
if rinfo.remoteport >= 1024 {
@@ -56,11 +51,11 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
}
status_stages := map[string]string{
"ipxe": "IPXE",
"kernel": "KERNEL",
"kmods": "KMODS_OVERLAY",
"system": "SYSTEM_OVERLAY",
"runtime": "RUNTIME_OVERLAY" }
"ipxe": "IPXE",
"kernel": "KERNEL",
"kmods": "KMODS_OVERLAY",
"system": "SYSTEM_OVERLAY",
"runtime": "RUNTIME_OVERLAY"}
status_stage := status_stages[rinfo.stage]
var stage_overlays []string
@@ -87,24 +82,24 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
if rinfo.stage == "ipxe" {
stage_file = path.Join(buildconfig.SYSCONFDIR(), "/warewulf/ipxe/unconfigured.ipxe")
tmpl_data = iPxeTemplate{
Hwaddr : rinfo.hwaddr }
Hwaddr: rinfo.hwaddr}
}
}else if rinfo.stage == "ipxe" {
} else if rinfo.stage == "ipxe" {
stage_file = path.Join(buildconfig.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() }
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 == "kernel" {
} else if rinfo.stage == "kernel" {
if node.Kernel.Override.Defined() {
stage_file = kernel.KernelImage(node.Kernel.Override.Get())
} else if node.ContainerName.Defined() {
@@ -117,28 +112,28 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
wwlog.Warn("No kernel version set for node %s", node.Id.Get())
}
}else if rinfo.stage == "kmods" {
} else if rinfo.stage == "kmods" {
if node.Kernel.Override.Defined() {
stage_file = kernel.KmodsImage(node.Kernel.Override.Get())
}else{
} else {
wwlog.Warn("No kernel override modules set for node %s", node.Id.Get())
}
}else if rinfo.stage == "container" {
} else if rinfo.stage == "container" {
if node.ContainerName.Defined() {
stage_file = container.ImageFile(node.ContainerName.Get())
} else {
wwlog.Warn("No container set for node %s", node.Id.Get())
}
}else if rinfo.stage == "system" {
} else if rinfo.stage == "system" {
if len(node.SystemOverlay.GetSlice()) != 0 {
stage_overlays = node.SystemOverlay.GetSlice()
} else {
wwlog.Warn("No system overlay set for node %s", node.Id.Get())
}
}else if rinfo.stage == "runtime" {
} else if rinfo.stage == "runtime" {
if rinfo.overlay != "" {
stage_overlays = []string{rinfo.overlay}
} else if len(node.RuntimeOverlay.GetSlice()) != 0 {
@@ -153,7 +148,7 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
stage_file, err = getOverlayFile(
node.Id.Get(),
stage_overlays,
conf.Warewulf.AutobuildOverlays )
conf.Warewulf.AutobuildOverlays)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
@@ -162,7 +157,7 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
}
}
wwlog.Serv("stage_file '%s'", stage_file )
wwlog.Serv("stage_file '%s'", stage_file)
if util.IsFile(stage_file) {
@@ -200,7 +195,7 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
wwlog.Send("%15s: %s", node.Id.Get(), stage_file)
}else{
} else {
if rinfo.compress == "gz" {
stage_file += ".gz"
@@ -210,7 +205,7 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusNotFound)
return
}
}else if rinfo.compress != "" {
} else if rinfo.compress != "" {
wwlog.Error("unsupported %s compressed version of file %s",
rinfo.compress, stage_file)
w.WriteHeader(http.StatusNotFound)
@@ -225,14 +220,14 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
updateStatus(node.Id.Get(), status_stage, path.Base(stage_file), rinfo.ipaddr)
}else if stage_file == "" {
} else if stage_file == "" {
w.WriteHeader(http.StatusBadRequest)
wwlog.Error("No resource selected")
updateStatus(node.Id.Get(), status_stage, "BAD_REQUEST", rinfo.ipaddr)
}else{
} else {
w.WriteHeader(http.StatusNotFound)
wwlog.Error("Not found: %s", stage_file )
wwlog.Error("Not found: %s", stage_file)
updateStatus(node.Id.Get(), status_stage, "NOT_FOUND", rinfo.ipaddr)
}

View File

@@ -58,10 +58,7 @@ func RunServer() error {
http.HandleFunc("/overlay-runtime/", ProvisionSend)
http.HandleFunc("/status", StatusSend)
conf, err := warewulfconf.New()
if err != nil {
return errors.Wrap(err, "could not get Warewulf configuration")
}
conf := warewulfconf.New()
daemonPort := conf.Warewulf.Port
wwlog.Serv("Starting HTTPD REST service on port %d", daemonPort)