Merge branch 'development' into issue/690
This commit is contained in:
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/api/apiconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
@@ -24,9 +24,10 @@ import (
|
||||
|
||||
func main() {
|
||||
log.Println("Client running")
|
||||
conf := warewulfconf.New()
|
||||
|
||||
// Read the config file.
|
||||
config, err := apiconfig.NewClient(path.Join(buildconfig.SYSCONFDIR(), "warewulf/wwapic.conf"))
|
||||
config, err := apiconfig.NewClient(path.Join(conf.Paths.Sysconfdir, "warewulf/wwapic.conf"))
|
||||
if err != nil {
|
||||
log.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
"github.com/hpcng/warewulf/internal/pkg/api/container"
|
||||
apinode "github.com/hpcng/warewulf/internal/pkg/api/node"
|
||||
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/version"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials"
|
||||
@@ -34,8 +34,9 @@ var apiVersion string
|
||||
func main() {
|
||||
log.Println("Server running")
|
||||
|
||||
conf := warewulfconf.New()
|
||||
// Read the config file.
|
||||
config, err := apiconfig.NewServer(path.Join(buildconfig.SYSCONFDIR(), "warewulf/wwapid.conf"))
|
||||
config, err := apiconfig.NewServer(path.Join(conf.Paths.Sysconfdir, "warewulf/wwapid.conf"))
|
||||
if err != nil {
|
||||
log.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
@@ -18,20 +18,20 @@ import (
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/api/apiconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
|
||||
gw "github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
|
||||
|
||||
"path"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
)
|
||||
|
||||
func run() error {
|
||||
|
||||
log.Println("test0")
|
||||
|
||||
conf := warewulfconf.New()
|
||||
// Read the config file.
|
||||
config, err := apiconfig.NewClientServer(path.Join(buildconfig.SYSCONFDIR(), "warewulf/wwapird.conf"))
|
||||
config, err := apiconfig.NewClientServer(path.Join(conf.Paths.Sysconfdir, "warewulf/wwapird.conf"))
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to read config file, err: %v", err)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
|
||||
"github.com/coreos/go-systemd/daemon"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/pidfile"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
@@ -50,10 +49,7 @@ func GetRootCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
conf, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conf := warewulfconf.New()
|
||||
|
||||
pid, err := pidfile.Write(PIDFile)
|
||||
if err != nil && pid == -1 {
|
||||
@@ -62,7 +58,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
return errors.New("found pidfile " + PIDFile + " not starting")
|
||||
}
|
||||
|
||||
if os.Args[0] == path.Join(buildconfig.WWCLIENTDIR(), "wwclient") {
|
||||
if os.Args[0] == path.Join(conf.Paths.WWClientdir, "wwclient") {
|
||||
err := os.Chdir("/")
|
||||
if err != nil {
|
||||
wwlog.Error("failed to change dir: %s", err)
|
||||
@@ -74,7 +70,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
fmt.Printf("Called via: %s\n", os.Args[0])
|
||||
fmt.Printf("Runtime overlay is being put in '/warewulf/wwclient-test' rather than '/'\n")
|
||||
fmt.Printf("For full functionality call with: %s\n", path.Join(buildconfig.WWCLIENTDIR(), "wwclient"))
|
||||
fmt.Printf("For full functionality call with: %s\n", path.Join(conf.Paths.WWClientdir, "wwclient"))
|
||||
err := os.MkdirAll("/warewulf/wwclient-test", 0755)
|
||||
if err != nil {
|
||||
wwlog.Error("failed to create dir: %s", err)
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
if os.Getpid() != 1 {
|
||||
wwlog.Error("PID is not 1: %d", os.Getpid())
|
||||
os.Exit(1)
|
||||
@@ -33,10 +33,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
wwlog.Error("Unknown Warewulf container: %s", containerName)
|
||||
os.Exit(1)
|
||||
}
|
||||
conf, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
wwlog.Verbose("Couldn't get warewulf ocnfiguration: %s", err)
|
||||
}
|
||||
conf := warewulfconf.New()
|
||||
mountPts := conf.MountsContainer
|
||||
mountPts = append(container.InitMountPnts(binds), mountPts...)
|
||||
// check for valid mount points
|
||||
|
||||
23
internal/app/wwctl/genconf/completions/main.go
Normal file
23
internal/app/wwctl/genconf/completions/main.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package completions
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
myArg := "bash"
|
||||
if len(args) == 1 {
|
||||
myArg = args[0]
|
||||
}
|
||||
switch myArg {
|
||||
case "zsh":
|
||||
err = cmd.Parent().Parent().GenZshCompletion(os.Stdout)
|
||||
case "fish":
|
||||
err = cmd.Parent().Parent().GenFishCompletion(os.Stdout, true)
|
||||
default:
|
||||
err = cmd.Parent().Parent().GenBashCompletion(os.Stdout)
|
||||
}
|
||||
return
|
||||
}
|
||||
22
internal/app/wwctl/genconf/completions/root.go
Normal file
22
internal/app/wwctl/genconf/completions/root.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package completions
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
Use: "completions",
|
||||
Short: "shell completion",
|
||||
Long: "This command generates the bash completions if no argument is given.",
|
||||
RunE: CobraRunE,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Aliases: []string{"bash"},
|
||||
}
|
||||
Zsh bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
}
|
||||
|
||||
func GetCommand() *cobra.Command {
|
||||
return baseCmd
|
||||
}
|
||||
13
internal/app/wwctl/genconf/dfaults/main.go
Normal file
13
internal/app/wwctl/genconf/dfaults/main.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package dfaults
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
fmt.Println(node.FallBackConf)
|
||||
return
|
||||
}
|
||||
21
internal/app/wwctl/genconf/dfaults/root.go
Normal file
21
internal/app/wwctl/genconf/dfaults/root.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package dfaults
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
Use: "defaults",
|
||||
Short: "print defaults",
|
||||
Long: "This command prints the fallbacks which are used if defaults.conf isn't present",
|
||||
RunE: CobraRunE,
|
||||
Args: cobra.NoArgs,
|
||||
Aliases: []string{"dfaults"},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
}
|
||||
|
||||
func GetCommand() *cobra.Command {
|
||||
return baseCmd
|
||||
}
|
||||
15
internal/app/wwctl/genconf/man/main.go
Normal file
15
internal/app/wwctl/genconf/man/main.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package man
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/cobra/doc"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
header := &doc.GenManHeader{
|
||||
Title: "WWCTL",
|
||||
Section: "1",
|
||||
}
|
||||
err = doc.GenManTree(cmd.Parent().Parent(), header, args[0])
|
||||
return
|
||||
}
|
||||
23
internal/app/wwctl/genconf/man/root.go
Normal file
23
internal/app/wwctl/genconf/man/root.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package man
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
Use: "man",
|
||||
Short: "manpage generation",
|
||||
Long: "This command generates the man pages for all commands, needs target dir as argument",
|
||||
RunE: CobraRunE,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Aliases: []string{"man_pages"},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
}
|
||||
|
||||
func GetCommand() *cobra.Command {
|
||||
return baseCmd
|
||||
}
|
||||
17
internal/app/wwctl/genconf/reference/main.go
Normal file
17
internal/app/wwctl/genconf/reference/main.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package reference
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/cobra/doc"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
linkHandler := func(name, ref string) string {
|
||||
return fmt.Sprintf(":ref:`%s <%s>`", name, ref)
|
||||
}
|
||||
err = doc.GenReSTTreeCustom(cmd.Parent().Parent(), args[0], func(arg string) string { return "" }, linkHandler)
|
||||
//err = doc.GenReSTTree(cmd.Parent().Parent(), args[0])
|
||||
return
|
||||
}
|
||||
22
internal/app/wwctl/genconf/reference/root.go
Normal file
22
internal/app/wwctl/genconf/reference/root.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package reference
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
Use: "reference",
|
||||
Short: "reference generation",
|
||||
Long: "This command generates the references in ReStructured Text, needs target dir as argument",
|
||||
RunE: CobraRunE,
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
}
|
||||
|
||||
func GetCommand() *cobra.Command {
|
||||
return baseCmd
|
||||
}
|
||||
35
internal/app/wwctl/genconf/root.go
Normal file
35
internal/app/wwctl/genconf/root.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package genconf
|
||||
|
||||
import (
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/genconf/completions"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/genconf/dfaults"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/genconf/man"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/genconf/reference"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/genconf/warewulfconf"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
Use: "genconfig",
|
||||
Short: "Generate various configurations",
|
||||
Long: "This command will allow you to generate different configurations like bash-completions.",
|
||||
Args: cobra.ExactArgs(0),
|
||||
Aliases: []string{"cnf"},
|
||||
}
|
||||
ListFull bool
|
||||
WWctlRoot *cobra.Command
|
||||
)
|
||||
|
||||
func init() {
|
||||
baseCmd.AddCommand(completions.GetCommand())
|
||||
baseCmd.AddCommand(man.GetCommand())
|
||||
baseCmd.AddCommand(reference.GetCommand())
|
||||
baseCmd.AddCommand(dfaults.GetCommand())
|
||||
baseCmd.AddCommand(warewulfconf.GetCommand())
|
||||
}
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
func GetCommand() *cobra.Command {
|
||||
return baseCmd
|
||||
}
|
||||
19
internal/app/wwctl/genconf/warewulfconf/print/main.go
Normal file
19
internal/app/wwctl/genconf/warewulfconf/print/main.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package print
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
conf := warewulfconf.New()
|
||||
buffer, err := yaml.Marshal(&conf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println(string(buffer))
|
||||
return
|
||||
}
|
||||
22
internal/app/wwctl/genconf/warewulfconf/print/root.go
Normal file
22
internal/app/wwctl/genconf/warewulfconf/print/root.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package print
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
Use: "print",
|
||||
Short: "print wareweulf.conf",
|
||||
Long: "This command prints the actual used warewulf.conf, can be used to create an empty valid warewulf.conf",
|
||||
RunE: CobraRunE,
|
||||
Args: cobra.ExactArgs(0),
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
}
|
||||
|
||||
func GetCommand() *cobra.Command {
|
||||
return baseCmd
|
||||
}
|
||||
27
internal/app/wwctl/genconf/warewulfconf/root.go
Normal file
27
internal/app/wwctl/genconf/warewulfconf/root.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package warewulfconf
|
||||
|
||||
import (
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/genconf/warewulfconf/print"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
Use: "warewulfconf",
|
||||
Short: "access warewulf.conf",
|
||||
Long: "Commands for accessing the actual used warewulf.conf",
|
||||
Args: cobra.ExactArgs(0),
|
||||
Aliases: []string{"cnf"},
|
||||
}
|
||||
ListFull bool
|
||||
WWctlRoot *cobra.Command
|
||||
)
|
||||
|
||||
func init() {
|
||||
baseCmd.AddCommand(print.GetCommand())
|
||||
}
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
func GetCommand() *cobra.Command {
|
||||
return baseCmd
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package add
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
apinode "github.com/hpcng/warewulf/internal/pkg/api/node"
|
||||
@@ -11,24 +9,33 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
// remove the default network as the all network values are assigned
|
||||
// to this network
|
||||
if NetName != "" {
|
||||
netDev := *NodeConf.NetDevs["default"]
|
||||
NodeConf.NetDevs[NetName] = &netDev
|
||||
delete(NodeConf.NetDevs, "default")
|
||||
|
||||
/*
|
||||
RunE needs a function of type func(*cobraCommand,[]string) err, but
|
||||
in order to avoid global variables which mess up testing a function of
|
||||
the required type is returned
|
||||
*/
|
||||
func CobraRunE(vars *variables) func(cmd *cobra.Command, args []string) error {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
// remove the default network as all network values are assigned
|
||||
// to this network
|
||||
if _, ok := vars.nodeConf.NetDevs["default"]; ok && vars.netName != "" {
|
||||
netDev := *vars.nodeConf.NetDevs["default"]
|
||||
vars.nodeConf.NetDevs[vars.netName] = &netDev
|
||||
delete(vars.nodeConf.NetDevs, "default")
|
||||
} else {
|
||||
if vars.nodeConf.NetDevs["default"].Empty() {
|
||||
delete(vars.nodeConf.NetDevs, "default")
|
||||
}
|
||||
}
|
||||
buffer, err := yaml.Marshal(vars.nodeConf)
|
||||
if err != nil {
|
||||
wwlog.Error("Cant marshall nodeInfo", err)
|
||||
return err
|
||||
}
|
||||
set := wwapiv1.NodeAddParameter{
|
||||
NodeConfYaml: string(buffer[:]),
|
||||
NodeNames: args,
|
||||
}
|
||||
return apinode.NodeAdd(&set)
|
||||
}
|
||||
buffer, err := yaml.Marshal(NodeConf)
|
||||
if err != nil {
|
||||
wwlog.Error("Cant marshall nodeInfo", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
set := wwapiv1.NodeAddParameter{
|
||||
NodeConfYaml: string(buffer[:]),
|
||||
NodeNames: args,
|
||||
}
|
||||
|
||||
return apinode.NodeAdd(&set)
|
||||
}
|
||||
|
||||
221
internal/app/wwctl/node/add/main_test.go
Normal file
221
internal/app/wwctl/node/add/main_test.go
Normal file
@@ -0,0 +1,221 @@
|
||||
package add
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Add(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
wantErr bool
|
||||
stdout string
|
||||
outDb string
|
||||
}{
|
||||
{name: "single node add",
|
||||
args: []string{"n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
`},
|
||||
{name: "single node add, profile foo",
|
||||
args: []string{"--profile=foo", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- foo
|
||||
`},
|
||||
{name: "single node add with Kernel args",
|
||||
args: []string{"--kernelargs=foo", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
kernel:
|
||||
args: foo
|
||||
profiles:
|
||||
- default
|
||||
`},
|
||||
{name: "double node add explicit",
|
||||
args: []string{"n01", "n02"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
n02:
|
||||
profiles:
|
||||
- default
|
||||
`},
|
||||
{name: "single node with ipaddr6",
|
||||
args: []string{"--ipaddr6=fdaa::1", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
default:
|
||||
ip6addr: fdaa::1
|
||||
`},
|
||||
{name: "single node with ipaddr",
|
||||
args: []string{"--ipaddr=10.0.0.1", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
default:
|
||||
ipaddr: 10.0.0.1
|
||||
`},
|
||||
{name: "three nodes with ipaddr",
|
||||
args: []string{"--ipaddr=10.10.0.1", "n[01-02,03]"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
default:
|
||||
ipaddr: 10.10.0.1
|
||||
n02:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
default:
|
||||
ipaddr: 10.10.0.2
|
||||
n03:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
default:
|
||||
ipaddr: 10.10.0.3
|
||||
`},
|
||||
{name: "three nodes with ipaddr different network",
|
||||
args: []string{"--ipaddr=10.10.0.1", "--netname=foo", "n[01-03]"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
foo:
|
||||
ipaddr: 10.10.0.1
|
||||
n02:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
foo:
|
||||
ipaddr: 10.10.0.2
|
||||
n03:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
foo:
|
||||
ipaddr: 10.10.0.3
|
||||
`},
|
||||
{name: "three nodes with ipaddr different network, with ipmiaddr",
|
||||
args: []string{"--ipaddr=10.10.0.1", "--netname=foo", "--ipmiaddr=10.20.0.1", "n[01-03]"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
ipmi:
|
||||
ipaddr: 10.20.0.1
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
foo:
|
||||
ipaddr: 10.10.0.1
|
||||
n02:
|
||||
ipmi:
|
||||
ipaddr: 10.20.0.2
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
foo:
|
||||
ipaddr: 10.10.0.2
|
||||
n03:
|
||||
ipmi:
|
||||
ipaddr: 10.20.0.3
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
foo:
|
||||
ipaddr: 10.10.0.3
|
||||
`},
|
||||
}
|
||||
conf_yml := `
|
||||
WW_INTERNAL: 0
|
||||
`
|
||||
nodes_yml := `
|
||||
WW_INTERNAL: 43
|
||||
`
|
||||
conf := warewulfconf.New()
|
||||
err := conf.Read([]byte(conf_yml))
|
||||
assert.NoError(t, err)
|
||||
db, err := node.TestNew([]byte(nodes_yml))
|
||||
assert.NoError(t, err)
|
||||
warewulfd.SetNoDaemon()
|
||||
for _, tt := range tests {
|
||||
db, err = node.TestNew([]byte(nodes_yml))
|
||||
assert.NoError(t, err)
|
||||
t.Logf("Running test: %s\n", tt.name)
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
baseCmd := GetCommand()
|
||||
baseCmd.SetArgs(tt.args)
|
||||
buf := new(bytes.Buffer)
|
||||
baseCmd.SetOut(buf)
|
||||
baseCmd.SetErr(buf)
|
||||
err = baseCmd.Execute()
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Got unwanted error: %s", err)
|
||||
t.FailNow()
|
||||
}
|
||||
dump := string(db.DBDump())
|
||||
if dump != tt.outDb {
|
||||
t.Errorf("DB dump is wrong, got:'%s'\nwant:'%s'", dump, tt.outDb)
|
||||
t.FailNow()
|
||||
}
|
||||
if buf.String() != tt.stdout {
|
||||
t.Errorf("Got wrong output, got:'%s'\nwant:'%s'", buf.String(), tt.stdout)
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -10,23 +10,26 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
// Holds the variables which are needed in CobraRunE
|
||||
type variables struct {
|
||||
netName string
|
||||
nodeConf node.NodeConf
|
||||
}
|
||||
|
||||
// Returns the newly created command
|
||||
func GetCommand() *cobra.Command {
|
||||
vars := variables{}
|
||||
vars.nodeConf = node.NewConf()
|
||||
baseCmd := &cobra.Command{
|
||||
DisableFlagsInUseLine: true,
|
||||
Use: "add [OPTIONS] NODENAME",
|
||||
Short: "Add new node to Warewulf",
|
||||
Long: "This command will add a new node named NODENAME to Warewulf.",
|
||||
RunE: CobraRunE,
|
||||
RunE: CobraRunE(&vars),
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
}
|
||||
NodeConf node.NodeConf
|
||||
NetName string
|
||||
)
|
||||
|
||||
func init() {
|
||||
NodeConf = node.NewConf()
|
||||
NodeConf.CreateFlags(baseCmd, []string{})
|
||||
baseCmd.PersistentFlags().StringVar(&NetName, "netname", "", "Set network name for network options")
|
||||
vars.nodeConf.CreateFlags(baseCmd, []string{"tagdel", "nettagdel", "ipmitagdel"})
|
||||
baseCmd.PersistentFlags().StringVar(&vars.netName, "netname", "", "Set network name for network options")
|
||||
|
||||
// register the command line completions
|
||||
if err := baseCmd.RegisterFlagCompletionFunc("container", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
@@ -65,9 +68,6 @@ func init() {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
func GetCommand() *cobra.Command {
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
return baseCmd
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package nodestatus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -19,15 +18,11 @@ import (
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
|
||||
controller, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
wwlog.Error("%s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
controller := warewulfconf.New()
|
||||
|
||||
if controller.Ipaddr == "" {
|
||||
wwlog.Error("The Warewulf Server IP Address is not properly configured")
|
||||
os.Exit(1)
|
||||
return fmt.Errorf("warewulf Server IP Address is not properly configured")
|
||||
|
||||
}
|
||||
|
||||
for {
|
||||
|
||||
@@ -14,11 +14,7 @@ import (
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
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("Could not open node configuration: %s", err)
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package wwctl
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/configure"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/container"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/genconf"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/kernel"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/node"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/overlay"
|
||||
@@ -12,11 +15,9 @@ import (
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/ssh"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/version"
|
||||
"github.com/hpcng/warewulf/internal/pkg/help"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/cobra/doc"
|
||||
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -29,9 +30,11 @@ var (
|
||||
SilenceUsage: true,
|
||||
SilenceErrors: true,
|
||||
}
|
||||
verboseArg bool
|
||||
DebugFlag bool
|
||||
LogLevel int
|
||||
verboseArg bool
|
||||
DebugFlag bool
|
||||
LogLevel int
|
||||
WarewulfConfArg string
|
||||
AllowEmptyConf bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -39,9 +42,11 @@ func init() {
|
||||
rootCmd.PersistentFlags().BoolVarP(&DebugFlag, "debug", "d", false, "Run with debugging messages enabled.")
|
||||
rootCmd.PersistentFlags().IntVar(&LogLevel, "loglevel", wwlog.INFO, "Set log level to given string")
|
||||
_ = rootCmd.PersistentFlags().MarkHidden("loglevel")
|
||||
rootCmd.PersistentFlags().StringVar(&WarewulfConfArg, "warewulfconf", "", "Set the warewulf configuration file")
|
||||
rootCmd.PersistentFlags().BoolVar(&AllowEmptyConf, "emptyconf", false, "Allow empty configuration")
|
||||
_ = rootCmd.PersistentFlags().MarkHidden("emptyconf")
|
||||
rootCmd.SetUsageTemplate(help.UsageTemplate)
|
||||
rootCmd.SetHelpTemplate(help.HelpTemplate)
|
||||
|
||||
rootCmd.AddCommand(overlay.GetCommand())
|
||||
rootCmd.AddCommand(container.GetCommand())
|
||||
rootCmd.AddCommand(node.GetCommand())
|
||||
@@ -52,6 +57,7 @@ func init() {
|
||||
rootCmd.AddCommand(server.GetCommand())
|
||||
rootCmd.AddCommand(version.GetCommand())
|
||||
rootCmd.AddCommand(ssh.GetCommand())
|
||||
rootCmd.AddCommand(genconf.GetCommand())
|
||||
}
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
@@ -59,7 +65,7 @@ func GetRootCommand() *cobra.Command {
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
func rootPersistentPreRunE(cmd *cobra.Command, args []string) error {
|
||||
func rootPersistentPreRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
if DebugFlag {
|
||||
wwlog.SetLogLevel(wwlog.DEBUG)
|
||||
} else if verboseArg {
|
||||
@@ -70,21 +76,17 @@ func rootPersistentPreRunE(cmd *cobra.Command, args []string) error {
|
||||
if LogLevel != wwlog.INFO {
|
||||
wwlog.SetLogLevel(LogLevel)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// External functions not used by the wwctl command line
|
||||
|
||||
// Generate Bash completion file
|
||||
func GenBashCompletion(w io.Writer) error {
|
||||
return rootCmd.GenBashCompletion(w)
|
||||
}
|
||||
|
||||
// Generate man pages
|
||||
func GenManTree(fileName string) error {
|
||||
header := &doc.GenManHeader{
|
||||
Title: "WWCTL",
|
||||
Section: "1",
|
||||
conf := warewulfconf.New()
|
||||
if !AllowEmptyConf && !conf.Initialized() {
|
||||
if WarewulfConfArg != "" {
|
||||
err = conf.ReadConf(WarewulfConfArg)
|
||||
} else if os.Getenv("WAREWULFCONF") != "" {
|
||||
err = conf.ReadConf(os.Getenv("WAREWULFCONF"))
|
||||
} else {
|
||||
err = conf.ReadConf(warewulfconf.ConfigFile)
|
||||
}
|
||||
} else {
|
||||
err = conf.SetDynamicDefaults()
|
||||
}
|
||||
return doc.GenManTree(rootCmd, header, fileName)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -10,10 +10,7 @@ import (
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
|
||||
if SetForeground {
|
||||
conf, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not read Warewulf configuration file")
|
||||
}
|
||||
conf := warewulfconf.New()
|
||||
conf.Warewulf.Syslog = false
|
||||
return errors.Wrap(warewulfd.RunServer(), "failed to start Warewulf server")
|
||||
} else {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -2,33 +2,35 @@ package batch
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
/* Submits 10 jobs into a pool that supports 2 simultaneous jobs, and
|
||||
tests that only two of the jobs ran at a time by capturing the time
|
||||
that they ran and comparing against the start time. */
|
||||
func TestBatchPool (t *testing.T) {
|
||||
pool := New(2)
|
||||
var times []time.Time
|
||||
for i := 0; i <= 10; i++ {
|
||||
pool.Submit(func() {
|
||||
times = append(times, time.Now())
|
||||
time.Sleep(1 * time.Second)
|
||||
})
|
||||
}
|
||||
startTime := time.Now()
|
||||
pool.Run()
|
||||
assert.Equal(t, 0 * time.Second, times[0].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 0 * time.Second, times[1].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 1 * time.Second, times[2].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 1 * time.Second, times[3].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 2 * time.Second, times[4].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 2 * time.Second, times[5].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 3 * time.Second, times[6].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 3 * time.Second, times[7].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 4 * time.Second, times[8].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 4 * time.Second, times[9].Sub(startTime).Round(time.Second))
|
||||
/*
|
||||
Submits 10 jobs into a pool that supports 2 simultaneous jobs, and
|
||||
|
||||
tests that only two of the jobs ran at a time by capturing the time
|
||||
that they ran and comparing against the start time.
|
||||
*/
|
||||
func TestBatchPool(t *testing.T) {
|
||||
/*
|
||||
pool := New(2)
|
||||
var times []time.Time
|
||||
for i := 0; i <= 10; i++ {
|
||||
pool.Submit(func() {
|
||||
times = append(times, time.Now())
|
||||
time.Sleep(1 * time.Second)
|
||||
})
|
||||
}
|
||||
startTime := time.Now()
|
||||
pool.Run()
|
||||
assert.Equal(t, 0 * time.Second, times[0].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 0 * time.Second, times[1].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 1 * time.Second, times[2].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 1 * time.Second, times[3].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 2 * time.Second, times[4].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 2 * time.Second, times[5].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 3 * time.Second, times[6].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 3 * time.Second, times[7].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 4 * time.Second, times[8].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 4 * time.Second, times[9].Sub(startTime).Round(time.Second))
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
package buildconfig
|
||||
|
||||
import "github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
|
||||
const WWVer = 43
|
||||
|
||||
var (
|
||||
bindir string = "UNDEF"
|
||||
sysconfdir string = "UNDEF"
|
||||
localstatedir string = "UNDEF"
|
||||
srvdir string = "UNDEF"
|
||||
tftpdir string = "UNDEF"
|
||||
firewallddir string = "UNDEF"
|
||||
systemddir string = "UNDEF"
|
||||
wwoverlaydir string = "UNDEF"
|
||||
wwchrootdir string = "UNDEF"
|
||||
wwprovisiondir string = "UNDEF"
|
||||
version string = "UNDEF"
|
||||
release string = "UNDEF"
|
||||
wwclientdir string = "UNDEF"
|
||||
datadir string = "UNDEF"
|
||||
tmpdir string = "UNDEF"
|
||||
)
|
||||
|
||||
func BINDIR() string {
|
||||
wwlog.Debug("BINDIR = '%s'", bindir)
|
||||
return bindir
|
||||
}
|
||||
|
||||
func DATADIR() string {
|
||||
wwlog.Debug("DATADIR = '%s'", datadir)
|
||||
return datadir
|
||||
}
|
||||
|
||||
func SYSCONFDIR() string {
|
||||
wwlog.Debug("SYSCONFDIR = '%s'", sysconfdir)
|
||||
return sysconfdir
|
||||
}
|
||||
|
||||
func LOCALSTATEDIR() string {
|
||||
wwlog.Debug("LOCALSTATEDIR = '%s'", localstatedir)
|
||||
return localstatedir
|
||||
}
|
||||
|
||||
func SRVDIR() string {
|
||||
wwlog.Debug("SRVDIR = '%s'", srvdir)
|
||||
return srvdir
|
||||
}
|
||||
|
||||
func TFTPDIR() string {
|
||||
wwlog.Debug("TFTPDIR = '%s'", tftpdir)
|
||||
return tftpdir
|
||||
}
|
||||
|
||||
func FIREWALLDDIR() string {
|
||||
wwlog.Debug("FIREWALLDDIR = '%s'", firewallddir)
|
||||
return firewallddir
|
||||
}
|
||||
|
||||
func SYSTEMDDIR() string {
|
||||
wwlog.Debug("SYSTEMDDIR = '%s'", systemddir)
|
||||
return systemddir
|
||||
}
|
||||
|
||||
func WWOVERLAYDIR() string {
|
||||
wwlog.Debug("WWOVERLAYDIR = '%s'", wwoverlaydir)
|
||||
return wwoverlaydir
|
||||
}
|
||||
|
||||
func WWCHROOTDIR() string {
|
||||
wwlog.Debug("WWCHROOTDIR = '%s'", wwchrootdir)
|
||||
return wwchrootdir
|
||||
}
|
||||
|
||||
func WWPROVISIONDIR() string {
|
||||
wwlog.Debug("WWPROVISIONDIR = '%s'", wwprovisiondir)
|
||||
return wwprovisiondir
|
||||
}
|
||||
|
||||
func VERSION() string {
|
||||
wwlog.Debug("VERSION = '%s'", version)
|
||||
return version
|
||||
}
|
||||
|
||||
func RELEASE() string {
|
||||
wwlog.Debug("RELEASE = '%s'", release)
|
||||
return release
|
||||
}
|
||||
|
||||
func WWCLIENTDIR() string {
|
||||
wwlog.Debug("WWCLIENTDIR = '%s'", wwclientdir)
|
||||
return wwclientdir
|
||||
}
|
||||
|
||||
func TMPDIR() string {
|
||||
wwlog.Debug("TMPDIR = '%s'", tmpdir)
|
||||
return tmpdir
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package buildconfig
|
||||
|
||||
func init() {
|
||||
bindir = "@BINDIR@"
|
||||
sysconfdir = "@SYSCONFDIR@"
|
||||
datadir = "@DATADIR@"
|
||||
localstatedir = "@LOCALSTATEDIR@"
|
||||
srvdir = "@SRVDIR@"
|
||||
tftpdir = "@TFTPDIR@"
|
||||
firewallddir = "@FIREWALLDDIR@"
|
||||
systemddir = "@SYSTEMDDIR@"
|
||||
wwoverlaydir = "@WWOVERLAYDIR@"
|
||||
wwchrootdir = "@WWCHROOTDIR@"
|
||||
wwprovisiondir = "@WWPROVISIONDIR@"
|
||||
version = "@VERSION@"
|
||||
release = "@RELEASE@"
|
||||
wwclientdir = "@WWCLIENTDIR@"
|
||||
tmpdir = "@TMPDIR@"
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -14,10 +14,10 @@ import (
|
||||
func SSH() error {
|
||||
if os.Getuid() == 0 {
|
||||
fmt.Printf("Updating system keys\n")
|
||||
conf := warewulfconf.New()
|
||||
wwkeydir := path.Join(conf.Paths.Sysconfdir, "warewulf/keys") + "/"
|
||||
|
||||
wwkeydir := path.Join(buildconfig.SYSCONFDIR(), "warewulf/keys") + "/"
|
||||
|
||||
err := os.MkdirAll(path.Join(buildconfig.SYSCONFDIR(), "warewulf/keys"), 0755)
|
||||
err := os.MkdirAll(path.Join(conf.Paths.Sysconfdir, "warewulf/keys"), 0755)
|
||||
if err != nil {
|
||||
wwlog.Error("Could not create base directory: %s", err)
|
||||
os.Exit(1)
|
||||
|
||||
@@ -5,21 +5,16 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
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()
|
||||
var tftpdir string = path.Join(controller.Paths.Tftpdir, "warewulf")
|
||||
|
||||
err = os.MkdirAll(tftpdir, 0755)
|
||||
err := os.MkdirAll(tftpdir, 0755)
|
||||
if err != nil {
|
||||
wwlog.Error("%s", err)
|
||||
return err
|
||||
@@ -32,7 +27,7 @@ func TFTP() error {
|
||||
continue
|
||||
}
|
||||
copyCheck[f] = true
|
||||
err = util.SafeCopyFile(path.Join(buildconfig.DATADIR(), f), path.Join(tftpdir, f))
|
||||
err = util.SafeCopyFile(path.Join(controller.Paths.Datadir, f), path.Join(tftpdir, f))
|
||||
if err != nil {
|
||||
wwlog.Warn("ipxe binary could not be copied, booting may not work: %s", err)
|
||||
}
|
||||
|
||||
@@ -3,11 +3,12 @@ package container
|
||||
import (
|
||||
"path"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
)
|
||||
|
||||
func SourceParentDir() string {
|
||||
return buildconfig.WWCHROOTDIR()
|
||||
conf := warewulfconf.New()
|
||||
return conf.Paths.WWChrootdir
|
||||
}
|
||||
|
||||
func SourceDir(name string) string {
|
||||
@@ -19,7 +20,8 @@ func RootFsDir(name string) string {
|
||||
}
|
||||
|
||||
func ImageParentDir() string {
|
||||
return path.Join(buildconfig.WWPROVISIONDIR(), "container/")
|
||||
conf := warewulfconf.New()
|
||||
return path.Join(conf.Paths.WWProvisiondir, "container/")
|
||||
}
|
||||
|
||||
func ImageFile(name string) string {
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
@@ -28,7 +28,8 @@ var (
|
||||
)
|
||||
|
||||
func KernelImageTopDir() string {
|
||||
return path.Join(buildconfig.WWPROVISIONDIR(), "kernel")
|
||||
conf := warewulfconf.New()
|
||||
return path.Join(conf.Paths.WWProvisiondir, "kernel")
|
||||
}
|
||||
|
||||
func KernelImage(kernelName string) string {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
@@ -16,6 +16,8 @@ import (
|
||||
var ConfigFile string
|
||||
var DefaultConfig string
|
||||
|
||||
var cachedDB NodeYaml
|
||||
|
||||
// used as fallback if DefaultConfig can't be read
|
||||
var FallBackConf = `---
|
||||
defaultnode:
|
||||
@@ -37,15 +39,25 @@ defaultnode:
|
||||
netmask: 255.255.255.0`
|
||||
|
||||
func init() {
|
||||
conf := warewulfconf.New()
|
||||
if ConfigFile == "" {
|
||||
ConfigFile = path.Join(buildconfig.SYSCONFDIR(), "warewulf/nodes.conf")
|
||||
ConfigFile = path.Join(conf.Paths.Sysconfdir, "warewulf/nodes.conf")
|
||||
}
|
||||
if DefaultConfig == "" {
|
||||
DefaultConfig = path.Join(buildconfig.SYSCONFDIR(), "warewulf/defaults.conf")
|
||||
DefaultConfig = path.Join(conf.Paths.Datadir, "warewulf/defaults.conf")
|
||||
}
|
||||
cachedDB.current = false
|
||||
cachedDB.persist = true
|
||||
}
|
||||
|
||||
/*
|
||||
Creates a new nodeDb object from the actual configuration
|
||||
*/
|
||||
func New() (NodeYaml, error) {
|
||||
if cachedDB.current {
|
||||
wwlog.Debug("Returning cached object")
|
||||
return cachedDB, nil
|
||||
}
|
||||
var ret NodeYaml
|
||||
|
||||
wwlog.Verbose("Opening node configuration file: %s", ConfigFile)
|
||||
@@ -61,10 +73,40 @@ func New() (NodeYaml, error) {
|
||||
}
|
||||
|
||||
wwlog.Debug("Returning node object")
|
||||
|
||||
cachedDB = ret
|
||||
cachedDB.current = true
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Creates a database object from a given buffer, always create
|
||||
a new object, never return the cached one.
|
||||
*/
|
||||
func TestNew(buffer []byte) (db NodeYaml, err error) {
|
||||
db.NodeProfiles = make(map[string]*NodeConf)
|
||||
db.Nodes = make(map[string]*NodeConf)
|
||||
err = yaml.Unmarshal(buffer, &db)
|
||||
db.persist = false
|
||||
cachedDB = db
|
||||
cachedDB.current = true
|
||||
wwlog.Debug("Created cached object")
|
||||
return
|
||||
}
|
||||
|
||||
func (config *NodeYaml) DBDump() (buffer []byte) {
|
||||
for _, n := range config.Nodes {
|
||||
n.Flatten()
|
||||
}
|
||||
for _, p := range config.NodeProfiles {
|
||||
p.Flatten()
|
||||
}
|
||||
buffer, err := yaml.Marshal(config)
|
||||
if err != nil {
|
||||
wwlog.Warn("porblems on dumping nodedb: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Get all the nodes of a configuration. This function also merges
|
||||
the nodes with the given profiles and set the default values
|
||||
@@ -72,12 +114,6 @@ for every node
|
||||
*/
|
||||
func (config *NodeYaml) FindAllNodes() ([]NodeInfo, error) {
|
||||
var ret []NodeInfo
|
||||
/*
|
||||
wwconfig, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
*/
|
||||
var defConf map[string]*NodeConf
|
||||
wwlog.Verbose("Opening defaults from file failed %s\n", DefaultConfig)
|
||||
defData, err := os.ReadFile(DefaultConfig)
|
||||
|
||||
@@ -10,6 +10,8 @@ type NodeYaml struct {
|
||||
WWInternal int `yaml:"WW_INTERNAL"`
|
||||
NodeProfiles map[string]*NodeConf
|
||||
Nodes map[string]*NodeConf
|
||||
current bool
|
||||
persist bool
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -382,3 +382,30 @@ func GetByName(node interface{}, name string) (string, error) {
|
||||
myEntry := entryField.Interface().(Entry)
|
||||
return myEntry.Get(), nil
|
||||
}
|
||||
|
||||
/*
|
||||
Check if the Netdev is empty, so has no values set
|
||||
*/
|
||||
func (dev *NetDevs) Empty() bool {
|
||||
if dev == nil {
|
||||
return true
|
||||
}
|
||||
varType := reflect.TypeOf(*dev)
|
||||
varVal := reflect.ValueOf(*dev)
|
||||
if varVal.IsZero() {
|
||||
return true
|
||||
}
|
||||
for i := 0; i < varType.NumField(); i++ {
|
||||
if varType.Field(i).Type.Kind() == reflect.String && !varVal.Field(i).IsZero() {
|
||||
val := varVal.Field(i).Interface().(string)
|
||||
if val != "" {
|
||||
return false
|
||||
}
|
||||
} else if varType.Field(i).Type == reflect.TypeOf(map[string]string{}) {
|
||||
if len(varVal.Field(i).Interface().(map[string]string)) != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
32
internal/pkg/node/methods_test.go
Normal file
32
internal/pkg/node/methods_test.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package node
|
||||
|
||||
import "testing"
|
||||
|
||||
func Test_Empty(t *testing.T) {
|
||||
var netdev NetDevs
|
||||
var netdevPtr *NetDevs
|
||||
|
||||
t.Run("test for empty", func(t *testing.T) {
|
||||
if netdev.Empty() != true {
|
||||
t.Errorf("netdev must be empty")
|
||||
}
|
||||
})
|
||||
t.Run("test for non empty", func(t *testing.T) {
|
||||
netdev.Device = "foo"
|
||||
if netdev.Empty() == true {
|
||||
t.Errorf("netdev must be non empty")
|
||||
}
|
||||
})
|
||||
t.Run("test for nil pointer", func(t *testing.T) {
|
||||
if netdevPtr.Empty() != true {
|
||||
t.Errorf("netdev must be empty")
|
||||
}
|
||||
})
|
||||
t.Run("test for pointer assigned", func(t *testing.T) {
|
||||
netdev.Ipaddr = "10.10.10.1"
|
||||
netdevPtr = &netdev
|
||||
if netdevPtr.Empty() == true {
|
||||
t.Errorf("netdev must be empty")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -127,7 +127,10 @@ func (config *NodeYaml) Persist() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Can't persist for unit tests
|
||||
if !config.persist {
|
||||
return err
|
||||
}
|
||||
file, err := os.OpenFile(ConfigFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
wwlog.Error("%s", err)
|
||||
|
||||
@@ -5,11 +5,12 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
)
|
||||
|
||||
func OverlaySourceTopDir() string {
|
||||
return buildconfig.WWOVERLAYDIR()
|
||||
conf := warewulfconf.New()
|
||||
return conf.Paths.WWOverlaydir
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -30,5 +31,6 @@ func OverlaySourceDir(overlayName string) string {
|
||||
Returns the overlay name of the image for a given node
|
||||
*/
|
||||
func OverlayImage(nodeName string, overlayName []string) string {
|
||||
return path.Join(buildconfig.WWPROVISIONDIR(), "overlays/", nodeName, strings.Join(overlayName, "-")+".img")
|
||||
conf := warewulfconf.New()
|
||||
return path.Join(conf.Paths.WWProvisiondir, "overlays/", nodeName, strings.Join(overlayName, "-")+".img")
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ type TemplateStruct struct {
|
||||
Nfs warewulfconf.NfsConf
|
||||
Warewulf warewulfconf.WarewulfConf
|
||||
Tftp warewulfconf.TftpConf
|
||||
Paths warewulfconf.BuildConfig
|
||||
AllNodes []node.NodeInfo
|
||||
node.NodeConf
|
||||
// backward compatiblity
|
||||
@@ -43,11 +44,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)
|
||||
|
||||
@@ -6,20 +6,20 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/container"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
/*
|
||||
Reads a file file from the host fs. If the file has nor '/' prefix
|
||||
the path is relative to SYSCONFDIR.
|
||||
Templates in the file are no evaluated.
|
||||
the path is relative to Paths.SysconfdirTemplates in the file are no evaluated.
|
||||
*/
|
||||
func templateFileInclude(inc string) string {
|
||||
conf := warewulfconf.New()
|
||||
if !strings.HasPrefix(inc, "/") {
|
||||
inc = path.Join(buildconfig.SYSCONFDIR(), "warewulf", inc)
|
||||
inc = path.Join(conf.Paths.Sysconfdir, "warewulf", inc)
|
||||
}
|
||||
wwlog.Debug("Including file into template: %s", inc)
|
||||
content, err := os.ReadFile(inc)
|
||||
@@ -35,8 +35,9 @@ is the file to read, the second the abort string
|
||||
Templates in the file are no evaluated.
|
||||
*/
|
||||
func templateFileBlock(inc string, abortStr string) (string, error) {
|
||||
conf := warewulfconf.New()
|
||||
if !strings.HasPrefix(inc, "/") {
|
||||
inc = path.Join(buildconfig.SYSCONFDIR(), "warewulf", inc)
|
||||
inc = path.Join(conf.Paths.Sysconfdir, "warewulf", inc)
|
||||
}
|
||||
wwlog.Debug("Including file block into template: %s", inc)
|
||||
readFile, err := os.Open(inc)
|
||||
|
||||
@@ -4,14 +4,15 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
)
|
||||
|
||||
/*
|
||||
Return the version of wwctl
|
||||
*/
|
||||
func GetVersion() string {
|
||||
return fmt.Sprintf("%s-%s", buildconfig.VERSION(), buildconfig.RELEASE())
|
||||
conf := warewulfconf.New()
|
||||
return fmt.Sprintf("%s-%s", conf.Paths.Version, conf.Paths.Release)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
18
internal/pkg/warewulfconf/buildconfig.go.in
Normal file
18
internal/pkg/warewulfconf/buildconfig.go.in
Normal file
@@ -0,0 +1,18 @@
|
||||
package warewulfconf
|
||||
|
||||
type BuildConfig struct {
|
||||
Bindir string `default:"@BINDIR@"`
|
||||
Sysconfdir string `default:"@SYSCONFDIR@"`
|
||||
Datadir string `default:"@DATADIR@"`
|
||||
Localstatedir string `default:"@LOCALSTATEDIR@"`
|
||||
Srvdir string `default:"@SRVDIR@"`
|
||||
Tftpdir string `default:"@TFTPDIR@"`
|
||||
Firewallddir string `default:"@FIREWALLDDIR@"`
|
||||
Systemddir string `default:"@SYSTEMDDIR@"`
|
||||
WWOverlaydir string `default:"@WWOVERLAYDIR@"`
|
||||
WWChrootdir string `default:"@WWCHROOTDIR@"`
|
||||
WWProvisiondir string `default:"@WWPROVISIONDIR@"`
|
||||
Version string `default:"@VERSION@"`
|
||||
Release string `default:"@RELEASE@"`
|
||||
WWClientdir string `default:"@WWCLIENTDIR@"`
|
||||
}
|
||||
@@ -1,17 +1,14 @@
|
||||
package warewulfconf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/brotherpowers/ipsubnet"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/creasty/defaults"
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
@@ -19,97 +16,141 @@ var cachedConf ControllerConf
|
||||
|
||||
var ConfigFile string
|
||||
|
||||
func init() {
|
||||
if ConfigFile == "" {
|
||||
ConfigFile = path.Join(buildconfig.SYSCONFDIR(), "warewulf/warewulf.conf")
|
||||
/*
|
||||
Creates a new empty ControllerConf object, returns a cached
|
||||
one if called in a nother context.
|
||||
*/
|
||||
func New() (conf 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 {
|
||||
conf.Warewulf = new(WarewulfConf)
|
||||
conf.Dhcp = new(DhcpConf)
|
||||
conf.Tftp = new(TftpConf)
|
||||
conf.Nfs = new(NfsConf)
|
||||
conf.Paths = new(BuildConfig)
|
||||
_ = defaults.Set(&conf)
|
||||
cachedConf = conf
|
||||
cachedConf.readConf = false
|
||||
cachedConf.current = true
|
||||
} else {
|
||||
// If cached struct isn't empty, use it as the return value
|
||||
conf = cachedConf
|
||||
}
|
||||
return conf
|
||||
}
|
||||
|
||||
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)
|
||||
/*
|
||||
Populate the configuration with the values from the configuration file.
|
||||
*/
|
||||
func (conf *ControllerConf) ReadConf(confFileName string) (err error) {
|
||||
wwlog.Debug("Reading warewulf.conf from: %s", confFileName)
|
||||
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 ret.Tftp.IpxeBinaries {
|
||||
for k, v := range conf.Tftp.IpxeBinaries {
|
||||
defIpxe[k] = v
|
||||
delete(ret.Tftp.IpxeBinaries, k)
|
||||
delete(conf.Tftp.IpxeBinaries, k)
|
||||
}
|
||||
err = yaml.Unmarshal(data, &conf)
|
||||
if err != nil {
|
||||
wwlog.Error("Could initialize default variables")
|
||||
return ret, err
|
||||
return
|
||||
}
|
||||
// Check if cached config is old before re-reading config file
|
||||
if !cachedConf.current {
|
||||
wwlog.Debug("Opening Warewulf configuration file: %s", ConfigFile)
|
||||
data, err := os.ReadFile(ConfigFile)
|
||||
if err != nil {
|
||||
wwlog.Warn("Error reading Warewulf configuration file")
|
||||
}
|
||||
|
||||
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.Warn("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.Warn("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
|
||||
err = conf.SetDynamicDefaults()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
if len(conf.Tftp.IpxeBinaries) == 0 {
|
||||
conf.Tftp.IpxeBinaries = defIpxe
|
||||
}
|
||||
cachedConf = *conf
|
||||
cachedConf.current = true
|
||||
cachedConf.readConf = true
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Set the runtime defaults like IP address of running system to the config
|
||||
*/
|
||||
func (conf *ControllerConf) SetDynamicDefaults() (err error) {
|
||||
if conf.Ipaddr == "" || conf.Netmask == "" || conf.Network == "" {
|
||||
var mask net.IPMask
|
||||
var network *net.IPNet
|
||||
var ipaddr net.IP
|
||||
|
||||
if conf.Ipaddr == "" {
|
||||
wwlog.Verbose("Configuration has no valid network, going to dynamic values")
|
||||
conn, _ := net.Dial("udp", "8.8.8.8:80")
|
||||
defer conn.Close()
|
||||
ipaddr = conn.LocalAddr().(*net.UDPAddr).IP
|
||||
mask = ipaddr.DefaultMask()
|
||||
sz, _ := mask.Size()
|
||||
conf.Ipaddr = ipaddr.String() + fmt.Sprintf("/%d", sz)
|
||||
}
|
||||
_, network, err = net.ParseCIDR(conf.Ipaddr)
|
||||
if err == nil {
|
||||
mask = network.Mask
|
||||
} else {
|
||||
return errors.Wrap(err, "Couldn't parse IP address")
|
||||
}
|
||||
if conf.Netmask == "" {
|
||||
conf.Netmask = fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3])
|
||||
wwlog.Verbose("Netmask address is not configured in warewulf.conf, using %s", conf.Netmask)
|
||||
}
|
||||
if conf.Network == "" {
|
||||
conf.Network = network.IP.String()
|
||||
wwlog.Verbose("Network is not configured in warewulf.conf, using %s", conf.Network)
|
||||
}
|
||||
}
|
||||
if conf.Dhcp.RangeStart == "" && conf.Dhcp.RangeEnd == "" {
|
||||
start := net.ParseIP(conf.Network).To4()
|
||||
start[3] += 1
|
||||
if start.Equal(net.ParseIP(conf.Ipaddr)) {
|
||||
start[3] += 1
|
||||
}
|
||||
conf.Dhcp.RangeStart = start.String()
|
||||
wwlog.Verbose("dhpd start is not configured in warewulf.conf, using %s", conf.Dhcp.RangeStart)
|
||||
sz, _ := net.IPMask(net.ParseIP(conf.Netmask).To4()).Size()
|
||||
range_end := (1 << (32 - sz)) / 8
|
||||
if range_end > 127 {
|
||||
range_end = 127
|
||||
}
|
||||
end := net.ParseIP(conf.Network).To4()
|
||||
end[3] += byte(range_end)
|
||||
conf.Dhcp.RangeEnd = end.String()
|
||||
wwlog.Verbose("dhpd end is not configured in warewulf.conf, using %s", conf.Dhcp.RangeEnd)
|
||||
|
||||
}
|
||||
// check validity of ipv6 net
|
||||
if conf.Ipaddr6 != "" {
|
||||
_, ipv6net, err := net.ParseCIDR(conf.Ipaddr6)
|
||||
if err != nil {
|
||||
wwlog.Error("Invalid ipv6 address specified, mut be CIDR notation: %s", conf.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")
|
||||
}
|
||||
}
|
||||
cachedConf = *conf
|
||||
cachedConf.current = true
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Return if configuration was read from disk
|
||||
*/
|
||||
func (conf *ControllerConf) Initialized() bool {
|
||||
return conf.readConf
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ package warewulfconf
|
||||
|
||||
import (
|
||||
"github.com/creasty/defaults"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
type ControllerConf struct {
|
||||
@@ -19,8 +17,10 @@ type ControllerConf struct {
|
||||
Dhcp *DhcpConf `yaml:"dhcp"`
|
||||
Tftp *TftpConf `yaml:"tftp"`
|
||||
Nfs *NfsConf `yaml:"nfs"`
|
||||
MountsContainer []*MountEntry `yaml:"container mounts"`
|
||||
MountsContainer []*MountEntry `yaml:"container mounts" default:"[{\"source\": \"/etc/resolv.conf\", \"dest\": \"/etc/resolv.conf\"}]"`
|
||||
Paths *BuildConfig `yaml:"paths"`
|
||||
current bool
|
||||
readConf bool
|
||||
}
|
||||
|
||||
type WarewulfConf struct {
|
||||
@@ -79,19 +79,9 @@ func (s *NfsConf) Unmarshal(unmarshal func(interface{}) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
if !util.IsFile(ConfigFile) {
|
||||
wwlog.Error("Configuration file not found: %s", ConfigFile)
|
||||
// fail silently as this also called by bash_completion
|
||||
}
|
||||
_, err := New()
|
||||
if err != nil {
|
||||
wwlog.Error("Could not read Warewulf configuration file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Waste processor cycles to make code more readable
|
||||
|
||||
func DataStore() string {
|
||||
_ = New()
|
||||
return cachedConf.Warewulf.DataStore
|
||||
}
|
||||
|
||||
@@ -23,6 +23,23 @@ const (
|
||||
|
||||
var loginit bool
|
||||
|
||||
// allow to run without daemon for tests
|
||||
var nodaemon bool
|
||||
|
||||
func init() {
|
||||
nodaemon = false
|
||||
}
|
||||
|
||||
// run without daemon
|
||||
func SetNoDaemon() {
|
||||
nodaemon = true
|
||||
}
|
||||
|
||||
// run with daemon
|
||||
func SetDaemon() {
|
||||
nodaemon = false
|
||||
}
|
||||
|
||||
func DaemonFormatter(logLevel int, rec *wwlog.LogRecord) string {
|
||||
return "[" + rec.Time.Format(time.UnixDate) + "] " + wwlog.DefaultFormatter(logLevel, rec)
|
||||
}
|
||||
@@ -44,10 +61,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 {
|
||||
|
||||
@@ -69,6 +83,10 @@ func DaemonInitLogging() error {
|
||||
}
|
||||
|
||||
func DaemonStart() error {
|
||||
if nodaemon {
|
||||
return nil
|
||||
}
|
||||
|
||||
if os.Getenv("WAREWULFD_BACKGROUND") == "1" {
|
||||
err := RunServer()
|
||||
if err != nil {
|
||||
@@ -119,6 +137,10 @@ func DaemonStart() error {
|
||||
}
|
||||
|
||||
func DaemonStatus() error {
|
||||
if nodaemon {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !util.IsFile(WAREWULFD_PIDFILE) {
|
||||
return errors.New("Warewulf server is not running")
|
||||
}
|
||||
@@ -145,6 +167,9 @@ func DaemonStatus() error {
|
||||
}
|
||||
|
||||
func DaemonReload() error {
|
||||
if nodaemon {
|
||||
return nil
|
||||
}
|
||||
if !util.IsFile(WAREWULFD_PIDFILE) {
|
||||
return errors.New("Warewulf server is not running")
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"strconv"
|
||||
"text/template"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/container"
|
||||
"github.com/hpcng/warewulf/internal/pkg/kernel"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
@@ -31,12 +30,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 +39,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 +50,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
|
||||
@@ -85,26 +79,26 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
if !node.Id.Defined() {
|
||||
wwlog.Error("%s (unknown/unconfigured node)", rinfo.hwaddr)
|
||||
if rinfo.stage == "ipxe" {
|
||||
stage_file = path.Join(buildconfig.SYSCONFDIR(), "/warewulf/ipxe/unconfigured.ipxe")
|
||||
stage_file = path.Join(conf.Paths.Sysconfdir, "/warewulf/ipxe/unconfigured.ipxe")
|
||||
tmpl_data = iPxeTemplate{
|
||||
Hwaddr : rinfo.hwaddr }
|
||||
Hwaddr: rinfo.hwaddr}
|
||||
}
|
||||
|
||||
}else if rinfo.stage == "ipxe" {
|
||||
stage_file = path.Join(buildconfig.SYSCONFDIR(), "warewulf/ipxe/"+node.Ipxe.Get()+".ipxe")
|
||||
} else if rinfo.stage == "ipxe" {
|
||||
stage_file = path.Join(conf.Paths.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 +111,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 +147,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 +156,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 +194,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 +204,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 +219,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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user