diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..88db322c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true + +[*.go] +indent_style = space +indent_size = 4 + +[Makefile] +indent_style = tab + +[*.{yaml,yml}] +indent_style = space +indent_size = 2 diff --git a/Makefile b/Makefile index ce3316ea..5eb72180 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: all -VERSION := 4.0 +VERSION := 4.0.0 # auto installed tooling TOOLS_DIR := .tools diff --git a/cmd/wwclient/wwclient.go b/cmd/wwclient/wwclient.go index bbf25217..a3859264 100644 --- a/cmd/wwclient/wwclient.go +++ b/cmd/wwclient/wwclient.go @@ -2,14 +2,15 @@ package main import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/warewulfconf" - "github.com/hpcng/warewulf/internal/pkg/wwlog" "log" "net" "net/http" "os" "os/exec" "time" + + "github.com/hpcng/warewulf/internal/pkg/warewulfconf" + "github.com/hpcng/warewulf/internal/pkg/wwlog" ) func main() { diff --git a/cmd/wwctl/main.go b/cmd/wwctl/main.go index a8718e31..0676131e 100644 --- a/cmd/wwctl/main.go +++ b/cmd/wwctl/main.go @@ -4,9 +4,8 @@ import ( "github.com/hpcng/warewulf/internal/app/wwctl" ) - func main() { root := wwctl.GetRootCommand() root.Execute() -} \ No newline at end of file +} diff --git a/go.sum b/go.sum index d9a970e7..8d8980a5 100644 --- a/go.sum +++ b/go.sum @@ -110,6 +110,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= diff --git a/internal/app/sandbox/main.go b/internal/app/sandbox/main.go index 5e2f00e1..c9bd0235 100644 --- a/internal/app/sandbox/main.go +++ b/internal/app/sandbox/main.go @@ -8,6 +8,6 @@ import ( func main() { nodeDB, _ := node.New() nodes, _ := nodeDB.FindAllNodes() -// wwlog.SetLevel(wwlog.DEBUG) + // wwlog.SetLevel(wwlog.DEBUG) overlay.OverlayBuild(nodes, "runtime") } diff --git a/internal/app/wwctl/build/main.go b/internal/app/wwctl/build/main.go index 257fa477..a00bcbca 100644 --- a/internal/app/wwctl/build/main.go +++ b/internal/app/wwctl/build/main.go @@ -1,12 +1,13 @@ package build import ( + "os" + "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/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/configure/dhcp/main.go b/internal/app/wwctl/configure/dhcp/main.go index da3dc414..084dd7c6 100644 --- a/internal/app/wwctl/configure/dhcp/main.go +++ b/internal/app/wwctl/configure/dhcp/main.go @@ -2,15 +2,16 @@ package dhcp import ( "fmt" + "os" + "path" + "strings" + "text/template" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/warewulfconf" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" - "path" - "strings" - "text/template" ) type dhcpTemplate struct { diff --git a/internal/app/wwctl/configure/hosts/main.go b/internal/app/wwctl/configure/hosts/main.go index bde5159f..f7365787 100644 --- a/internal/app/wwctl/configure/hosts/main.go +++ b/internal/app/wwctl/configure/hosts/main.go @@ -3,13 +3,14 @@ package hosts import ( "bytes" "fmt" + "os" + "text/template" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/warewulfconf" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" - "text/template" ) type TemplateStruct struct { diff --git a/internal/app/wwctl/configure/nfs/main.go b/internal/app/wwctl/configure/nfs/main.go index 984c7ea7..b2c9768d 100644 --- a/internal/app/wwctl/configure/nfs/main.go +++ b/internal/app/wwctl/configure/nfs/main.go @@ -2,11 +2,12 @@ package nfs import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/warewulfconf" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/configure/root.go b/internal/app/wwctl/configure/root.go index 21d43277..32c4664d 100644 --- a/internal/app/wwctl/configure/root.go +++ b/internal/app/wwctl/configure/root.go @@ -2,13 +2,14 @@ package configure import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/app/wwctl/configure/dhcp" "github.com/hpcng/warewulf/internal/app/wwctl/configure/hosts" "github.com/hpcng/warewulf/internal/app/wwctl/configure/nfs" "github.com/hpcng/warewulf/internal/app/wwctl/configure/ssh" "github.com/hpcng/warewulf/internal/app/wwctl/configure/tftp" "github.com/spf13/cobra" - "os" ) var ( diff --git a/internal/app/wwctl/configure/ssh/main.go b/internal/app/wwctl/configure/ssh/main.go index 50e1eb92..5ea7f711 100644 --- a/internal/app/wwctl/configure/ssh/main.go +++ b/internal/app/wwctl/configure/ssh/main.go @@ -2,11 +2,12 @@ package ssh import ( "fmt" + "os" + "path" + "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" - "path" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/configure/tftp/main.go b/internal/app/wwctl/configure/tftp/main.go index 8085cd59..83219f14 100644 --- a/internal/app/wwctl/configure/tftp/main.go +++ b/internal/app/wwctl/configure/tftp/main.go @@ -2,13 +2,14 @@ package tftp import ( "fmt" + "os" + "path" + "github.com/hpcng/warewulf/internal/pkg/staticfiles" "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/warewulfconf" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" - "path" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/container/build/main.go b/internal/app/wwctl/container/build/main.go index b9b20403..b0f9e692 100644 --- a/internal/app/wwctl/container/build/main.go +++ b/internal/app/wwctl/container/build/main.go @@ -2,11 +2,12 @@ package build import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/container" "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/container/delete/main.go b/internal/app/wwctl/container/delete/main.go index dfd9d8b5..ea3ce338 100644 --- a/internal/app/wwctl/container/delete/main.go +++ b/internal/app/wwctl/container/delete/main.go @@ -2,11 +2,12 @@ package delete import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/container" "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/container/exec/child/main.go b/internal/app/wwctl/container/exec/child/main.go index 15a79e66..a7a16fde 100644 --- a/internal/app/wwctl/container/exec/child/main.go +++ b/internal/app/wwctl/container/exec/child/main.go @@ -4,13 +4,14 @@ package child import ( "fmt" + "os" + "path" + "syscall" + "github.com/hpcng/warewulf/internal/pkg/container" "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" - "path" - "syscall" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/container/exec/main.go b/internal/app/wwctl/container/exec/main.go index 765baf6d..0e818d85 100644 --- a/internal/app/wwctl/container/exec/main.go +++ b/internal/app/wwctl/container/exec/main.go @@ -4,12 +4,13 @@ package exec import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/container" - "github.com/hpcng/warewulf/internal/pkg/wwlog" - "github.com/spf13/cobra" "os" "os/exec" "syscall" + + "github.com/hpcng/warewulf/internal/pkg/container" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/container/imprt/main.go b/internal/app/wwctl/container/imprt/main.go index 309b6824..180980fb 100644 --- a/internal/app/wwctl/container/imprt/main.go +++ b/internal/app/wwctl/container/imprt/main.go @@ -2,15 +2,69 @@ package imprt import ( "fmt" + "os" + "path" + "strconv" + + "github.com/containers/image/v5/types" "github.com/hpcng/warewulf/internal/pkg/container" "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/util" + "github.com/hpcng/warewulf/internal/pkg/warewulfd" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" - "path" ) +func setOCICredentials(sCtx *types.SystemContext) error { + username, userSet := os.LookupEnv("WAREWULF_OCI_USERNAME") + password, passSet := os.LookupEnv("WAREWULF_OCI_PASSWORD") + if userSet || passSet { + if userSet && passSet { + sCtx.DockerAuthConfig = &types.DockerAuthConfig{ + Username: username, + Password: password, + } + } else { + return fmt.Errorf("oci username and password env vars must be specified together") + } + } + return nil +} + +func setNoHTTPSOpts(sCtx *types.SystemContext) error { + val, ok := os.LookupEnv("WAREWULF_OCI_NOHTTPS") + if !ok { + return nil + } + + noHTTPS, err := strconv.ParseBool(val) + if err != nil { + return fmt.Errorf("while parsing insecure http option: %v", err) + } + + // only set this if we want to disable, otherwise leave as undefined + if noHTTPS { + sCtx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(true) + } + sCtx.OCIInsecureSkipTLSVerify = noHTTPS + + return nil +} + +func getSystemContext() (sCtx *types.SystemContext, err error) { + sCtx = &types.SystemContext{} + + if err := setOCICredentials(sCtx); err != nil { + return nil, err + } + + if err := setNoHTTPSOpts(sCtx); err != nil { + return nil, err + } + + return sCtx, nil +} + func CobraRunE(cmd *cobra.Command, args []string) error { var name string uri := args[0] @@ -45,7 +99,12 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } } - err := container.PullURI(uri, name) + sCtx, err := getSystemContext() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + } + + err = container.PullURI(uri, name, sCtx) if err != nil { wwlog.Printf(wwlog.ERROR, "Could not pull image: %s\n", err) os.Exit(1) @@ -79,6 +138,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } nodeDB.Persist() fmt.Printf("Set default profile to container: %s\n", name) + warewulfd.DaemonReload() } diff --git a/internal/app/wwctl/container/list/main.go b/internal/app/wwctl/container/list/main.go index 1a2f3128..77a91512 100644 --- a/internal/app/wwctl/container/list/main.go +++ b/internal/app/wwctl/container/list/main.go @@ -2,12 +2,13 @@ package list import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/container" "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/controller/add/main.go b/internal/app/wwctl/controller/add/main.go index f7231a4a..4986cf5f 100644 --- a/internal/app/wwctl/controller/add/main.go +++ b/internal/app/wwctl/controller/add/main.go @@ -1,10 +1,11 @@ package add import ( + "os" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { @@ -26,4 +27,4 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodeDB.Persist() return nil -} \ No newline at end of file +} diff --git a/internal/app/wwctl/controller/add/root.go b/internal/app/wwctl/controller/add/root.go index f26c860d..eb4af736 100644 --- a/internal/app/wwctl/controller/add/root.go +++ b/internal/app/wwctl/controller/add/root.go @@ -4,11 +4,11 @@ import "github.com/spf13/cobra" var ( baseCmd = &cobra.Command{ - Use: "add", - Short: "Add", - Long: "Add", - RunE: CobraRunE, - Args: cobra.MinimumNArgs(1), + Use: "add", + Short: "Add", + Long: "Add", + RunE: CobraRunE, + Args: cobra.MinimumNArgs(1), } SetController string ) diff --git a/internal/app/wwctl/controller/delete/main.go b/internal/app/wwctl/controller/delete/main.go index 4939940a..e2605357 100644 --- a/internal/app/wwctl/controller/delete/main.go +++ b/internal/app/wwctl/controller/delete/main.go @@ -2,11 +2,12 @@ package delete import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/manifoldco/promptui" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { @@ -19,7 +20,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } - nodes, err := nodeDB. FindAllNodes() + nodes, err := nodeDB.FindAllNodes() if err != nil { wwlog.Printf(wwlog.ERROR, "Could not load all nodes: %s\n", err) os.Exit(1) @@ -32,10 +33,10 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } else { for _, n := range nodes { if n.Cid.Get() == c { - numNodes ++ + numNodes++ } } - count ++ + count++ } } @@ -58,4 +59,4 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } return nil -} \ No newline at end of file +} diff --git a/internal/app/wwctl/controller/delete/root.go b/internal/app/wwctl/controller/delete/root.go index 0fc4fdcc..43d5bf82 100644 --- a/internal/app/wwctl/controller/delete/root.go +++ b/internal/app/wwctl/controller/delete/root.go @@ -4,11 +4,11 @@ import "github.com/spf13/cobra" var ( baseCmd = &cobra.Command{ - Use: "delete", - Short: "Delete", - Long: "Delete", - RunE: CobraRunE, - Args: cobra.MinimumNArgs(1), + Use: "delete", + Short: "Delete", + Long: "Delete", + RunE: CobraRunE, + Args: cobra.MinimumNArgs(1), } SetController string ) diff --git a/internal/app/wwctl/controller/list/main.go b/internal/app/wwctl/controller/list/main.go index a32e8bbf..4b982098 100644 --- a/internal/app/wwctl/controller/list/main.go +++ b/internal/app/wwctl/controller/list/main.go @@ -3,10 +3,11 @@ package list import "C" import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/controller/list/root.go b/internal/app/wwctl/controller/list/root.go index 583c8fed..add5a6fe 100644 --- a/internal/app/wwctl/controller/list/root.go +++ b/internal/app/wwctl/controller/list/root.go @@ -4,10 +4,10 @@ import "github.com/spf13/cobra" var ( baseCmd = &cobra.Command{ - Use: "list", - Short: "List", - Long: "List", - RunE: CobraRunE, + Use: "list", + Short: "List", + Long: "List", + RunE: CobraRunE, } ShowAll bool ) diff --git a/internal/app/wwctl/controller/root.go b/internal/app/wwctl/controller/root.go index 31e100f5..22d6134e 100644 --- a/internal/app/wwctl/controller/root.go +++ b/internal/app/wwctl/controller/root.go @@ -1,19 +1,18 @@ package controller import ( - "github.com/spf13/cobra" "github.com/hpcng/warewulf/internal/app/wwctl/controller/add" "github.com/hpcng/warewulf/internal/app/wwctl/controller/delete" "github.com/hpcng/warewulf/internal/app/wwctl/controller/list" "github.com/hpcng/warewulf/internal/app/wwctl/controller/set" - + "github.com/spf13/cobra" ) var ( baseCmd = &cobra.Command{ - Use: "controller", - Short: "Controller management", - Long: "Management of group settings and power management", + Use: "controller", + Short: "Controller management", + Long: "Management of group settings and power management", } ) diff --git a/internal/app/wwctl/controller/set/main.go b/internal/app/wwctl/controller/set/main.go index e7ed61d6..827ca137 100644 --- a/internal/app/wwctl/controller/set/main.go +++ b/internal/app/wwctl/controller/set/main.go @@ -2,11 +2,12 @@ package set import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/manifoldco/promptui" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/kernel/imprt/main.go b/internal/app/wwctl/kernel/imprt/main.go index 4109fc55..745f9f48 100644 --- a/internal/app/wwctl/kernel/imprt/main.go +++ b/internal/app/wwctl/kernel/imprt/main.go @@ -2,17 +2,19 @@ package imprt import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/kernel" "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/warewulfd" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { for _, arg := range args { - output, err := kernel.Build(arg) + output, err := kernel.Build(arg, OptRoot) if err != nil { wwlog.Printf(wwlog.ERROR, "Failed building kernel: %s\n", err) os.Exit(1) @@ -43,6 +45,8 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } nodeDB.Persist() fmt.Printf("Set default kernel version to: %s\n", args[0]) + + warewulfd.DaemonReload() } } diff --git a/internal/app/wwctl/kernel/imprt/root.go b/internal/app/wwctl/kernel/imprt/root.go index 22881842..b529e680 100644 --- a/internal/app/wwctl/kernel/imprt/root.go +++ b/internal/app/wwctl/kernel/imprt/root.go @@ -16,12 +16,14 @@ var ( BuildAll bool ByNode bool SetDefault bool + OptRoot string ) func init() { baseCmd.PersistentFlags().BoolVarP(&BuildAll, "all", "a", false, "Build all overlays (runtime and system)") baseCmd.PersistentFlags().BoolVarP(&ByNode, "node", "n", false, "Build overlay for a particular node(s)") baseCmd.PersistentFlags().BoolVar(&SetDefault, "setdefault", false, "Set this kernel for the default profile") + baseCmd.PersistentFlags().StringVarP(&OptRoot, "root", "r", "/", "Import kernel from root (chroot) directory") } // GetRootCommand returns the root cobra.Command for the application. diff --git a/internal/app/wwctl/kernel/list/main.go b/internal/app/wwctl/kernel/list/main.go index 155454b2..c72f4406 100644 --- a/internal/app/wwctl/kernel/list/main.go +++ b/internal/app/wwctl/kernel/list/main.go @@ -2,11 +2,12 @@ package list import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/kernel" "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/node/add/main.go b/internal/app/wwctl/node/add/main.go index 598b4974..c3f88fb0 100644 --- a/internal/app/wwctl/node/add/main.go +++ b/internal/app/wwctl/node/add/main.go @@ -2,10 +2,11 @@ package add import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/node/console/power.go b/internal/app/wwctl/node/console/power.go index c105479a..2da2d576 100644 --- a/internal/app/wwctl/node/console/power.go +++ b/internal/app/wwctl/node/console/power.go @@ -1,11 +1,12 @@ package console import ( + "os" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/power" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { @@ -57,4 +58,3 @@ func CobraRunE(cmd *cobra.Command, args []string) error { return returnErr } - diff --git a/internal/app/wwctl/node/delete/main.go b/internal/app/wwctl/node/delete/main.go index 2730c967..5c46327c 100644 --- a/internal/app/wwctl/node/delete/main.go +++ b/internal/app/wwctl/node/delete/main.go @@ -2,11 +2,12 @@ package delete import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/manifoldco/promptui" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/node/list/main.go b/internal/app/wwctl/node/list/main.go index 74d68a8a..017c68bc 100644 --- a/internal/app/wwctl/node/list/main.go +++ b/internal/app/wwctl/node/list/main.go @@ -2,12 +2,13 @@ package list import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/node" - "github.com/hpcng/warewulf/internal/pkg/wwlog" - "github.com/spf13/cobra" "os" "sort" "strings" + + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/node/set/main.go b/internal/app/wwctl/node/set/main.go index 2878cbc2..6355d3f5 100644 --- a/internal/app/wwctl/node/set/main.go +++ b/internal/app/wwctl/node/set/main.go @@ -2,13 +2,15 @@ package set import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/container" "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/util" + "github.com/hpcng/warewulf/internal/pkg/warewulfd" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/manifoldco/promptui" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { @@ -274,6 +276,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if result == "y" || result == "yes" { nodeDB.Persist() + warewulfd.DaemonReload() } } diff --git a/internal/app/wwctl/overlay/build/main.go b/internal/app/wwctl/overlay/build/main.go index 761a2f77..61a843eb 100644 --- a/internal/app/wwctl/overlay/build/main.go +++ b/internal/app/wwctl/overlay/build/main.go @@ -1,11 +1,12 @@ package build import ( + "os" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/overlay" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/overlay/build/root.go b/internal/app/wwctl/overlay/build/root.go index 4da9af71..eeaf7089 100644 --- a/internal/app/wwctl/overlay/build/root.go +++ b/internal/app/wwctl/overlay/build/root.go @@ -7,7 +7,6 @@ var ( Use: "build [flags] ", Short: "(Re)build an overlay", Long: "This command will build a system or runtime overlay.", - Args: cobra.MinimumNArgs(1), RunE: CobraRunE, } SystemOverlay bool diff --git a/internal/app/wwctl/overlay/chmod/main.go b/internal/app/wwctl/overlay/chmod/main.go index 0621a10c..b59d7755 100644 --- a/internal/app/wwctl/overlay/chmod/main.go +++ b/internal/app/wwctl/overlay/chmod/main.go @@ -1,15 +1,16 @@ package chmod import ( + "os" + "path" + "strconv" + "github.com/hpcng/warewulf/internal/pkg/config" "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" "github.com/spf13/cobra" - "os" - "path" - "strconv" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/overlay/create/main.go b/internal/app/wwctl/overlay/create/main.go index dab21898..407e6b34 100644 --- a/internal/app/wwctl/overlay/create/main.go +++ b/internal/app/wwctl/overlay/create/main.go @@ -1,11 +1,12 @@ package create import ( + "os" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/overlay" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/overlay/delete/main.go b/internal/app/wwctl/overlay/delete/main.go index 606f910a..bc8856dd 100644 --- a/internal/app/wwctl/overlay/delete/main.go +++ b/internal/app/wwctl/overlay/delete/main.go @@ -2,14 +2,15 @@ package delete import ( "fmt" + "os" + "path" + "github.com/hpcng/warewulf/internal/pkg/config" "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" "github.com/spf13/cobra" - "os" - "path" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/overlay/edit/main.go b/internal/app/wwctl/overlay/edit/main.go index 269815ff..dd0fdfae 100644 --- a/internal/app/wwctl/overlay/edit/main.go +++ b/internal/app/wwctl/overlay/edit/main.go @@ -2,15 +2,16 @@ package edit import ( "fmt" + "os" + "path" + "path/filepath" + "github.com/hpcng/warewulf/internal/pkg/config" "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" "github.com/spf13/cobra" - "os" - "path" - "path/filepath" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/overlay/imprt/main.go b/internal/app/wwctl/overlay/imprt/main.go index 08d67af4..bf16d30a 100644 --- a/internal/app/wwctl/overlay/imprt/main.go +++ b/internal/app/wwctl/overlay/imprt/main.go @@ -1,14 +1,15 @@ package imprt import ( + "os" + "path" + "github.com/hpcng/warewulf/internal/pkg/config" "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" "github.com/spf13/cobra" - "os" - "path" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/overlay/list/main.go b/internal/app/wwctl/overlay/list/main.go index 918df167..cc8e8847 100644 --- a/internal/app/wwctl/overlay/list/main.go +++ b/internal/app/wwctl/overlay/list/main.go @@ -2,14 +2,15 @@ package list import ( "fmt" + "os" + "syscall" + "github.com/hpcng/warewulf/internal/pkg/config" "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" "github.com/spf13/cobra" - "os" - "syscall" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/overlay/mkdir/main.go b/internal/app/wwctl/overlay/mkdir/main.go index fee39fd4..af1e30fe 100644 --- a/internal/app/wwctl/overlay/mkdir/main.go +++ b/internal/app/wwctl/overlay/mkdir/main.go @@ -2,14 +2,15 @@ package mkdir import ( "fmt" + "os" + "path" + "github.com/hpcng/warewulf/internal/pkg/config" "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" "github.com/spf13/cobra" - "os" - "path" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/overlay/show/main.go b/internal/app/wwctl/overlay/show/main.go index 5d08b3bd..372455b2 100644 --- a/internal/app/wwctl/overlay/show/main.go +++ b/internal/app/wwctl/overlay/show/main.go @@ -2,13 +2,14 @@ package show import ( "fmt" + "io/ioutil" + "os" + "path" + "github.com/hpcng/warewulf/internal/pkg/config" "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "io/ioutil" - "os" - "path" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/profile/add/main.go b/internal/app/wwctl/profile/add/main.go index f21e6e69..07259e13 100644 --- a/internal/app/wwctl/profile/add/main.go +++ b/internal/app/wwctl/profile/add/main.go @@ -1,10 +1,11 @@ package add import ( + "os" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/profile/delete/main.go b/internal/app/wwctl/profile/delete/main.go index 6909d34b..48bd74f1 100644 --- a/internal/app/wwctl/profile/delete/main.go +++ b/internal/app/wwctl/profile/delete/main.go @@ -2,12 +2,13 @@ package delete import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/manifoldco/promptui" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/profile/list/main.go b/internal/app/wwctl/profile/list/main.go index 371e6171..a855a14c 100644 --- a/internal/app/wwctl/profile/list/main.go +++ b/internal/app/wwctl/profile/list/main.go @@ -2,10 +2,11 @@ package list import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/profile/set/main.go b/internal/app/wwctl/profile/set/main.go index 74ec6adc..11547f42 100644 --- a/internal/app/wwctl/profile/set/main.go +++ b/internal/app/wwctl/profile/set/main.go @@ -2,13 +2,15 @@ package set import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/container" "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/util" + "github.com/hpcng/warewulf/internal/pkg/warewulfd" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/manifoldco/promptui" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { @@ -251,6 +253,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if result == "y" || result == "yes" { nodeDB.Persist() + warewulfd.DaemonReload() } } else { diff --git a/internal/app/wwctl/ready/main.go b/internal/app/wwctl/ready/main.go index fec73de0..2df4b33d 100644 --- a/internal/app/wwctl/ready/main.go +++ b/internal/app/wwctl/ready/main.go @@ -2,6 +2,8 @@ package ready import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/config" "github.com/hpcng/warewulf/internal/pkg/container" "github.com/hpcng/warewulf/internal/pkg/kernel" @@ -9,7 +11,6 @@ import ( "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" - "os" ) func CobraRunE(cmd *cobra.Command, args []string) error { diff --git a/internal/app/wwctl/server/reload/main.go b/internal/app/wwctl/server/reload/main.go new file mode 100644 index 00000000..a81f1a85 --- /dev/null +++ b/internal/app/wwctl/server/reload/main.go @@ -0,0 +1,10 @@ +package reload + +import ( + "github.com/hpcng/warewulf/internal/pkg/warewulfd" + "github.com/spf13/cobra" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + return warewulfd.DaemonReload() +} diff --git a/internal/app/wwctl/server/reload/root.go b/internal/app/wwctl/server/reload/root.go new file mode 100644 index 00000000..b503b746 --- /dev/null +++ b/internal/app/wwctl/server/reload/root.go @@ -0,0 +1,19 @@ +package reload + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "reload", + Short: "Reload the Warewulf server configuration", + RunE: CobraRunE, + } +) + +func init() { +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/server/restart/main.go b/internal/app/wwctl/server/restart/main.go new file mode 100644 index 00000000..264b0794 --- /dev/null +++ b/internal/app/wwctl/server/restart/main.go @@ -0,0 +1,11 @@ +package restart + +import ( + "github.com/hpcng/warewulf/internal/pkg/warewulfd" + "github.com/spf13/cobra" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + warewulfd.DaemonStop() + return warewulfd.DaemonStart() +} diff --git a/internal/app/wwctl/server/restart/root.go b/internal/app/wwctl/server/restart/root.go new file mode 100644 index 00000000..c1538dcd --- /dev/null +++ b/internal/app/wwctl/server/restart/root.go @@ -0,0 +1,19 @@ +package restart + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "restart", + Short: "Restart the Warewulf server", + RunE: CobraRunE, + } +) + +func init() { +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/server/root.go b/internal/app/wwctl/server/root.go index 0ab1e49a..cf1f3f5d 100644 --- a/internal/app/wwctl/server/root.go +++ b/internal/app/wwctl/server/root.go @@ -1,6 +1,8 @@ package server import ( + "github.com/hpcng/warewulf/internal/app/wwctl/server/reload" + "github.com/hpcng/warewulf/internal/app/wwctl/server/restart" "github.com/hpcng/warewulf/internal/app/wwctl/server/start" "github.com/hpcng/warewulf/internal/app/wwctl/server/status" "github.com/hpcng/warewulf/internal/app/wwctl/server/stop" @@ -20,6 +22,9 @@ func init() { baseCmd.AddCommand(start.GetCommand()) baseCmd.AddCommand(status.GetCommand()) baseCmd.AddCommand(stop.GetCommand()) + baseCmd.AddCommand(restart.GetCommand()) + baseCmd.AddCommand(reload.GetCommand()) + } // GetRootCommand returns the root cobra.Command for the application. diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index 5a189525..4db905e4 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -2,9 +2,10 @@ package config import ( "fmt" + "path" + "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/wwlog" - "path" ) const ( diff --git a/internal/pkg/container/build.go b/internal/pkg/container/build.go index 9e29f3ee..0b4e5256 100644 --- a/internal/pkg/container/build.go +++ b/internal/pkg/container/build.go @@ -2,12 +2,13 @@ package container import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/errors" - "github.com/hpcng/warewulf/internal/pkg/util" - "github.com/hpcng/warewulf/internal/pkg/wwlog" "os" "os/exec" "path" + + "github.com/hpcng/warewulf/internal/pkg/errors" + "github.com/hpcng/warewulf/internal/pkg/util" + "github.com/hpcng/warewulf/internal/pkg/wwlog" ) func Build(name string, buildForce bool) (string, error) { diff --git a/internal/pkg/container/pull.go b/internal/pkg/container/pull.go index b559c4fe..26a4680b 100644 --- a/internal/pkg/container/pull.go +++ b/internal/pkg/container/pull.go @@ -2,13 +2,15 @@ package container import ( "context" + "os" + + "github.com/containers/image/v5/types" "github.com/hpcng/warewulf/internal/pkg/config" "github.com/hpcng/warewulf/internal/pkg/errors" "github.com/hpcng/warewulf/internal/pkg/oci" - "os" ) -func PullURI(uri string, name string) error { +func PullURI(uri string, name string, sCtx *types.SystemContext) error { OciBlobCacheDir := config.LocalStateDir + "/oci/blobs" err := os.MkdirAll(OciBlobCacheDir, 0755) @@ -29,13 +31,15 @@ func PullURI(uri string, name string) error { p, err := oci.NewPuller( oci.OptSetBlobCachePath(OciBlobCacheDir), - oci.OptSetSystemContext(nil), + oci.OptSetSystemContext(sCtx), ) if err != nil { return err } - p.GenerateID(context.Background(), uri) + if _, err := p.GenerateID(context.Background(), uri); err != nil { + return err + } if err := p.Pull(context.Background(), uri, fullPath); err != nil { return err diff --git a/internal/pkg/container/vnfs.go b/internal/pkg/container/vnfs.go index 436dfed7..731f67cb 100644 --- a/internal/pkg/container/vnfs.go +++ b/internal/pkg/container/vnfs.go @@ -1,13 +1,14 @@ package container import ( + "io/ioutil" + "os" + "path" + "github.com/hpcng/warewulf/internal/pkg/config" "github.com/hpcng/warewulf/internal/pkg/errors" "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/wwlog" - "io/ioutil" - "os" - "path" ) func ValidName(name string) bool { diff --git a/internal/pkg/kernel/kernel.go b/internal/pkg/kernel/kernel.go index d7df72ad..62ac2cbc 100644 --- a/internal/pkg/kernel/kernel.go +++ b/internal/pkg/kernel/kernel.go @@ -2,14 +2,15 @@ package kernel import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/config" - "github.com/hpcng/warewulf/internal/pkg/errors" - "github.com/hpcng/warewulf/internal/pkg/util" - "github.com/hpcng/warewulf/internal/pkg/wwlog" "io/ioutil" "os" "os/exec" "path" + + "github.com/hpcng/warewulf/internal/pkg/config" + "github.com/hpcng/warewulf/internal/pkg/errors" + "github.com/hpcng/warewulf/internal/pkg/util" + "github.com/hpcng/warewulf/internal/pkg/wwlog" ) func ParentDir() string { @@ -69,10 +70,10 @@ func ListKernels() ([]string, error) { return ret, nil } -func Build(kernelVersion string) (string, error) { +func Build(kernelVersion string, root string) (string, error) { - kernelImage := "/boot/vmlinuz-" + kernelVersion - kernelDrivers := "/lib/modules/" + kernelVersion + kernelImage := path.Join(root, "/boot/vmlinuz-"+kernelVersion) + kernelDrivers := path.Join(root, "/lib/modules/"+kernelVersion) kernelDestination := KernelImage(kernelVersion) driversDestination := KmodsImage(kernelVersion) diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index ae9a7b7c..8e97419b 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -2,13 +2,14 @@ package node import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/errors" - "github.com/hpcng/warewulf/internal/pkg/wwlog" - "gopkg.in/yaml.v2" "io/ioutil" "regexp" "sort" "strings" + + "github.com/hpcng/warewulf/internal/pkg/errors" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "gopkg.in/yaml.v2" ) const ConfigFile = "/etc/warewulf/nodes.conf" diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index 2e914b02..93a001d3 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -2,9 +2,10 @@ package node import ( "fmt" + "os" + "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/wwlog" - "os" ) /****** diff --git a/internal/pkg/node/modifiers.go b/internal/pkg/node/modifiers.go index 102488bf..a8107d27 100644 --- a/internal/pkg/node/modifiers.go +++ b/internal/pkg/node/modifiers.go @@ -1,10 +1,11 @@ package node import ( + "os" + "github.com/hpcng/warewulf/internal/pkg/errors" "github.com/hpcng/warewulf/internal/pkg/wwlog" "gopkg.in/yaml.v2" - "os" ) /**** diff --git a/internal/pkg/oci/puller.go b/internal/pkg/oci/puller.go index db393024..071d565c 100644 --- a/internal/pkg/oci/puller.go +++ b/internal/pkg/oci/puller.go @@ -100,7 +100,7 @@ func (p *puller) GenerateID(ctx context.Context, uri string) (string, error) { return "", fmt.Errorf("unable to parse uri: %v", err) } - src, err := ref.NewImageSource(ctx, nil) + src, err := ref.NewImageSource(ctx, p.sysCtx) if err != nil { return "", err } diff --git a/internal/pkg/overlay/funcmap.go b/internal/pkg/overlay/funcmap.go index ab4b808e..314a3644 100644 --- a/internal/pkg/overlay/funcmap.go +++ b/internal/pkg/overlay/funcmap.go @@ -1,11 +1,12 @@ package overlay import ( - "github.com/hpcng/warewulf/internal/pkg/container" - "github.com/hpcng/warewulf/internal/pkg/wwlog" "io/ioutil" "path" "strings" + + "github.com/hpcng/warewulf/internal/pkg/container" + "github.com/hpcng/warewulf/internal/pkg/wwlog" ) func templateFileInclude(path string) string { diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index 5f01a37d..522b90f7 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -2,11 +2,6 @@ package overlay import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/config" - "github.com/hpcng/warewulf/internal/pkg/errors" - "github.com/hpcng/warewulf/internal/pkg/node" - "github.com/hpcng/warewulf/internal/pkg/util" - "github.com/hpcng/warewulf/internal/pkg/wwlog" "io/ioutil" "os" "os/exec" @@ -15,6 +10,12 @@ import ( "regexp" "strings" "text/template" + + "github.com/hpcng/warewulf/internal/pkg/config" + "github.com/hpcng/warewulf/internal/pkg/errors" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/util" + "github.com/hpcng/warewulf/internal/pkg/wwlog" ) type TemplateStruct struct { diff --git a/internal/pkg/power/ipmitool.go b/internal/pkg/power/ipmitool.go index 063fa6ea..aac1ca66 100644 --- a/internal/pkg/power/ipmitool.go +++ b/internal/pkg/power/ipmitool.go @@ -1,8 +1,8 @@ package power import ( - "os/exec" "os" + "os/exec" ) type IPMIResult struct { @@ -16,7 +16,7 @@ type IPMI struct { User string Password string AuthType string - result IPMIResult + result IPMIResult } func (ipmi *IPMI) Result() (string, error) { @@ -96,4 +96,3 @@ func (ipmi *IPMI) SensorList() (string, error) { func (ipmi *IPMI) Console() error { return ipmi.IPMIInteractiveCommand("sol", "activate") } - diff --git a/internal/pkg/power/power.go b/internal/pkg/power/power.go index a8d09f4c..10bd60fc 100644 --- a/internal/pkg/power/power.go +++ b/internal/pkg/power/power.go @@ -1,10 +1,9 @@ - package power //type PowerControl interface { - //PowerOn() (result string, err error) - //PowerOff() (result string, err error) - //PowerStatus() (result string, err error) +//PowerOn() (result string, err error) +//PowerOff() (result string, err error) +//PowerStatus() (result string, err error) //} type PowerOnInterface interface { @@ -18,5 +17,3 @@ type PowerOffInterface interface { type PowerStatusInterface interface { PowerStatus() (result string, err error) } - - diff --git a/internal/pkg/staticfiles/staticfiles.go b/internal/pkg/staticfiles/staticfiles.go index 66013c29..6731b9ae 100644 --- a/internal/pkg/staticfiles/staticfiles.go +++ b/internal/pkg/staticfiles/staticfiles.go @@ -1,8 +1,9 @@ package staticfiles import ( - "github.com/hpcng/warewulf/internal/pkg/wwlog" "io/ioutil" + + "github.com/hpcng/warewulf/internal/pkg/wwlog" ) func WriteData(source string, dest string) error { diff --git a/internal/pkg/util/util.go b/internal/pkg/util/util.go index 2366696e..36f12118 100644 --- a/internal/pkg/util/util.go +++ b/internal/pkg/util/util.go @@ -1,9 +1,9 @@ package util import ( + "bufio" "crypto/sha256" "fmt" - "github.com/hpcng/warewulf/internal/pkg/wwlog" "io" "math/rand" "os" @@ -11,8 +11,8 @@ import ( "path/filepath" "regexp" "time" - "bufio" - // "strings" + + "github.com/hpcng/warewulf/internal/pkg/wwlog" ) func DirModTime(path string) (time.Time, error) { diff --git a/internal/pkg/vnfs_old/containerdir.go b/internal/pkg/vnfs_old/containerdir.go index 6e2e7897..ba9b3ae9 100644 --- a/internal/pkg/vnfs_old/containerdir.go +++ b/internal/pkg/vnfs_old/containerdir.go @@ -2,10 +2,11 @@ package vnfs import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/util" - "github.com/hpcng/warewulf/internal/pkg/wwlog" "os" "path" + + "github.com/hpcng/warewulf/internal/pkg/util" + "github.com/hpcng/warewulf/internal/pkg/wwlog" ) func BuildContainerdir(vnfs VnfsObject, buildForce bool) { @@ -51,7 +52,7 @@ func BuildContainerdir(vnfs VnfsObject, buildForce bool) { wwlog.Printf(wwlog.ERROR, "Could not create symlink for Chroot: %s\n", err) os.Exit(1) } - err = os.Rename(vnfs.Chroot + "-link", vnfs.Chroot) + err = os.Rename(vnfs.Chroot+"-link", vnfs.Chroot) if err != nil { wwlog.Printf(wwlog.ERROR, "Could not rename link: %s\n", err) os.Exit(1) diff --git a/internal/pkg/vnfs_old/docker.go b/internal/pkg/vnfs_old/docker.go index 46bf8111..4731dd4d 100644 --- a/internal/pkg/vnfs_old/docker.go +++ b/internal/pkg/vnfs_old/docker.go @@ -3,11 +3,12 @@ package vnfs import ( "context" "fmt" + "os" + "path" + "github.com/hpcng/warewulf/internal/pkg/config" "github.com/hpcng/warewulf/internal/pkg/oci" "github.com/hpcng/warewulf/internal/pkg/wwlog" - "os" - "path" ) func BuildDocker(vnfs VnfsObject, buildForce bool) { diff --git a/internal/pkg/vnfs_old/vnfs.go b/internal/pkg/vnfs_old/vnfs.go index 79ae7a02..2f5ab3c6 100644 --- a/internal/pkg/vnfs_old/vnfs.go +++ b/internal/pkg/vnfs_old/vnfs.go @@ -1,15 +1,16 @@ package vnfs import ( + "io/ioutil" + "os" + "path" + "strings" + "github.com/hpcng/warewulf/internal/pkg/config" "github.com/hpcng/warewulf/internal/pkg/errors" "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/wwlog" "gopkg.in/yaml.v2" - "io/ioutil" - "os" - "path" - "strings" ) type VnfsObject struct { diff --git a/internal/pkg/warewulfconf/constructors.go b/internal/pkg/warewulfconf/constructors.go index 9d83271f..fc0886f3 100644 --- a/internal/pkg/warewulfconf/constructors.go +++ b/internal/pkg/warewulfconf/constructors.go @@ -2,11 +2,12 @@ package warewulfconf import ( "fmt" + "io/ioutil" + "net" + "github.com/brotherpowers/ipsubnet" "github.com/hpcng/warewulf/internal/pkg/wwlog" "gopkg.in/yaml.v2" - "io/ioutil" - "net" ) func New() (ControllerConf, error) { @@ -15,7 +16,7 @@ func New() (ControllerConf, error) { wwlog.Printf(wwlog.DEBUG, "Opening Warewulf configuration file: %s\n", ConfigFile) data, err := ioutil.ReadFile(ConfigFile) if err != nil { - fmt.Printf("error reading node configuration file\n") + fmt.Printf("error reading Warewulf configuration file\n") return ret, err } diff --git a/internal/pkg/warewulfconf/datastructure.go b/internal/pkg/warewulfconf/datastructure.go index ed15aa95..da2dc0ad 100644 --- a/internal/pkg/warewulfconf/datastructure.go +++ b/internal/pkg/warewulfconf/datastructure.go @@ -1,9 +1,10 @@ package warewulfconf import ( + "os" + "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/wwlog" - "os" ) const ConfigFile = "/etc/warewulf/warewulf.conf" diff --git a/internal/pkg/warewulfconf/modifiers.go b/internal/pkg/warewulfconf/modifiers.go index f50e329e..d12eb659 100644 --- a/internal/pkg/warewulfconf/modifiers.go +++ b/internal/pkg/warewulfconf/modifiers.go @@ -1,9 +1,10 @@ package warewulfconf import ( + "os" + "github.com/hpcng/warewulf/internal/pkg/wwlog" "gopkg.in/yaml.v2" - "os" ) func (self *ControllerConf) Persist() error { diff --git a/internal/pkg/warewulfd/container.go b/internal/pkg/warewulfd/container.go index 1aa0b69d..ad368417 100644 --- a/internal/pkg/warewulfd/container.go +++ b/internal/pkg/warewulfd/container.go @@ -1,9 +1,10 @@ package warewulfd import ( - "github.com/hpcng/warewulf/internal/pkg/container" "log" "net/http" + + "github.com/hpcng/warewulf/internal/pkg/container" ) func ContainerSend(w http.ResponseWriter, req *http.Request) { diff --git a/internal/pkg/warewulfd/daemon.go b/internal/pkg/warewulfd/daemon.go index f52ffe9f..c28ca1e9 100644 --- a/internal/pkg/warewulfd/daemon.go +++ b/internal/pkg/warewulfd/daemon.go @@ -2,14 +2,15 @@ package warewulfd import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/util" - "github.com/hpcng/warewulf/internal/pkg/wwlog" "io/ioutil" "os" "os/exec" "strconv" "syscall" "time" + + "github.com/hpcng/warewulf/internal/pkg/util" + "github.com/hpcng/warewulf/internal/pkg/wwlog" ) const ( @@ -83,6 +84,34 @@ func DaemonStatus() error { return nil } +func DaemonReload() error { + if util.IsFile(WAREWULFD_PIDFILE) == false { + wwlog.Printf(wwlog.INFO, "Warewulf daemon process not running (%s)\n", WAREWULFD_PIDFILE) + return nil + } + + dat, err := ioutil.ReadFile(WAREWULFD_PIDFILE) + if err != nil { + return err + } + + pid, _ := strconv.Atoi(string(dat)) + process, err := os.FindProcess(pid) + + if err != nil { + fmt.Printf("Failed to find process: %s\n", err) + return err + } else { + err := process.Signal(syscall.Signal(syscall.SIGHUP)) + if err != nil { + fmt.Printf("SIGCONT on pid %d returned: %v\n", pid, err) + return err + } + } + + return nil +} + func DaemonStop() error { if util.IsFile(WAREWULFD_PIDFILE) == false { diff --git a/internal/pkg/warewulfd/ipxe.go b/internal/pkg/warewulfd/ipxe.go index 5fde3bc5..6c3330a0 100644 --- a/internal/pkg/warewulfd/ipxe.go +++ b/internal/pkg/warewulfd/ipxe.go @@ -2,15 +2,16 @@ package warewulfd import ( "fmt" - "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" "log" "net/http" "strconv" "strings" "text/template" + + "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" ) type iPxeTemplate struct { @@ -30,19 +31,14 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) { url := strings.Split(req.URL.Path, "/") var unconfiguredNode bool - nodeDB, err := node.New() - if err != nil { - log.Printf("Could not read node configuration file: %s\n", err) - w.WriteHeader(503) - return - } - if url[2] == "" { log.Printf("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 { wwlog.Printf(wwlog.ERROR, "%s\n", err) @@ -50,16 +46,22 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) { return } - hwaddr := strings.ReplaceAll(url[2], "-", ":") + nodeobj, err := GetNode(hwaddr) - n, err := nodeDB.FindByHwaddr(hwaddr) if err != nil { // If we failed to find a node, let's see if we can add one... var netdev string + nodeDB, err := node.New() + if err != nil { + log.Printf("Could not read node configuration file: %s\n", err) + w.WriteHeader(503) + return + } + wwlog.Printf(wwlog.VERBOSE, "Node was not found, looking for discoverable nodes...\n") - n, netdev, err = nodeDB.FindDiscoverableNode() + n, netdev, err := nodeDB.FindDiscoverableNode() if err != nil { wwlog.Printf(wwlog.WARN, "No nodes are set as discoverable...\n") unconfiguredNode = true @@ -79,6 +81,7 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) { wwlog.Printf(wwlog.ERROR, "Could not persist new node configuration while adding node: %s\n", n.Id.Get()) unconfiguredNode = true } else { + nodeobj = n wwlog.Printf(wwlog.INFO, "Building System Overlay:\n") _ = overlay.BuildSystemOverlay([]node.NodeInfo{n}) wwlog.Printf(wwlog.INFO, "Building Runtime Overlay:\n") @@ -110,9 +113,10 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) { return } else { - log.Printf("IPXE: %15s: %s\n", n.Id.Get(), req.URL.Path) - ipxeTemplate := fmt.Sprintf("/etc/warewulf/ipxe/%s.ipxe", n.Ipxe.Get()) + log.Printf("IPXE: %15s: %s\n", nodeobj.Id.Get(), req.URL.Path) + + ipxeTemplate := fmt.Sprintf("/etc/warewulf/ipxe/%s.ipxe", nodeobj.Ipxe.Get()) tmpl, err := template.ParseFiles(ipxeTemplate) if err != nil { @@ -122,14 +126,14 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) { var replace iPxeTemplate - replace.Fqdn = n.Id.Get() + replace.Fqdn = nodeobj.Id.Get() replace.Ipaddr = conf.Ipaddr replace.Port = strconv.Itoa(conf.Warewulf.Port) - replace.Hostname = n.Id.Get() + replace.Hostname = nodeobj.Id.Get() replace.Hwaddr = url[2] - replace.ContainerName = n.ContainerName.Get() - replace.KernelArgs = n.KernelArgs.Get() - replace.KernelVersion = n.KernelVersion.Get() + replace.ContainerName = nodeobj.ContainerName.Get() + replace.KernelArgs = nodeobj.KernelArgs.Get() + replace.KernelVersion = nodeobj.KernelVersion.Get() err = tmpl.Execute(w, replace) if err != nil { @@ -137,7 +141,7 @@ func IpxeSend(w http.ResponseWriter, req *http.Request) { return } - log.Printf("SEND: %15s: %s\n", n.Id.Get(), ipxeTemplate) + log.Printf("SEND: %15s: %s\n", nodeobj.Id.Get(), ipxeTemplate) } return diff --git a/internal/pkg/warewulfd/kernel.go b/internal/pkg/warewulfd/kernel.go index 4d8d7a5c..85702363 100644 --- a/internal/pkg/warewulfd/kernel.go +++ b/internal/pkg/warewulfd/kernel.go @@ -1,9 +1,10 @@ package warewulfd import ( - "github.com/hpcng/warewulf/internal/pkg/kernel" "log" "net/http" + + "github.com/hpcng/warewulf/internal/pkg/kernel" ) func KernelSend(w http.ResponseWriter, req *http.Request) { diff --git a/internal/pkg/warewulfd/kmods.go b/internal/pkg/warewulfd/kmods.go index 7558de83..73dd34c7 100644 --- a/internal/pkg/warewulfd/kmods.go +++ b/internal/pkg/warewulfd/kmods.go @@ -1,9 +1,10 @@ package warewulfd import ( - "github.com/hpcng/warewulf/internal/pkg/kernel" "log" "net/http" + + "github.com/hpcng/warewulf/internal/pkg/kernel" ) func KmodsSend(w http.ResponseWriter, req *http.Request) { diff --git a/internal/pkg/warewulfd/nodedb.go b/internal/pkg/warewulfd/nodedb.go new file mode 100644 index 00000000..2030e0d8 --- /dev/null +++ b/internal/pkg/warewulfd/nodedb.go @@ -0,0 +1,65 @@ +package warewulfd + +import ( + "sync" + + "github.com/hpcng/warewulf/internal/pkg/errors" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/wwlog" +) + +type nodeDB struct { + lock sync.RWMutex + NodeInfo map[string]node.NodeInfo +} + +var ( + db nodeDB +) + +func LoadNodeDB() error { + + var TmpMap map[string]node.NodeInfo + TmpMap = make(map[string]node.NodeInfo) + + wwlog.Printf(wwlog.INFO, "Loading the node Database\n") + + DB, err := node.New() + if err != nil { + return err + } + + nodes, err := DB.FindAllNodes() + if err != nil { + return err + } + + for _, n := range nodes { + for _, netdev := range n.NetDevs { + wwlog.Printf(wwlog.DEBUG, "Caching node entry: '%s' -> %s\n", netdev.Hwaddr.Get(), n.Id.Get()) + + TmpMap[netdev.Hwaddr.Get()] = n + } + } + + db.lock.Lock() + defer db.lock.Unlock() + db.NodeInfo = TmpMap + + return nil +} + +func GetNode(val string) (node.NodeInfo, error) { + db.lock.RLock() + defer db.lock.RUnlock() + + if _, ok := db.NodeInfo[val]; ok { + wwlog.Printf(wwlog.DEBUG, "Found node:\n%+v\n", db.NodeInfo[val]) + + return db.NodeInfo[val], nil + } + + wwlog.Printf(wwlog.VERBOSE, "Node not found in DB: %s\n", val) + var empty node.NodeInfo + return empty, errors.New("No node found") +} diff --git a/internal/pkg/warewulfd/runtime.go b/internal/pkg/warewulfd/runtime.go index 7f13668d..4b346aaf 100644 --- a/internal/pkg/warewulfd/runtime.go +++ b/internal/pkg/warewulfd/runtime.go @@ -2,13 +2,14 @@ package warewulfd import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/config" - "github.com/hpcng/warewulf/internal/pkg/node" - "github.com/hpcng/warewulf/internal/pkg/warewulfconf" "log" "net/http" "strconv" "strings" + + "github.com/hpcng/warewulf/internal/pkg/config" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/warewulfconf" ) func RuntimeOverlaySend(w http.ResponseWriter, req *http.Request) { diff --git a/internal/pkg/warewulfd/system.go b/internal/pkg/warewulfd/system.go index 3a92a7a5..892d0fc4 100644 --- a/internal/pkg/warewulfd/system.go +++ b/internal/pkg/warewulfd/system.go @@ -1,9 +1,10 @@ package warewulfd import ( - "github.com/hpcng/warewulf/internal/pkg/config" "log" "net/http" + + "github.com/hpcng/warewulf/internal/pkg/config" ) func SystemOverlaySend(w http.ResponseWriter, req *http.Request) { diff --git a/internal/pkg/warewulfd/util.go b/internal/pkg/warewulfd/util.go index 3e5403ab..f7ebb401 100644 --- a/internal/pkg/warewulfd/util.go +++ b/internal/pkg/warewulfd/util.go @@ -1,35 +1,31 @@ package warewulfd import ( - "fmt" - "github.com/hpcng/warewulf/internal/pkg/errors" - "github.com/hpcng/warewulf/internal/pkg/node" "io" "log" "net/http" "os" "strconv" "strings" + + "github.com/hpcng/warewulf/internal/pkg/errors" + "github.com/hpcng/warewulf/internal/pkg/node" ) func getSanity(req *http.Request) (node.NodeInfo, error) { url := strings.Split(req.URL.Path, "/") - var ret node.NodeInfo - - nodes, err := node.New() - if err != nil { - return ret, errors.New(fmt.Sprintf("%s", err)) - } hwaddr := strings.ReplaceAll(url[2], "-", ":") - ret, err = nodes.FindByHwaddr(hwaddr) + + nodeobj, err := GetNode(hwaddr) if err != nil { + var ret node.NodeInfo return ret, errors.New("Could not find node by HW address") } - log.Printf("REQ: %15s: %s\n", ret.Id.Get(), req.URL.Path) + log.Printf("REQ: %15s: %s\n", nodeobj.Id.Get(), req.URL.Path) - return ret, nil + return nodeobj, nil } func sendFile(w http.ResponseWriter, filename string, sendto string) error { diff --git a/internal/pkg/warewulfd/warewulfd.go b/internal/pkg/warewulfd/warewulfd.go index ba90adcc..73ff9069 100644 --- a/internal/pkg/warewulfd/warewulfd.go +++ b/internal/pkg/warewulfd/warewulfd.go @@ -1,8 +1,12 @@ package warewulfd import ( - "github.com/hpcng/warewulf/internal/pkg/wwlog" "net/http" + "os" + "os/signal" + "syscall" + + "github.com/hpcng/warewulf/internal/pkg/wwlog" ) // TODO: https://github.com/danderson/netboot/blob/master/pixiecore/dhcp.go @@ -10,6 +14,23 @@ import ( func RunServer() error { + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGHUP) + + go func() { + for _ = range c { + err := LoadNodeDB() + if err != nil { + wwlog.Printf(wwlog.WARN, "Could not load database: %s\n", err) + } + } + }() + + err := LoadNodeDB() + if err != nil { + wwlog.Printf(wwlog.WARN, "Could not load database: %s\n", err) + } + wwlog.Printf(wwlog.DEBUG, "Registering handlers for the web service\n") http.HandleFunc("/ipxe/", IpxeSend) @@ -21,7 +42,11 @@ func RunServer() error { wwlog.Printf(wwlog.VERBOSE, "Starting HTTPD REST service\n") - http.ListenAndServe(":9873", nil) + err = http.ListenAndServe(":9873", nil) + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not start listening service: %s\n", err) + os.Exit(1) + } return nil } diff --git a/internal/pkg/wwlog/wwlog.go b/internal/pkg/wwlog/wwlog.go index 1b240d7f..d608d30d 100644 --- a/internal/pkg/wwlog/wwlog.go +++ b/internal/pkg/wwlog/wwlog.go @@ -6,17 +6,17 @@ import ( ) const ( - CRITICAL = 0 - ERROR = 1 - WARN = 2 - INFO = 3 - VERBOSE = 4 - DEBUG = 5 + CRITICAL = 0 + ERROR = 1 + WARN = 2 + INFO = 3 + VERBOSE = 4 + DEBUG = 5 ) var ( logLevel = INFO - Indent string + Indent string ) func SetLevel(level int) { @@ -37,17 +37,17 @@ func SetIndent(i int) { func prefixLevel(level int) { if level == DEBUG { - log.SetPrefix("[DEBUG] "+Indent) + log.SetPrefix("[DEBUG] " + Indent) } else if level == VERBOSE { - log.SetPrefix("[VERBOSE] "+Indent) + log.SetPrefix("[VERBOSE] " + Indent) } else if level == INFO { - log.SetPrefix("[INFO] "+Indent) + log.SetPrefix("[INFO] " + Indent) } else if level == WARN { - log.SetPrefix("[WARN] "+Indent) + log.SetPrefix("[WARN] " + Indent) } else if level == ERROR { - log.SetPrefix("[ERROR] "+Indent) + log.SetPrefix("[ERROR] " + Indent) } else if level == CRITICAL { - log.SetPrefix("[CRITICAL] "+Indent) + log.SetPrefix("[CRITICAL] " + Indent) } } @@ -57,14 +57,14 @@ func Println(level int, message string) { log.Println(message) } - log.SetPrefix("[LOG] "+Indent) + log.SetPrefix("[LOG] " + Indent) } -func Printf(level int, message string, a...interface{}) { +func Printf(level int, message string, a ...interface{}) { if level <= logLevel { prefixLevel(level) log.Printf(message, a...) } - log.SetPrefix("[LOG] "+Indent) + log.SetPrefix("[LOG] " + Indent) } diff --git a/overlays/system/default/warewulf/init.d/50-ipmi b/overlays/system/default/warewulf/init.d/50-ipmi index 0a2b3c88..bfe83eea 100755 --- a/overlays/system/default/warewulf/init.d/50-ipmi +++ b/overlays/system/default/warewulf/init.d/50-ipmi @@ -84,8 +84,7 @@ ipmitool channel setaccess 1 2 link=on ipmi=on callin=on privilege=4 ipmitool sol set force-encryption true 1 ipmitool sol set force-authentication true 1 ipmitool sol set privilege-level admin 1 -#ipmitool sol payload enable 1 4 -ipmitool sol payload enable 1 2 1 +ipmitool sol payload enable 1 2 ipmitool sol set enabled true 1 1 speed=38.4 # 19.2 38.4 115.2 ipmitool sol set non-volatile-bit-rate $speed 1 diff --git a/warewulf.spec.in b/warewulf.spec.in index 5eb87cc7..d41ccfec 100644 --- a/warewulf.spec.in +++ b/warewulf.spec.in @@ -44,5 +44,5 @@ rm -rf $RPM_BUILD_ROOT /var/warewulf %changelog -* Tue Jan 26 14:46:24 JST 2021 Brian Clemens - 4.0.0 -- Initial release \ No newline at end of file +* Tue Jan 26 2021 14:46:24 JST Brian Clemens - 4.0.0 +- Initial release