diff --git a/etc/nodes.conf b/etc/nodes.conf index a692cbb1..40cf1e3c 100644 --- a/etc/nodes.conf +++ b/etc/nodes.conf @@ -1,34 +1,15 @@ nodegroups: - group_1: - comment: This is the group 1 - vnfs: /var/chroots/centos-7 - system overlay: default + default: + comment: This is the default group + vnfs: docker://warewulf/centos-8 runtime overlay: default - domain suffix: group1 - nodes: - n0000: - hostname: localtest - kernel version: 3.10.0-1127.el7.x86_64 - kernel args: crashkernel=no quiet - system overlay: test - netdevs: - eth0: - hwaddr: xx:xx:xx:xx:aa - ipaddr: 192.168.1.1 - netmask: 255.255.255.0 - gateway: 192.168.1.1 - group_2: - comment: This is the group 2 - vnfs: docker://warewulf/centos-7 - system overlay: default - runtime overlay: default - domain suffix: group2 - kernel version: 3.10.0-1127.el7.x86_64 + domain suffix: default + kernel version: "" kernel args: crashkernel=no quiet nodes: n0000: hostname: n0000 - ipmi ipaddr: x.x.x.x + kernel args: crashkernel=no netdevs: eth0: hwaddr: 00:0c:29:23:8b:48 @@ -37,21 +18,36 @@ nodegroups: gateway: 192.168.1.1 type: ethernet ib0: - hwaddr: xx:xx:xx:xx:xx - ipaddr: x.x.x.x - netmask: x.x.x.x - gateway: x.x.x.x + hwaddr: aa:bb:cc:dd:ee:a0 + ipaddr: 192.168.10.100 + netmask: 255.255.255.0 type: infiniband n0001: hostname: n0001 ipmi ipaddr: x.x.x.x netdevs: eth0: - hwaddr: xx:xx:xx:xx:xx + hwaddr: aa:bb:cc:dd:ee:b0 ipaddr: 192.168.1.101 netmask: 255.255.255.0 gateway: 192.168.1.1 ib0: - hwaddr: xx:xx:xx:xx:xx - ipaddr: x.x.x.x - netmask: x.x.x.x + hwaddr: aa:bb:cc:dd:ee:b1 + ipaddr: 192.168.10.100 + netmask: 255.255.255.0 + group_1: + comment: This is the group 1 + vnfs: /var/chroots/centos-7 + runtime overlay: default + domain suffix: group1 + nodes: + n0000: + hostname: localtest + kernel version: 3.10.0-1127.el7.x86_64 + system overlay: test + netdevs: + eth0: + hwaddr: aa:bb:cc:dd:ee:c0 + ipaddr: 192.168.2.100 + netmask: 255.255.255.0 + gateway: 192.168.2.1 diff --git a/go.mod b/go.mod index f2c34b44..a9c1f20b 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.15 require ( github.com/containers/image/v5 v5.7.0 github.com/kelseyhightower/envconfig v1.4.0 + github.com/manifoldco/promptui v0.8.0 github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 github.com/opencontainers/umoci v0.4.6 github.com/spf13/cobra v1.1.1 diff --git a/go.sum b/go.sum index 044bc343..17ed50fd 100644 --- a/go.sum +++ b/go.sum @@ -46,6 +46,10 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/checkpoint-restore/go-criu/v4 v4.0.2/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3/go.mod h1:XT+cAw5wfvsodedcijoh1l9cf7v1x9FlFB/3VmF/O8s= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= @@ -191,6 +195,8 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= +github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= @@ -214,13 +220,19 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw= +github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/manifoldco/promptui v0.8.0 h1:R95mMF+McvXZQ7j1g8ucVZE1gLP3Sv6j9vlF9kyRqQo= +github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= @@ -468,6 +480,7 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/internal/app/warewulfd/response/ipxe.go b/internal/app/warewulfd/response/ipxe.go index 76336e6b..6a9e2d3b 100644 --- a/internal/app/warewulfd/response/ipxe.go +++ b/internal/app/warewulfd/response/ipxe.go @@ -2,8 +2,8 @@ package response import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/assets" "github.com/hpcng/warewulf/internal/pkg/config" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/wwlog" "log" "net/http" @@ -26,13 +26,20 @@ type iPxeTemplate struct { func IpxeSend(w http.ResponseWriter, req *http.Request) { url := strings.Split(req.URL.Path, "/") + nodes, 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) return } hwaddr := strings.ReplaceAll(url[2], "-", ":") - node, err := assets.FindByHwaddr(hwaddr) + node, err := nodes.FindByHwaddr(hwaddr) if err != nil { log.Printf("Could not find HW Addr: %s: %s\n", hwaddr, err) w.WriteHeader(404) diff --git a/internal/app/warewulfd/response/runtime.go b/internal/app/warewulfd/response/runtime.go index 0b0a4ea7..06b30309 100644 --- a/internal/app/warewulfd/response/runtime.go +++ b/internal/app/warewulfd/response/runtime.go @@ -2,8 +2,8 @@ package response import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/assets" "github.com/hpcng/warewulf/internal/pkg/config" + "github.com/hpcng/warewulf/internal/pkg/node" "log" "net/http" "strconv" @@ -12,6 +12,12 @@ import ( func RuntimeOverlaySend(w http.ResponseWriter, req *http.Request) { config := config.New() + nodes, err := node.New() + if err != nil { + log.Printf("Could not read node configuration file: %s\n", err) + w.WriteHeader(503) + return + } remote := strings.Split(req.RemoteAddr, ":") port, err := strconv.Atoi(remote[1]) @@ -34,7 +40,7 @@ func RuntimeOverlaySend(w http.ResponseWriter, req *http.Request) { } } - node, err := assets.FindByIpaddr(remote[0]) + node, err := nodes.FindByIpaddr(remote[0]) if err != nil { fmt.Printf("Could not find node by IP address: %s\n", remote[0]) w.WriteHeader(404) diff --git a/internal/app/warewulfd/response/util.go b/internal/app/warewulfd/response/util.go index 2eaad20a..793ef1fb 100644 --- a/internal/app/warewulfd/response/util.go +++ b/internal/app/warewulfd/response/util.go @@ -1,7 +1,8 @@ package response import ( - "github.com/hpcng/warewulf/internal/pkg/assets" + "fmt" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/errors" "io" "log" @@ -11,23 +12,29 @@ import ( "strings" ) -func getSanity(req *http.Request) (assets.NodeInfo, error) { +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], "-", ":") - node, err := assets.FindByHwaddr(hwaddr) + ret, err = nodes.FindByHwaddr(hwaddr) if err != nil { - return node, errors.New("Could not find node by HW address") + return ret, errors.New("Could not find node by HW address") } - if node.Fqdn == "" { + if ret.Fqdn == "" { log.Printf("UNKNOWN: %15s: %s\n", hwaddr, req.URL.Path) - return node, errors.New("Unknown node HW address: " + hwaddr) + return ret, errors.New("Unknown node HW address: " + hwaddr) } else { - log.Printf("REQ: %15s: %s\n", node.Fqdn, req.URL.Path) + log.Printf("REQ: %15s: %s\n", ret.Fqdn, req.URL.Path) } - return node, nil + return ret, nil } func sendFile(w http.ResponseWriter, filename string, sendto string) error { diff --git a/internal/app/wwctl/build/build.go b/internal/app/wwctl/build/build.go deleted file mode 100644 index 323c6095..00000000 --- a/internal/app/wwctl/build/build.go +++ /dev/null @@ -1,79 +0,0 @@ -package build - -import ( - "github.com/hpcng/warewulf/internal/app/wwctl/build/kernel" - runtime_overlay "github.com/hpcng/warewulf/internal/app/wwctl/build/runtime-overlay" - system_overlay "github.com/hpcng/warewulf/internal/app/wwctl/build/system-overlay" - "github.com/hpcng/warewulf/internal/app/wwctl/build/vnfs" - "github.com/hpcng/warewulf/internal/pkg/assets" - "github.com/hpcng/warewulf/internal/pkg/wwlog" - "github.com/spf13/cobra" - "os" -) - - -func CobraRunE(cmd *cobra.Command, args []string) error { - var nodeList []assets.NodeInfo - - if buildAll == true { - wwlog.Printf(wwlog.VERBOSE, "Building all components\n") - buildVnfs = true - buildKernel = true - buildSystemOverlay = true; - buildRuntimeOverlay = true; - } - - if len(args) >= 1 { - nodeList, _ = assets.SearchByName(args[0]) - } else { - nodeList, _ = assets.FindAllNodes() - } - - if len(nodeList) == 0 { - wwlog.Printf(wwlog.ERROR, "No nodes found matching: '%s'\n", args[0]) - os.Exit(255) - } else { - wwlog.Printf(wwlog.VERBOSE, "Found matching nodes for build: %d\n", len(nodeList)) - } - - if buildVnfs == true { -// wwlog.Printf(wwlog.INFO, "===============================================================================\n") - - err := vnfs.Build(nodeList, buildForce) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(255) - } - } - - if buildKernel == true { -// wwlog.Printf(wwlog.INFO, "===============================================================================\n") - - err := kernel.Build(nodeList, buildForce) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(255) - } - } - - if buildSystemOverlay == true { -// wwlog.Printf(wwlog.INFO, "===============================================================================\n") - err := system_overlay.Build(nodeList, buildForce) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(255) - } - } - - if buildRuntimeOverlay == true { -// wwlog.Printf(wwlog.INFO, "===============================================================================\n") - err := runtime_overlay.Build(nodeList, buildForce) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(255) - } - } - - - return nil -} \ No newline at end of file diff --git a/internal/app/wwctl/build/kernel/kernel.go b/internal/app/wwctl/build/kernel/kernel.go deleted file mode 100644 index 08f3d850..00000000 --- a/internal/app/wwctl/build/kernel/kernel.go +++ /dev/null @@ -1,73 +0,0 @@ -package kernel - -import ( - "fmt" - "github.com/hpcng/warewulf/internal/pkg/assets" - "github.com/hpcng/warewulf/internal/pkg/config" - "github.com/hpcng/warewulf/internal/pkg/util" - "github.com/hpcng/warewulf/internal/pkg/wwlog" - "os" - "os/exec" - "path" -) - -func Build(nodeList []assets.NodeInfo, force bool) error { - config := config.New() - set := make(map[string]int) - - wwlog.Printf(wwlog.INFO, "Importing Kernels:\n") - wwlog.SetIndent(4) - - for _, node := range nodeList { - if node.KernelVersion != "" { - set[node.KernelVersion] ++ - wwlog.Printf(wwlog.DEBUG, "Node '%s' has KernelVersion '%s'\n", node.Fqdn, node.KernelVersion) - } - } - - for kernelVersion := range set { - kernelImage := "/boot/vmlinuz-"+kernelVersion - kernelDrivers := "/lib/modules/"+kernelVersion - kernelDestination := config.KernelImage(kernelVersion) - driversDestination := config.KmodsImage(kernelVersion) - - // Create the destination paths just in case it doesn't exist - os.MkdirAll(path.Dir(kernelDestination), 0755) - os.MkdirAll(path.Dir(driversDestination), 0755) - - - if _, err := os.Stat(kernelImage); err == nil { - if util.PathIsNewer(kernelImage, kernelDestination) && force == false { - wwlog.Printf(wwlog.INFO, "%-35s: Skipping, kernel is current\n", "vmlinuz-"+kernelVersion) - - } else { - err := util.CopyFile(kernelImage, kernelDestination) - if err != nil { - wwlog.Printf(wwlog.ERROR, "Failed copying kernel image: %s\n", err) - continue - } - wwlog.Printf(wwlog.INFO, "%-35s: Done\n", "vmlinuz-"+kernelVersion) - - } - } - - if _, err := os.Stat(kernelDrivers); err == nil { - if util.PathIsNewer(kernelDrivers, driversDestination) && force == false { - wwlog.Printf(wwlog.INFO, "%-35s: Skipping, drivers are current\n", "kmods-"+kernelVersion+".img") - - } else { - cmd := fmt.Sprintf("cd /; find .%s | cpio --quiet -o -H newc -F \"%s\"", kernelDrivers, driversDestination) - err := exec.Command("/bin/sh", "-c", cmd).Run() - if err != nil { - wwlog.Printf(wwlog.ERROR, "Could not generate kernel driver overlay: %s\n", err) - continue - } - wwlog.Printf(wwlog.INFO, "%-35s: Done\n", "kmods-"+kernelVersion+".img") - } - } - } - - wwlog.SetIndent(0) - - return nil -} \ No newline at end of file diff --git a/internal/app/wwctl/build/main.go b/internal/app/wwctl/build/main.go new file mode 100644 index 00000000..0a2f5edc --- /dev/null +++ b/internal/app/wwctl/build/main.go @@ -0,0 +1,90 @@ +package build + +import ( + "github.com/hpcng/warewulf/internal/pkg/kernel" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/overlay" + "github.com/hpcng/warewulf/internal/pkg/vnfs" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" + "os" +) + + +func CobraRunE(cmd *cobra.Command, args []string) error { + var nodes []node.NodeInfo + showHelp := true + + n, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + if len(args) > 0 { + var err error + nodes, err = n.SearchByName(args[0]) + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not find nodes for search term: %s\n", args[0]) + os.Exit(1) + } + + } else { + var err error + nodes, err = n.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not get list of nodes: %s\n", err) + os.Exit(1) + } + + } + + if buildVnfs == true || buildAll == true { + set := make(map[string]int) + showHelp = false + + wwlog.Printf(wwlog.INFO, "Building VNFS images...\n") + + for _, node := range nodes { + set[node.Vnfs] ++ + } + for e := range set { + vnfs.Build(e, buildForce) + } + } + + if buildKernel == true || buildAll == true { + set := make(map[string]int) + showHelp = false + + wwlog.Printf(wwlog.INFO, "Building Kernel images...\n") + + for _, node := range nodes { + set[node.KernelVersion] ++ + } + for e := range set { + kernel.Build(e) + } + } + + if buildSystemOverlay == true || buildAll == true { + wwlog.Printf(wwlog.INFO, "Building System Overlays...\n") + showHelp = false + + overlay.SystemBuild(nodes, buildForce) + } + + if buildRuntimeOverlay == true || buildAll == true { + wwlog.Printf(wwlog.INFO, "Building Runtime Overlays...n") + showHelp = false + + overlay.RuntimeBuild(nodes, buildForce) + } + + if showHelp == true { + cmd.Usage() + os.Exit(1) + } + + return nil +} diff --git a/internal/app/wwctl/build/root.go b/internal/app/wwctl/build/root.go index 494aef6d..32329651 100644 --- a/internal/app/wwctl/build/root.go +++ b/internal/app/wwctl/build/root.go @@ -13,6 +13,7 @@ var ( "that seems to be needed.", RunE: CobraRunE, } + buildVnfs bool buildKernel bool buildRuntimeOverlay bool diff --git a/internal/app/wwctl/build/runtime-overlay/runtime-overlay.go b/internal/app/wwctl/build/runtime-overlay/runtime-overlay.go deleted file mode 100644 index b1168aa1..00000000 --- a/internal/app/wwctl/build/runtime-overlay/runtime-overlay.go +++ /dev/null @@ -1,144 +0,0 @@ -package runtime_overlay - -import ( - "fmt" - "github.com/hpcng/warewulf/internal/pkg/assets" - "github.com/hpcng/warewulf/internal/pkg/config" - "github.com/hpcng/warewulf/internal/pkg/util" - "github.com/hpcng/warewulf/internal/pkg/wwlog" - "io/ioutil" - "os" - "os/exec" - "path" - "path/filepath" - "regexp" - "strings" - "text/template" -) - -func fileInclude(path string) string { - wwlog.Printf(wwlog.DEBUG, "Including file into template: %s\n", path) - content, err := ioutil.ReadFile(path) - if err != nil { - wwlog.Printf(wwlog.ERROR, "Template include: %s\n", err) - } - return strings.TrimSuffix(string(content), "\n") -} - -func Build(nodeList []assets.NodeInfo, force bool) error { - wwlog.Printf(wwlog.INFO, "Building Runtime Overlays:\n") - config := config.New() - - wwlog.SetIndent(4) - - for _, node := range nodeList { - if node.RuntimeOverlay != "" { - OverlayDir := config.RuntimeOverlaySource(node.RuntimeOverlay) - OverlayFile := config.RuntimeOverlayImage(node.Fqdn) - - wwlog.Printf(wwlog.VERBOSE, "Building Runtime Overlay for: %s\n", node.Fqdn) - - tmpDir, err := ioutil.TempDir(os.TempDir(), ".wwctl-runtime-overlay-") - if err != nil { - return err - } - - if _, err := os.Stat(OverlayDir); err != nil { - return err - } - - err = os.MkdirAll(path.Dir(OverlayFile), 0755) - if err != nil { - return err - } - - if force == false { - wwlog.Printf(wwlog.DEBUG, "Checking if overlay is required\n") - } - if util.PathIsNewer(OverlayDir, OverlayFile) { - if force == false { - wwlog.Printf(wwlog.INFO, "%-35s: Skipping, overlay is current\n", node.Fqdn) - continue - } - } - - wwlog.Printf(wwlog.DEBUG, "Changing directory to OverlayDir: %s\n", OverlayDir) - err = os.Chdir(OverlayDir) - if err != nil { - wwlog.Printf(wwlog.ERROR, "Could not chdir() to OverlayDir: %s\n", OverlayDir) - continue - } - - wwlog.Printf(wwlog.DEBUG, "Walking the file system: %s\n", OverlayDir) - err = filepath.Walk(".", func(location string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - if info.IsDir() { - wwlog.Printf(wwlog.DEBUG, "Found directory: %s\n", location) - - err := os.MkdirAll(path.Join(tmpDir, location), info.Mode()) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - return err - } - - } else if filepath.Ext(location) == ".ww" { - wwlog.Printf(wwlog.DEBUG, "Found template file: %s\n", location) - - destFile := strings.TrimSuffix(location, ".ww") - - tmpl, err := template.New(path.Base(location)).Funcs(template.FuncMap{"Include": fileInclude}).ParseGlob(path.Join(OverlayDir, destFile + ".ww*")) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - return err - } - - w, err := os.OpenFile(path.Join(tmpDir, destFile), os.O_RDWR|os.O_CREATE, info.Mode()) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - return err - } - defer w.Close() - - err = tmpl.Execute(w, node) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - return err - } - - } else if b, _ := regexp.MatchString(`\.ww[a-zA-Z0-9\-\._]*$`, location); b == true { - wwlog.Printf(wwlog.DEBUG, "Ignoring WW template file: %s\n", location) - } else { - wwlog.Printf(wwlog.DEBUG, "Found file: %s\n", location) - - err := util.CopyFile(path.Join(OverlayDir, location), path.Join(tmpDir, location)) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - return err - } - - } - - return nil - }) - wwlog.Printf(wwlog.VERBOSE, "Finished generating overlay directory for: %s\n", node.Fqdn) - - cmd := fmt.Sprintf("cd \"%s\"; find . | cpio --quiet -o -H newc -F \"%s\"", tmpDir, OverlayFile) - wwlog.Printf(wwlog.DEBUG, "RUNNING: %s\n", cmd) - err = exec.Command("/bin/sh", "-c", cmd).Run() - if err != nil { - wwlog.Printf(wwlog.ERROR, "Could not generate runtime image overlay: %s\n", err) - continue - } - wwlog.Printf(wwlog.INFO, "%-35s: Done\n", node.Fqdn) - - wwlog.Printf(wwlog.DEBUG, "Removing temporary directory: %s\n", tmpDir) - os.RemoveAll(tmpDir) - } - } - - wwlog.SetIndent(0) - return nil -} diff --git a/internal/app/wwctl/build/system-overlay/system-overlay.go b/internal/app/wwctl/build/system-overlay/system-overlay.go deleted file mode 100644 index 2e1dee02..00000000 --- a/internal/app/wwctl/build/system-overlay/system-overlay.go +++ /dev/null @@ -1,144 +0,0 @@ -package system_overlay - -import ( - "fmt" - "github.com/hpcng/warewulf/internal/pkg/assets" - "github.com/hpcng/warewulf/internal/pkg/config" - "github.com/hpcng/warewulf/internal/pkg/util" - "github.com/hpcng/warewulf/internal/pkg/wwlog" - "io/ioutil" - "os" - "os/exec" - "path" - "path/filepath" - "regexp" - "strings" - "text/template" -) - -func fileInclude(path string) string { - wwlog.Printf(wwlog.DEBUG, "Including file into template: %s\n", path) - content, err := ioutil.ReadFile(path) - if err != nil { - wwlog.Printf(wwlog.ERROR, "Template include: %s\n", err) - } - return strings.TrimSuffix(string(content), "\n") -} - -func Build(nodeList []assets.NodeInfo, force bool) error { - wwlog.Printf(wwlog.INFO, "Building System Overlays:\n") - config := config.New() - - wwlog.SetIndent(4) - - for _, node := range nodeList { - if node.SystemOverlay != "" { - OverlayDir := config.SystemOverlaySource(node.SystemOverlay) - OverlayFile := config.SystemOverlayImage(node.Fqdn) - - wwlog.Printf(wwlog.VERBOSE, "Building System Overlay for: %s\n", node.Fqdn) - - tmpDir, err := ioutil.TempDir(os.TempDir(), ".wwctl-system-overlay-") - if err != nil { - return err - } - - if _, err := os.Stat(OverlayDir); err != nil { - return err - } - - err = os.MkdirAll(path.Dir(OverlayFile), 0755) - if err != nil { - return err - } - - if force == false { - wwlog.Printf(wwlog.DEBUG, "Checking if overlay is required\n") - } - if util.PathIsNewer(OverlayDir, OverlayFile) { - if force == false { - wwlog.Printf(wwlog.INFO, "%-35s: Skipping, overlay is current\n", node.Fqdn) - continue - } - } - - wwlog.Printf(wwlog.DEBUG, "Changing directory to OverlayDir: %s\n", OverlayDir) - err = os.Chdir(OverlayDir) - if err != nil { - wwlog.Printf(wwlog.ERROR, "Could not chdir() to OverlayDir: %s\n", OverlayDir) - continue - } - - wwlog.Printf(wwlog.DEBUG, "Walking the file system: %s\n", OverlayDir) - err = filepath.Walk(".", func(location string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - if info.IsDir() { - wwlog.Printf(wwlog.DEBUG, "Found directory: %s\n", location) - - err := os.MkdirAll(path.Join(tmpDir, location), info.Mode()) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - return err - } - - } else if filepath.Ext(location) == ".ww" { - wwlog.Printf(wwlog.DEBUG, "Found template file: %s\n", location) - - destFile := strings.TrimSuffix(location, ".ww") - - tmpl, err := template.New(path.Base(location)).Funcs(template.FuncMap{"Include": fileInclude}).ParseGlob(path.Join(OverlayDir, destFile + ".ww*")) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - return err - } - - w, err := os.OpenFile(path.Join(tmpDir, destFile), os.O_RDWR|os.O_CREATE, info.Mode()) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - return err - } - defer w.Close() - - err = tmpl.Execute(w, node) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - return err - } - - } else if b, _ := regexp.MatchString(`\.ww[a-zA-Z0-9\-\._]*$`, location); b == true { - wwlog.Printf(wwlog.DEBUG, "Ignoring WW template file: %s\n", location) - } else { - wwlog.Printf(wwlog.DEBUG, "Found file: %s\n", location) - - err := util.CopyFile(path.Join(OverlayDir, location), path.Join(tmpDir, location)) - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - return err - } - - } - - return nil - }) - wwlog.Printf(wwlog.VERBOSE, "Finished generating overlay directory for: %s\n", node.Fqdn) - - cmd := fmt.Sprintf("cd \"%s\"; find . | cpio --quiet -o -H newc -F \"%s\"", tmpDir, OverlayFile) - wwlog.Printf(wwlog.DEBUG, "RUNNING: %s\n", cmd) - err = exec.Command("/bin/sh", "-c", cmd).Run() - if err != nil { - wwlog.Printf(wwlog.ERROR, "Could not generate system image overlay: %s\n", err) - continue - } - wwlog.Printf(wwlog.INFO, "%-35s: Done\n", node.Fqdn) - - wwlog.Printf(wwlog.DEBUG, "Removing temporary directory: %s\n", tmpDir) - os.RemoveAll(tmpDir) - } - } - - wwlog.SetIndent(0) - return nil -} diff --git a/internal/app/wwctl/build/vnfs/containerdir.go b/internal/app/wwctl/build/vnfs/containerdir.go deleted file mode 100644 index 92d433a6..00000000 --- a/internal/app/wwctl/build/vnfs/containerdir.go +++ /dev/null @@ -1,65 +0,0 @@ -package vnfs - -import ( - "fmt" - "github.com/hpcng/warewulf/internal/pkg/config" - "github.com/hpcng/warewulf/internal/pkg/util" - "github.com/hpcng/warewulf/internal/pkg/vnfs" - "github.com/hpcng/warewulf/internal/pkg/wwlog" - "os" - "path" -) - -func BuildContainerdir(v vnfs.VnfsObject) { - config := config.New() - - if _, err := os.Stat(v.Source()); err != nil { - wwlog.Printf(wwlog.INFO, "%-35s: Skipping (bad path)\n", v.Name()) - return - } - - wwlog.Printf(wwlog.DEBUG, "Checking if there have been any updates to the VNFS directory\n") - if util.PathIsNewer(v.Source(), config.VnfsImage(v.NameClean())) { - if buildForce == false { - wwlog.Printf(wwlog.INFO, "%-35s: Skipping, VNFS is current\n", v.Name()) - return - } - } - - wwlog.Printf(wwlog.DEBUG, "Making the directory: %s\n", path.Dir(config.VnfsImage(v.NameClean()))) - err := os.MkdirAll(path.Dir(config.VnfsImage(v.NameClean())), 0755) - if err != nil { - fmt.Printf("ERROR: %s\n", err) - return - } - - wwlog.Printf(wwlog.DEBUG, "Making the directory: %s\n", path.Dir(config.VnfsChroot(v.NameClean()))) - err = os.MkdirAll(path.Dir(config.VnfsChroot(v.NameClean())), 0755) - if err != nil { - fmt.Printf("ERROR: %s\n", err) - return - } - - wwlog.Printf(wwlog.DEBUG, "Building VNFS image: '%s' -> '%s'\n", v.Source(), config.VnfsImage(v.NameClean())) - err = buildVnfs(v.Source(), config.VnfsImage(v.NameClean())) - if err != nil { - fmt.Printf("ERROR: %s\n", err) - os.Exit(1) - } - - // Setup links from OCI rootfs to chroot path - _ = os.Remove(config.VnfsChroot(v.NameClean()) + "-link") - err = os.Symlink(v.Source(), config.VnfsChroot(v.NameClean())+"-link") - if err != nil { - wwlog.Printf(wwlog.ERROR, "Could not create symlink for Chroot: %s\n", err) - os.Exit(1) - } - err = os.Rename(config.VnfsChroot(v.NameClean())+"-link", config.VnfsChroot(v.NameClean())) - if err != nil { - wwlog.Printf(wwlog.ERROR, "Could not rename link: %s\n", err) - os.Exit(1) - } - - wwlog.Printf(wwlog.INFO, "%-35s: Done\n", v.Name()) - -} diff --git a/internal/app/wwctl/build/vnfs/docker.go b/internal/app/wwctl/build/vnfs/docker.go deleted file mode 100644 index 84ba9150..00000000 --- a/internal/app/wwctl/build/vnfs/docker.go +++ /dev/null @@ -1,102 +0,0 @@ -package vnfs - -import ( - "context" - "fmt" - "github.com/hpcng/warewulf/internal/pkg/config" - "github.com/hpcng/warewulf/internal/pkg/oci" - "github.com/hpcng/warewulf/internal/pkg/vnfs" - "github.com/hpcng/warewulf/internal/pkg/wwlog" - "os" - "path" -) - - -func BuildDocker(v vnfs.VnfsObject) { - wwlog.Printf(wwlog.VERBOSE, "Building OCI Container: %s\n", v.Source()) - config := config.New() - - OciCacheDir := config.LocalStateDir + "/oci" - VnfsHashDir := config.LocalStateDir + "/oci/vnfs" - - c, err := oci.NewCache(oci.OptSetCachePath(OciCacheDir)) - if err != nil { - fmt.Printf("ERROR: %s\n", err) - os.Exit(1) - } - - wwlog.Printf(wwlog.VERBOSE, "Downloading OCI container layers\n") - sourcePath, err := c.Pull(context.Background(), v.Source(), nil) - if err != nil { - fmt.Printf("ERROR: %s\n", err) - os.Exit(1) - } - - hashDestination := VnfsHashDir + path.Base(sourcePath) - - name, err := os.Readlink(config.VnfsImage(v.NameClean())) - if err == nil { - if name == hashDestination { - wwlog.Printf(wwlog.INFO, "%-35s: Skipping, VNFS is current\n", v.Name()) - return - } - } - - err = os.MkdirAll(VnfsHashDir, 0755) - if err != nil { - fmt.Printf("ERROR: %s\n", err) - return - } - err = os.MkdirAll(path.Dir(config.VnfsImage(v.NameClean())), 0755) - if err != nil { - fmt.Printf("ERROR: %s\n", err) - return - } - err = os.MkdirAll(path.Dir(config.VnfsChroot(v.NameClean())), 0755) - if err != nil { - fmt.Printf("ERROR: %s\n", err) - return - } - - wwlog.Printf(wwlog.VERBOSE, "Building bootable VNFS image\n") - - err = buildVnfs(sourcePath, hashDestination) - if err != nil { - fmt.Printf("ERROR: %s\n", err) - os.Exit(1) - } - - wwlog.Printf(wwlog.VERBOSE, "Finalizing Build\n") - - // Setup links from OCI image to provision path - _ = os.Remove(config.VnfsImage(v.NameClean()) + "-link") - err = os.Symlink(hashDestination, config.VnfsImage(v.NameClean())+"-link") - if err != nil { - wwlog.Printf(wwlog.ERROR, "Could not create symlink for Image: %s\n", err) - os.Exit(1) - } - err = os.Rename(config.VnfsImage(v.NameClean())+"-link", config.VnfsImage(v.NameClean())) - if err != nil { - wwlog.Printf(wwlog.ERROR, "Could not rename link: %s\n", err) - os.Exit(1) - } - - // Setup links from OCI rootfs to chroot path - _ = os.Remove(config.VnfsChroot(v.NameClean()) + "-link") - err = os.Symlink(sourcePath, config.VnfsChroot(v.NameClean())+"-link") - if err != nil { - wwlog.Printf(wwlog.ERROR, "Could not create symlink for Chroot: %s\n", err) - os.Exit(1) - } - err = os.Rename(config.VnfsChroot(v.NameClean())+"-link", config.VnfsChroot(v.NameClean())) - if err != nil { - wwlog.Printf(wwlog.ERROR, "Could not rename link: %s\n", err) - os.Exit(1) - } - - - wwlog.Printf(wwlog.INFO, "%-35s: Done\n", v.Name()) - - return -} - diff --git a/internal/app/wwctl/build/vnfs/util.go b/internal/app/wwctl/build/vnfs/util.go deleted file mode 100644 index 91d26a39..00000000 --- a/internal/app/wwctl/build/vnfs/util.go +++ /dev/null @@ -1,14 +0,0 @@ -package vnfs - -import ( - "fmt" - "os/exec" -) - -func buildVnfs(source string, dest string) error { - cmd := fmt.Sprintf("cd %s; find . | cpio --quiet -o -H newc | gzip -c > \"%s\"", source, dest) - - err := exec.Command("/bin/sh", "-c", cmd).Run() - - return err -} diff --git a/internal/app/wwctl/build/vnfs/vnfs.go b/internal/app/wwctl/build/vnfs/vnfs.go deleted file mode 100644 index e3f2dc4d..00000000 --- a/internal/app/wwctl/build/vnfs/vnfs.go +++ /dev/null @@ -1,47 +0,0 @@ -package vnfs - -import ( - "strings" - - "github.com/hpcng/warewulf/internal/pkg/assets" - "github.com/hpcng/warewulf/internal/pkg/vnfs" - "github.com/hpcng/warewulf/internal/pkg/wwlog" -) - -var buildForce bool - -func Build(nodeList []assets.NodeInfo, force bool) error { - set := make(map[string]int) - - wwlog.Printf(wwlog.INFO, "Building and Importing VNFS Images:\n") - wwlog.SetIndent(4) - - buildForce = force - - for _, node := range nodeList { - if node.Vnfs != "" { - set[node.Vnfs]++ - wwlog.Printf(wwlog.DEBUG, "Node '%s' has VNFS '%s'\n", node.Fqdn, node.Vnfs) - } - } - - for uri := range set { - v := vnfs.New(uri) - wwlog.Printf(wwlog.VERBOSE, "VNFS found: %s (nodes: %d)\n", uri, set[uri]) - if strings.HasPrefix(uri, "/") { - if strings.HasSuffix(uri, "tar.gz") { - //wwlog.Printf(wwlog.WARN, "Building VNFS from local tarball: %s\n", uri) - wwlog.Printf(wwlog.WARN, "Building VNFS from local tarball is not supported yet: %s\n", uri) - - } else { - BuildContainerdir(v) - } - } else { - BuildDocker(v) - } - } - - wwlog.SetIndent(0) - - return nil -} diff --git a/internal/app/wwctl/group/add/main.go b/internal/app/wwctl/group/add/main.go new file mode 100644 index 00000000..ab092f67 --- /dev/null +++ b/internal/app/wwctl/group/add/main.go @@ -0,0 +1,29 @@ +package add + +import ( + "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 { + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Failed opening node database: %s\n", err) + os.Exit(1) + } + + for _, g := range args { + err = nodeDB.AddGroup(g) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + + nodeDB.Persist() + + return nil +} + diff --git a/internal/app/wwctl/group/add/root.go b/internal/app/wwctl/group/add/root.go new file mode 100644 index 00000000..35070791 --- /dev/null +++ b/internal/app/wwctl/group/add/root.go @@ -0,0 +1,25 @@ +package add + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "add", + Short: "Add a new node group", + Long: "Add a new node group ", + RunE: CobraRunE, + Args: cobra.MinimumNArgs(1), + } + SetVnfs string + SetKernel string +) + +func init() { + baseCmd.PersistentFlags().StringVarP(&SetVnfs, "vnfs", "V", "", "Set node Virtual Node File System (VNFS)") + baseCmd.PersistentFlags().StringVarP(&SetKernel, "kernel", "K", "", "Set Kernel version for nodes") +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/group/delete/main.go b/internal/app/wwctl/group/delete/main.go new file mode 100644 index 00000000..97348514 --- /dev/null +++ b/internal/app/wwctl/group/delete/main.go @@ -0,0 +1,61 @@ +package delete + +import ( + "fmt" + "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 { + var count int + var numNodes int + + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Failed to open node database: %s\n", err) + os.Exit(1) + } + + nodes, err := nodeDB. FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not load all nodes: %s\n", err) + os.Exit(1) + } + + for _, g := range args { + err := nodeDB.DelGroup(g) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + } else { + for _, n := range nodes { + if n.GroupName == g { + numNodes ++ + } + } + count ++ + } + } + + if count > 0 { + q := fmt.Sprintf("Are you sure you want to delete %d group(s) (%d nodes)", count, numNodes) + + prompt := promptui.Prompt{ + Label: q, + IsConfirm: true, + } + + result, _ := prompt.Run() + + if result == "y" || result == "yes" { + nodeDB.Persist() + } + + } else { + wwlog.Printf(wwlog.INFO, "No groups found\n") + } + + return nil +} diff --git a/internal/app/wwctl/group/delete/root.go b/internal/app/wwctl/group/delete/root.go new file mode 100644 index 00000000..a4a58522 --- /dev/null +++ b/internal/app/wwctl/group/delete/root.go @@ -0,0 +1,25 @@ +package delete + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "delete", + Short: "Add a new node group", + Long: "Add a new node group ", + RunE: CobraRunE, + } + SetVnfs string + SetKernel string + // SetGroupLevel bool +) + +func init() { + baseCmd.PersistentFlags().StringVarP(&SetVnfs, "vnfs", "V", "", "Set node Virtual Node File System (VNFS)") + baseCmd.PersistentFlags().StringVarP(&SetKernel, "kernel", "K", "", "Set Kernel version for nodes") +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/group/list/main.go b/internal/app/wwctl/group/list/main.go new file mode 100644 index 00000000..177ff841 --- /dev/null +++ b/internal/app/wwctl/group/list/main.go @@ -0,0 +1,44 @@ +package list + +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" + "os" + "reflect" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + groups, err := nodeDB.FindAllGroups() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not find all nodes: %s\n", err) + os.Exit(1) + } + + + if ShowAll == true { + for _, group := range groups { + v := reflect.ValueOf(group) + typeOfS := v.Type() + fmt.Printf("################################################################################\n") + for i := 0; i< v.NumField(); i++ { + fmt.Printf("%-25s %s = %v\n", group.Id, typeOfS.Field(i).Name, v.Field(i).Interface()) + } + } + } else { + fmt.Printf("%-22s %-16s %-30s %-30s %-16s\n", "GROUP NAME", "DOMAINNAME", "KERNEL VERSION", "VNFS IMAGE", "RUNTIME OVERLAY") + for _, g := range groups { + fmt.Printf("%-22s %-16s %-30s %-30s %-16s\n", g.GroupName, g.DomainName, g.KernelVersion, g.Vnfs, g.RuntimeOverlay) + } + } + + + return nil +} diff --git a/internal/app/wwctl/group/list/root.go b/internal/app/wwctl/group/list/root.go new file mode 100644 index 00000000..5d0183f8 --- /dev/null +++ b/internal/app/wwctl/group/list/root.go @@ -0,0 +1,23 @@ +package list + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "list", + Short: "List group configurations", + Long: "List group configurations ", + RunE: CobraRunE, + } + ShowAll bool +) + +func init() { + baseCmd.PersistentFlags().BoolVarP(&ShowAll, "all", "a", false, "Show all node configurations") + +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/group/root.go b/internal/app/wwctl/group/root.go new file mode 100644 index 00000000..98cf1ebb --- /dev/null +++ b/internal/app/wwctl/group/root.go @@ -0,0 +1,29 @@ +package group + +import ( + "github.com/hpcng/warewulf/internal/app/wwctl/group/add" + "github.com/hpcng/warewulf/internal/app/wwctl/group/delete" + "github.com/hpcng/warewulf/internal/app/wwctl/group/list" + "github.com/hpcng/warewulf/internal/app/wwctl/group/set" + "github.com/spf13/cobra" +) + +var ( + baseCmd = &cobra.Command{ + Use: "group", + Short: "Group management", + Long: "Management of group settings and power management", + } +) + +func init() { + baseCmd.AddCommand(list.GetCommand()) + baseCmd.AddCommand(set.GetCommand()) + baseCmd.AddCommand(add.GetCommand()) + baseCmd.AddCommand(delete.GetCommand()) +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/group/set/main.go b/internal/app/wwctl/group/set/main.go new file mode 100644 index 00000000..4ed4e3e7 --- /dev/null +++ b/internal/app/wwctl/group/set/main.go @@ -0,0 +1,247 @@ +package set + +import ( + "fmt" + "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 { + var err error + var groups []node.GroupInfo + + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + if err != nil { + wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + os.Exit(1) + } + + if len(args) > 0 { + var tmp []node.GroupInfo + tmp, err = nodeDB.FindAllGroups() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + for _, a := range args { + for _, g := range tmp { + if g.Id == a { + groups = append(groups, g) + } + } + } + + } else { + cmd.Usage() + os.Exit(1) + } + + for _, g := range groups { + if SetVnfs != "" { + wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting vnfs to: %s\n", g.Id, SetVnfs) + err := nodeDB.SetGroupVal(g.Id, "vnfs", SetVnfs) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + if SetClearNodes == true { + nodes, err := nodeDB.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + for _, n := range nodes { + _ = nodeDB.SetNodeVal(g.Id, n.Id, "vnfs", "") + } + } + } + + if SetKernel != "" { + wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting kernel to: %s\n", g.Id, SetVnfs) + err := nodeDB.SetGroupVal(g.Id, "kernel", SetKernel) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + if SetClearNodes == true { + nodes, err := nodeDB.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + for _, n := range nodes { + _ = nodeDB.SetNodeVal(g.Id, n.Id, "kernel", "") + } + } + } + + if SetDomainName != "" { + wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting domain name to: %s\n", g.Id, SetDomainName) + err := nodeDB.SetGroupVal(g.Id, "domain", SetDomainName) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + if SetClearNodes == true { + nodes, err := nodeDB.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + for _, n := range nodes { + _ = nodeDB.SetNodeVal(g.Id, n.Id, "domain", "") + } + } + } + + if SetIpxe != "" { + wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting iPXE template to: %s\n", g.Id, SetIpxe) + err := nodeDB.SetGroupVal(g.Id, "ipxe", SetIpxe) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + if SetClearNodes == true { + nodes, err := nodeDB.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + for _, n := range nodes { + _ = nodeDB.SetNodeVal(g.Id, n.Id, "ipxe", "") + } + } + } + + if SetRuntimeOverlay != "" { + wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting runtime overlay to: %s\n", g.Id, SetRuntimeOverlay) + err := nodeDB.SetGroupVal(g.Id, "runtimeoverlay", SetRuntimeOverlay) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + if SetClearNodes == true { + nodes, err := nodeDB.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + for _, n := range nodes { + _ = nodeDB.SetNodeVal(g.Id, n.Id, "runtimeoverlay", "") + } + } + } + + if SetSystemOverlay != "" { + wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting system overlay to: %s\n", g.Id, SetSystemOverlay) + err := nodeDB.SetGroupVal(g.Id, "systemoverlay", SetSystemOverlay) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + if SetClearNodes == true { + nodes, err := nodeDB.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + for _, n := range nodes { + _ = nodeDB.SetNodeVal(g.Id, n.Id, "systemoverlay", "") + } + } + } + if SetIpmiIpaddr != "" { + wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting IPMI IP address to: %s\n", g.Id, SetIpmiIpaddr) + err := nodeDB.SetGroupVal(g.Id, "ipmiipaddr", SetIpmiIpaddr) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + if SetClearNodes == true { + nodes, err := nodeDB.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + for _, n := range nodes { + _ = nodeDB.SetNodeVal(g.Id, n.Id, "ipmiipaddr", "") + } + } + } + if SetIpmiUsername != "" { + wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting IPMI IP username to: %s\n", g.Id, SetIpmiUsername) + err := nodeDB.SetGroupVal(g.Id, "ipmiusername", SetIpmiUsername) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + if SetClearNodes == true { + nodes, err := nodeDB.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + for _, n := range nodes { + _ = nodeDB.SetNodeVal(g.Id, n.Id, "ipmiusername", "") + } + } + } + if SetIpmiPassword != "" { + wwlog.Printf(wwlog.VERBOSE, "Group: %s, Setting IPMI IP password to: %s\n", g.Id, SetIpmiPassword) + err := nodeDB.SetGroupVal(g.Id, "ipmipassword", SetIpmiPassword) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + if SetClearNodes == true { + nodes, err := nodeDB.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + for _, n := range nodes { + _ = nodeDB.SetNodeVal(g.Id, n.Id, "ipmipassword", "") + } + } + } + + + + + + + } + + if len(groups) > 0 { + q := fmt.Sprintf("Are you sure you want to modify %d group(s)", len(groups)) + + prompt := promptui.Prompt{ + Label: q, + IsConfirm: true, + } + + result, _ := prompt.Run() + + if result == "y" || result == "yes" { + nodeDB.Persist() + } + + } else { + fmt.Printf("No groups found\n") + } + + return nil +} diff --git a/internal/app/wwctl/group/set/root.go b/internal/app/wwctl/group/set/root.go new file mode 100644 index 00000000..8338958b --- /dev/null +++ b/internal/app/wwctl/group/set/root.go @@ -0,0 +1,43 @@ +package set + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "set", + Short: "Set group configurations", + Long: "Set group configurations ", + RunE: CobraRunE, + } + SetVnfs string + SetKernel string + SetDomainName string + SetIpxe string + SetRuntimeOverlay string + SetSystemOverlay string + SetHostname string + SetClearNodes bool + SetIpmiIpaddr string + SetIpmiUsername string + SetIpmiPassword string + +) + +func init() { + baseCmd.PersistentFlags().StringVarP(&SetVnfs, "vnfs", "V", "", "Set node Virtual Node File System (VNFS)") + baseCmd.PersistentFlags().StringVarP(&SetKernel, "kernel", "K", "", "Set Kernel version for nodes") + baseCmd.PersistentFlags().StringVarP(&SetDomainName, "domain", "D", "", "Set the node's domain name") + baseCmd.PersistentFlags().StringVarP(&SetIpxe, "ipxe", "P", "", "Set the node's iPXE template name") + baseCmd.PersistentFlags().StringVarP(&SetRuntimeOverlay, "runtime", "R", "", "Set the node's runtime overlay") + baseCmd.PersistentFlags().StringVarP(&SetSystemOverlay, "system", "S", "", "Set the node's system overlay") + baseCmd.PersistentFlags().StringVar(&SetIpmiIpaddr, "ipmi", "", "Set the node's IPMI address") + baseCmd.PersistentFlags().StringVar(&SetIpmiUsername, "ipmiuser", "", "Set the node's IPMI username") + baseCmd.PersistentFlags().StringVar(&SetIpmiPassword, "ipmipass", "", "Set the node's IPMI password") + + baseCmd.PersistentFlags().BoolVarP(&SetClearNodes, "clear", "c", false, "Clear node configurations when setting parent group") +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/kernel/build/main.go b/internal/app/wwctl/kernel/build/main.go index cc11403a..89f01653 100644 --- a/internal/app/wwctl/kernel/build/main.go +++ b/internal/app/wwctl/kernel/build/main.go @@ -1,20 +1,26 @@ package build import ( - "github.com/hpcng/warewulf/internal/pkg/assets" "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 { - var nodes []assets.NodeInfo + var nodes []node.NodeInfo set := make(map[string]int) + n, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + if len(args) == 1 && ByNode == true { var err error - nodes, err = assets.SearchByName(args[0]) + nodes, err = n.SearchByName(args[0]) if err != nil { wwlog.Printf(wwlog.ERROR, "Could not find nodes for search term: %s\n", args[0]) os.Exit(1) @@ -26,7 +32,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } else if BuildAll == true { var err error - nodes, err = assets.FindAllNodes() + nodes, err = n.FindAllNodes() if err != nil { wwlog.Printf(wwlog.ERROR, "Could not get list of nodes: %s\n", err) os.Exit(1) diff --git a/internal/app/wwctl/node/add/main.go b/internal/app/wwctl/node/add/main.go new file mode 100644 index 00000000..e52bf95b --- /dev/null +++ b/internal/app/wwctl/node/add/main.go @@ -0,0 +1,28 @@ +package add + +import ( + "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 { + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Failed to open node database: %s\n", err) + os.Exit(1) + } + + for _, a := range args { + err = nodeDB.AddNode(SetGroup, a) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + + nodeDB.Persist() + + return nil +} \ No newline at end of file diff --git a/internal/app/wwctl/node/add/root.go b/internal/app/wwctl/node/add/root.go new file mode 100644 index 00000000..b95a8b90 --- /dev/null +++ b/internal/app/wwctl/node/add/root.go @@ -0,0 +1,23 @@ +package add + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "add", + Short: "Add new node", + Long: "Add new node ", + RunE: CobraRunE, + Args: cobra.MinimumNArgs(1), + } + SetGroup string +) + +func init() { + baseCmd.PersistentFlags().StringVarP(&SetGroup, "group", "g", "default", "Set group to add nodes to") +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/node/delete/main.go b/internal/app/wwctl/node/delete/main.go new file mode 100644 index 00000000..23b566f4 --- /dev/null +++ b/internal/app/wwctl/node/delete/main.go @@ -0,0 +1,55 @@ +package delete + +import ( + "fmt" + "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 { + var count int + + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Failed to open node database: %s\n", err) + os.Exit(1) + } + + nodeList, err := nodeDB.SearchByNameList(args) + + for _, n := range nodeList { + if SetGroup != "" && SetGroup != n.GroupName { + wwlog.Printf(wwlog.DEBUG, "skipping node of different group: %s/%s\n", n.GroupName, n.Id) + continue + } + err := nodeDB.DelNode(n.GroupName, n.Id) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + } else { + count++ + } + } + + if count > 0 { + q := fmt.Sprintf("Are you sure you want to delete %d nodes(s)", count) + + prompt := promptui.Prompt{ + Label: q, + IsConfirm: true, + } + + result, _ := prompt.Run() + + if result == "y" || result == "yes" { + nodeDB.Persist() + } + + } else { + fmt.Printf("No nodes found\n") + } + + return nil +} diff --git a/internal/app/wwctl/node/delete/root.go b/internal/app/wwctl/node/delete/root.go new file mode 100644 index 00000000..ded732bf --- /dev/null +++ b/internal/app/wwctl/node/delete/root.go @@ -0,0 +1,25 @@ +package delete + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "delete", + Short: "Set node configurations", + Long: "Set node configurations ", + RunE: CobraRunE, + } + SetForce string + SetGroup string +) + +func init() { + baseCmd.PersistentFlags().StringVarP(&SetForce, "force", "f", "", "Force node delete") + baseCmd.PersistentFlags().StringVarP(&SetGroup, "group", "g", "default", "Set group to delete nodes from") + +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/node/list/main.go b/internal/app/wwctl/node/list/main.go new file mode 100644 index 00000000..95ebec14 --- /dev/null +++ b/internal/app/wwctl/node/list/main.go @@ -0,0 +1,71 @@ +package list + +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" + "os" + "reflect" +) + + + +func CobraRunE(cmd *cobra.Command, args []string) error { + var err error + var nodes []node.NodeInfo + + n, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + if len(args) > 0 { + nodes, err = n.SearchByNameList(args) + } else { + nodes, err = n.FindAllNodes() + } + if err != nil { + wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + os.Exit(1) + } + + + if ShowAll == true { + for _, node := range nodes { + v := reflect.ValueOf(node) + typeOfS := v.Type() + fmt.Printf("################################################################################\n") + for i := 0; i< v.NumField(); i++ { + fmt.Printf("%-25s %s = %v\n", node.Fqdn, typeOfS.Field(i).Name, v.Field(i).Interface()) + } + } + + } else if ShowNet == true { + fmt.Printf("%-22s %-10s %-20s %-16s %-16s %-16s %s\n", "NODE NAME", "DEVICE", "HWADDR", "IPADDR", "NETMASK", "GATEWAY", "TYPE") + + for _, node := range nodes { + for name, dev := range node.NetDevs { + fmt.Printf("%-22s %-10s %-20s %-16s %-16s %-16s %s\n", node.Fqdn, name, dev.Hwaddr, dev.Ipaddr, dev.Netmask, dev.Gateway, dev.Type) + } + } + + } else if ShowIpmi == true { + fmt.Printf("%-22s %-16s %-20s %-20s\n", "NODE NAME", "IPMI IPADDR", "IPMI USERNAME", "IPMI PASSWORD") + + for _, node := range nodes { + fmt.Printf("%-22s %-16s %-20s %-20s\n", node.Fqdn, node.IpmiIpaddr, node.IpmiUserName, node.IpmiPassword) + } + + } else { + fmt.Printf("%-22s %-16s %-30s %-30s %-16s\n", "NODE NAME", "GROUP NAME", "KERNEL VERSION", "VNFS IMAGE", "RUNTIME OVERLAY") + + for _, node := range nodes { + fmt.Printf("%-22s %-16s %-30s %-30s %-16s\n", node.Fqdn, node.GroupName, node.KernelVersion, node.Vnfs, node.RuntimeOverlay) + } + } + + + return nil +} diff --git a/internal/app/wwctl/node/list/root.go b/internal/app/wwctl/node/list/root.go new file mode 100644 index 00000000..59c1c9cc --- /dev/null +++ b/internal/app/wwctl/node/list/root.go @@ -0,0 +1,26 @@ +package list + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "list", + Short: "List all nodes", + Long: "List all nodes", + RunE: CobraRunE, + } + ShowNet bool + ShowIpmi bool + ShowAll bool +) + +func init() { + baseCmd.PersistentFlags().BoolVarP(&ShowNet, "net", "n", false, "Show node network configurations") + baseCmd.PersistentFlags().BoolVarP(&ShowIpmi, "ipmi", "i", false, "Show node IPMI configurations") + baseCmd.PersistentFlags().BoolVarP(&ShowAll, "all", "a", false, "Show all node configurations") +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/node/poweroff/power.go b/internal/app/wwctl/node/poweroff/power.go index b6f05a7d..3364fd88 100644 --- a/internal/app/wwctl/node/poweroff/power.go +++ b/internal/app/wwctl/node/poweroff/power.go @@ -1,7 +1,7 @@ package poweroff import ( - "github.com/hpcng/warewulf/internal/pkg/assets" + "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" @@ -9,14 +9,17 @@ import ( ) func CobraRunE(cmd *cobra.Command, args []string) error { - var returnErr error = nil + var nodeList []node.NodeInfo - var nodeList []assets.NodeInfo + n, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } if len(args) >= 1 { - //nodeList, _ = assets.SearchByName(args[0]) - nodeList, _ = assets.SearchByNameList(args) + nodeList, _ = n.SearchByNameList(args) } else { wwlog.Printf(wwlog.ERROR, "No requested nodes\n") os.Exit(255) diff --git a/internal/app/wwctl/node/poweron/power.go b/internal/app/wwctl/node/poweron/power.go index 6b5821ab..900177c2 100644 --- a/internal/app/wwctl/node/poweron/power.go +++ b/internal/app/wwctl/node/poweron/power.go @@ -1,7 +1,7 @@ package poweron import ( - "github.com/hpcng/warewulf/internal/pkg/assets" + "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" @@ -9,14 +9,17 @@ import ( ) func CobraRunE(cmd *cobra.Command, args []string) error { - var returnErr error = nil + var nodeList []node.NodeInfo - var nodeList []assets.NodeInfo + n, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } if len(args) >= 1 { - //nodeList, _ = assets.SearchByName(args[0]) - nodeList, _ = assets.SearchByNameList(args) + nodeList, _ = n.SearchByNameList(args) } else { wwlog.Printf(wwlog.ERROR, "No requested nodes\n") os.Exit(255) diff --git a/internal/app/wwctl/node/powerstatus/power.go b/internal/app/wwctl/node/powerstatus/power.go index f503389b..1f02fb57 100644 --- a/internal/app/wwctl/node/powerstatus/power.go +++ b/internal/app/wwctl/node/powerstatus/power.go @@ -1,7 +1,7 @@ package powerstatus import ( - "github.com/hpcng/warewulf/internal/pkg/assets" + "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" @@ -9,14 +9,17 @@ import ( ) func CobraRunE(cmd *cobra.Command, args []string) error { - var returnErr error = nil + var nodeList []node.NodeInfo - var nodeList []assets.NodeInfo + n, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } if len(args) >= 1 { - //nodeList, _ = assets.SearchByName(args[0]) - nodeList, _ = assets.SearchByNameList(args) + nodeList, _ = n.SearchByNameList(args) } else { wwlog.Printf(wwlog.ERROR, "No requested nodes\n") os.Exit(255) diff --git a/internal/app/wwctl/node/root.go b/internal/app/wwctl/node/root.go index 150ae6bc..8d7f4ab4 100644 --- a/internal/app/wwctl/node/root.go +++ b/internal/app/wwctl/node/root.go @@ -1,9 +1,13 @@ package node import ( + "github.com/hpcng/warewulf/internal/app/wwctl/node/add" + "github.com/hpcng/warewulf/internal/app/wwctl/node/delete" + "github.com/hpcng/warewulf/internal/app/wwctl/node/list" "github.com/hpcng/warewulf/internal/app/wwctl/node/poweron" "github.com/hpcng/warewulf/internal/app/wwctl/node/poweroff" "github.com/hpcng/warewulf/internal/app/wwctl/node/powerstatus" + "github.com/hpcng/warewulf/internal/app/wwctl/node/set" "github.com/spf13/cobra" ) @@ -19,6 +23,10 @@ func init() { baseCmd.AddCommand(poweron.GetCommand()) baseCmd.AddCommand(poweroff.GetCommand()) baseCmd.AddCommand(powerstatus.GetCommand()) + baseCmd.AddCommand(list.GetCommand()) + baseCmd.AddCommand(set.GetCommand()) + baseCmd.AddCommand(add.GetCommand()) + baseCmd.AddCommand(delete.GetCommand()) } // GetRootCommand returns the root cobra.Command for the application. diff --git a/internal/app/wwctl/node/set/main.go b/internal/app/wwctl/node/set/main.go new file mode 100644 index 00000000..e7d2db05 --- /dev/null +++ b/internal/app/wwctl/node/set/main.go @@ -0,0 +1,206 @@ +package set + +import ( + "fmt" + "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 { + var err error + var nodes []node.NodeInfo + + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + if err != nil { + wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + os.Exit(1) + } + + if len(args) > 0 { + nodes, err = nodeDB.SearchByNameList(args) + if err != nil { + wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + os.Exit(1) + } + + } else { + cmd.Usage() + os.Exit(1) + } + + for _, n := range nodes { + wwlog.Printf(wwlog.VERBOSE, "Evaluating node: %s\n", n.Fqdn) + if SetVnfs != "" { + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting vnfs to: %s\n", n.Fqdn, SetVnfs) + err := nodeDB.SetNodeVal(n.Gid, n.Id, "vnfs", SetVnfs) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetKernel != "" { + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting kernel to: %s\n", n.Fqdn, SetVnfs) + err := nodeDB.SetNodeVal(n.Gid, n.Id, "kernel", SetKernel) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetDomainName != "" { + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting domain name to: %s\n", n.Fqdn, SetDomainName) + err := nodeDB.SetNodeVal(n.Gid, n.Id, "domain", SetDomainName) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetIpxe != "" { + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting iPXE template to: %s\n", n.Fqdn, SetIpxe) + err := nodeDB.SetNodeVal(n.Gid, n.Id, "ipxe", SetIpxe) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetRuntimeOverlay != "" { + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting runtime overlay to: %s\n", n.Fqdn, SetRuntimeOverlay) + err := nodeDB.SetNodeVal(n.Gid, n.Id, "runtimeoverlay", SetRuntimeOverlay) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetSystemOverlay != "" { + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting system overlay to: %s\n", n.Fqdn, SetSystemOverlay) + err := nodeDB.SetNodeVal(n.Gid, n.Id, "systemoverlay", SetSystemOverlay) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetHostname != "" { + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting hostname to: %s\n", n.Fqdn, SetHostname) + err := nodeDB.SetNodeVal(n.Gid, n.Id, "hostname", SetHostname) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetIpmiIpaddr != "" { + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI IP address to: %s\n", n.Fqdn, SetIpmiIpaddr) + err := nodeDB.SetNodeVal(n.Gid, n.Id, "ipmiipaddr", SetIpmiIpaddr) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetIpmiUsername != "" { + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI IP username to: %s\n", n.Fqdn, SetIpmiUsername) + err := nodeDB.SetNodeVal(n.Gid, n.Id, "ipmiusername", SetIpmiUsername) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetIpmiPassword != "" { + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI IP password to: %s\n", n.Fqdn, SetIpmiPassword) + err := nodeDB.SetNodeVal(n.Gid, n.Id, "ipmipassword", SetIpmiPassword) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + + + + if SetNetDevDel == true { + if SetNetDev == "" { + wwlog.Printf(wwlog.ERROR, "You must include the '--netdev' option\n") + os.Exit(1) + } + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Deleting network device: %s\n", n.Fqdn, SetNetDev) + err := nodeDB.DelNodeNet(n.Gid, n.Id, SetNetDev) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + } + if SetIpaddr != "" { + if SetNetDev == "" { + wwlog.Printf(wwlog.ERROR, "You must include the '--netdev' option\n") + os.Exit(1) + } + wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting Ipaddr to: %s\n", n.Fqdn, SetNetDev, SetIpaddr) + err := nodeDB.SetNodeNet(n.Gid, n.Id, SetNetDev, "ipaddr", SetIpaddr) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetNetmask != "" { + if SetNetDev == "" { + wwlog.Printf(wwlog.ERROR, "You must include the '--netdev' option\n") + os.Exit(1) + } + wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting netmask to: %s\n", n.Fqdn, SetNetDev, SetNetmask) + err := nodeDB.SetNodeNet(n.Gid, n.Id, SetNetDev, "netmask", SetNetmask) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetGateway != "" { + if SetNetDev == "" { + wwlog.Printf(wwlog.ERROR, "You must include the '--netdev' option\n") + os.Exit(1) + } + wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting gateway to: %s\n", n.Fqdn, SetNetDev, SetGateway) + err := nodeDB.SetNodeNet(n.Gid, n.Id, SetNetDev, "gateway", SetGateway) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + if SetHwaddr != "" { + if SetNetDev == "" { + wwlog.Printf(wwlog.ERROR, "You must include the '--netdev' option\n") + os.Exit(1) + } + wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting HW address to: %s\n", n.Fqdn, SetNetDev, SetHwaddr) + err := nodeDB.SetNodeNet(n.Gid, n.Id, SetNetDev, "hwaddr", SetHwaddr) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + } + } + + if len(nodes) > 0 { + q := fmt.Sprintf("Are you sure you want to modify %d nodes(s)", len(nodes)) + + prompt := promptui.Prompt{ + Label: q, + IsConfirm: true, + } + + result, _ := prompt.Run() + + if result == "y" || result == "yes" { + nodeDB.Persist() + } + + } else { + fmt.Printf("No nodes found\n") + } + + return nil +} \ No newline at end of file diff --git a/internal/app/wwctl/node/set/root.go b/internal/app/wwctl/node/set/root.go new file mode 100644 index 00000000..211be16e --- /dev/null +++ b/internal/app/wwctl/node/set/root.go @@ -0,0 +1,55 @@ +package set + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "set", + Short: "Set node configurations", + Long: "Set node configurations ", + RunE: CobraRunE, + } + SetVnfs string + SetKernel string + SetNetDev string + SetIpaddr string + SetNetmask string + SetGateway string + SetHwaddr string + SetNetDevDel bool + SetDomainName string + SetIpxe string + SetRuntimeOverlay string + SetSystemOverlay string + SetHostname string + SetIpmiIpaddr string + SetIpmiUsername string + SetIpmiPassword string + +) + +func init() { + baseCmd.PersistentFlags().StringVarP(&SetVnfs, "vnfs", "V", "", "Set node Virtual Node File System (VNFS)") + baseCmd.PersistentFlags().StringVarP(&SetKernel, "kernel", "K", "", "Set Kernel version for nodes") + baseCmd.PersistentFlags().StringVarP(&SetDomainName, "domain", "D", "", "Set the node's domain name") + baseCmd.PersistentFlags().StringVarP(&SetIpxe, "ipxe", "P", "", "Set the node's iPXE template name") + baseCmd.PersistentFlags().StringVarP(&SetRuntimeOverlay, "runtime", "R", "", "Set the node's runtime overlay") + baseCmd.PersistentFlags().StringVarP(&SetSystemOverlay, "system", "S", "", "Set the node's system overlay") + baseCmd.PersistentFlags().StringVarP(&SetHostname, "hostname", "H", "", "Set the node's hostname") + baseCmd.PersistentFlags().StringVar(&SetIpmiIpaddr, "ipmi", "", "Set the node's IPMI address") + baseCmd.PersistentFlags().StringVar(&SetIpmiUsername, "ipmiuser", "", "Set the node's IPMI username") + baseCmd.PersistentFlags().StringVar(&SetIpmiPassword, "ipmipass", "", "Set the node's IPMI password") + + baseCmd.PersistentFlags().StringVarP(&SetNetDev, "netdev", "n", "", "Define the network device to configure") + baseCmd.PersistentFlags().StringVarP(&SetIpaddr, "ipaddr", "I", "", "Set the node's network device IP address") + baseCmd.PersistentFlags().StringVarP(&SetNetmask, "netmask", "M", "", "Set the node's network device netmask") + baseCmd.PersistentFlags().StringVarP(&SetGateway, "gateway", "G", "", "Set the node's network device gateway") + baseCmd.PersistentFlags().StringVarP(&SetHwaddr, "hwaddr", "N", "", "Set the node's network device HW address") + baseCmd.PersistentFlags().BoolVar(&SetNetDevDel, "delete", false, "Delete the node's network device") + +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/overlay/build/main.go b/internal/app/wwctl/overlay/build/main.go index 7ca3d49b..3dbb0eda 100644 --- a/internal/app/wwctl/overlay/build/main.go +++ b/internal/app/wwctl/overlay/build/main.go @@ -1,7 +1,7 @@ package build import ( - "github.com/hpcng/warewulf/internal/pkg/assets" + "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" @@ -9,10 +9,16 @@ import ( ) func CobraRunE(cmd *cobra.Command, args []string) error { - var updateNodes []assets.NodeInfo + var updateNodes []node.NodeInfo + + n, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } if len(args) > 0 && BuildAll == false { - nodes, err := assets.FindAllNodes() + nodes, err := n.FindAllNodes() if err != nil { wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) os.Exit(1) @@ -27,7 +33,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } } else { var err error - updateNodes, err = assets.FindAllNodes() + updateNodes, err = n.FindAllNodes() if err != nil { wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) os.Exit(1) diff --git a/internal/app/wwctl/overlay/chmod/main.go b/internal/app/wwctl/overlay/chmod/main.go index c03ef9de..4ce3c364 100644 --- a/internal/app/wwctl/overlay/chmod/main.go +++ b/internal/app/wwctl/overlay/chmod/main.go @@ -1,8 +1,8 @@ package chmod import ( - "github.com/hpcng/warewulf/internal/pkg/assets" "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" @@ -49,13 +49,19 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if NoOverlayUpdate == false { - nodes, err := assets.FindAllNodes() + n, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + nodes, err := n.FindAllNodes() if err != nil { wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) os.Exit(1) } - var updateNodes []assets.NodeInfo + var updateNodes []node.NodeInfo for _, node := range nodes { if SystemOverlay == true && node.SystemOverlay == overlayName { diff --git a/internal/app/wwctl/overlay/create/main.go b/internal/app/wwctl/overlay/create/main.go index 731d0a67..95d31c90 100644 --- a/internal/app/wwctl/overlay/create/main.go +++ b/internal/app/wwctl/overlay/create/main.go @@ -1,7 +1,7 @@ package create import ( - "github.com/hpcng/warewulf/internal/pkg/assets" + "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" @@ -11,7 +11,6 @@ import ( func CobraRunE(cmd *cobra.Command, args []string) error { - if len(args) < 1 { cmd.Help() os.Exit(1) @@ -34,13 +33,19 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if NoOverlayUpdate == false { - nodes, err := assets.FindAllNodes() + n, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + nodes, err := n.FindAllNodes() if err != nil { wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) os.Exit(1) } - var updateNodes []assets.NodeInfo + var updateNodes []node.NodeInfo for _, node := range nodes { if SystemOverlay == true && node.SystemOverlay == args[0] { diff --git a/internal/app/wwctl/overlay/delete/main.go b/internal/app/wwctl/overlay/delete/main.go index 709b0ad3..05fbbc25 100644 --- a/internal/app/wwctl/overlay/delete/main.go +++ b/internal/app/wwctl/overlay/delete/main.go @@ -2,8 +2,8 @@ package delete import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/assets" "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" @@ -95,13 +95,19 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if NoOverlayUpdate == false { - nodes, err := assets.FindAllNodes() + n, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + nodes, err := n.FindAllNodes() if err != nil { wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) os.Exit(1) } - var updateNodes []assets.NodeInfo + var updateNodes []node.NodeInfo for _, node := range nodes { if SystemOverlay == true && node.SystemOverlay == args[0] { diff --git a/internal/app/wwctl/overlay/edit/main.go b/internal/app/wwctl/overlay/edit/main.go index b53fe5b5..1b68e538 100644 --- a/internal/app/wwctl/overlay/edit/main.go +++ b/internal/app/wwctl/overlay/edit/main.go @@ -2,8 +2,8 @@ package edit import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/assets" "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" @@ -93,13 +93,19 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if NoOverlayUpdate == false { - nodes, err := assets.FindAllNodes() + n, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + nodes, err := n.FindAllNodes() if err != nil { wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) os.Exit(1) } - var updateNodes []assets.NodeInfo + var updateNodes []node.NodeInfo for _, node := range nodes { if SystemOverlay == true && node.SystemOverlay == args[0] { diff --git a/internal/app/wwctl/overlay/imprt/main.go b/internal/app/wwctl/overlay/imprt/main.go index 8035176e..0ce1c3b1 100644 --- a/internal/app/wwctl/overlay/imprt/main.go +++ b/internal/app/wwctl/overlay/imprt/main.go @@ -1,8 +1,8 @@ package imprt import ( - "github.com/hpcng/warewulf/internal/pkg/assets" "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" @@ -45,13 +45,19 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } if NoOverlayUpdate == false { - nodes, err := assets.FindAllNodes() + n, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + nodes, err := n.FindAllNodes() if err != nil { wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) os.Exit(1) } - var updateNodes []assets.NodeInfo + var updateNodes []node.NodeInfo for _, node := range nodes { if SystemOverlay == true && node.SystemOverlay == overlayName { diff --git a/internal/app/wwctl/overlay/list/main.go b/internal/app/wwctl/overlay/list/main.go index 1257c18a..1b51fff9 100644 --- a/internal/app/wwctl/overlay/list/main.go +++ b/internal/app/wwctl/overlay/list/main.go @@ -2,8 +2,8 @@ package list import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/assets" "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" @@ -17,7 +17,13 @@ func CobraRunE(cmd *cobra.Command, args []string) error { set := make(map[string]int) var o []string var err error - var nodeList []assets.NodeInfo + var nodeList []node.NodeInfo + + n, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } if SystemOverlay == true { if ListLong == false { @@ -39,7 +45,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { return err } - nodeList, err = assets.FindAllNodes() + nodeList, err = n.FindAllNodes() if err != nil { wwlog.Printf(wwlog.ERROR, "Could not get node configuration: %s\n", err) return err diff --git a/internal/app/wwctl/overlay/mkdir/main.go b/internal/app/wwctl/overlay/mkdir/main.go index 956f9682..62dfe7c8 100644 --- a/internal/app/wwctl/overlay/mkdir/main.go +++ b/internal/app/wwctl/overlay/mkdir/main.go @@ -2,8 +2,8 @@ package mkdir import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/assets" "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" @@ -42,13 +42,19 @@ func CobraRunE(cmd *cobra.Command, args []string) error { fmt.Printf("Created directory within overlay: %s:%s\n", args[0], args[1]) if NoOverlayUpdate == false { - nodes, err := assets.FindAllNodes() + n, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + nodes, err := n.FindAllNodes() if err != nil { wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) os.Exit(1) } - var updateNodes []assets.NodeInfo + var updateNodes []node.NodeInfo for _, node := range nodes { if SystemOverlay == true && node.SystemOverlay == args[0] { diff --git a/internal/app/wwctl/overlay/show/main.go b/internal/app/wwctl/overlay/show/main.go new file mode 100644 index 00000000..d75485e1 --- /dev/null +++ b/internal/app/wwctl/overlay/show/main.go @@ -0,0 +1,47 @@ +package show + +import ( + "fmt" + "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 { + config := config.New() + var overlaySourceDir string + overlayName := args[0] + fileName := args[1] + + if SystemOverlay == true { + overlaySourceDir = config.SystemOverlaySource(overlayName) + } else { + overlaySourceDir = config.RuntimeOverlaySource(overlayName) + } + + if util.IsDir(overlaySourceDir) == false { + wwlog.Printf(wwlog.ERROR, "Overlay does not exist: %s\n", overlayName) + os.Exit(1) + } + + overlayFile := path.Join(overlaySourceDir, fileName) + + if util.IsFile(overlayFile) == false { + wwlog.Printf(wwlog.ERROR, "File does not exist within overlay: %s:%s\n", overlayName, fileName) + os.Exit(1) + } + + f, err := ioutil.ReadFile(overlayFile) + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not read file: %s\n", err) + os.Exit(1) + } + + fmt.Print(string(f)) + + return nil +} \ No newline at end of file diff --git a/internal/app/wwctl/overlay/show/root.go b/internal/app/wwctl/overlay/show/root.go index edf55abd..ab13c82e 100644 --- a/internal/app/wwctl/overlay/show/root.go +++ b/internal/app/wwctl/overlay/show/root.go @@ -1,7 +1,6 @@ package show import ( - "fmt" "github.com/spf13/cobra" ) @@ -11,21 +10,17 @@ var ( Short: "Show Warewulf Overlay objects", Long: "Warewulf show overlay objects", RunE: CobraRunE, + Aliases: []string{"cat"}, + Args: cobra.ExactArgs(2), } - + SystemOverlay bool ) func init() { - + baseCmd.PersistentFlags().BoolVarP(&SystemOverlay, "system", "s", false, "Show System Overlays as well") } // GetRootCommand returns the root cobra.Command for the application. func GetCommand() *cobra.Command { return baseCmd -} - - -func CobraRunE(cmd *cobra.Command, args []string) error { - fmt.Printf("Show: Hello World\n") - return nil } \ No newline at end of file diff --git a/internal/app/wwctl/root.go b/internal/app/wwctl/root.go index dc14b516..cd1b64c3 100644 --- a/internal/app/wwctl/root.go +++ b/internal/app/wwctl/root.go @@ -2,6 +2,7 @@ package wwctl import ( "github.com/hpcng/warewulf/internal/app/wwctl/build" + "github.com/hpcng/warewulf/internal/app/wwctl/group" "github.com/hpcng/warewulf/internal/app/wwctl/kernel" "github.com/hpcng/warewulf/internal/app/wwctl/node" "github.com/hpcng/warewulf/internal/app/wwctl/overlay" @@ -30,6 +31,8 @@ func init() { rootCmd.AddCommand(vnfs.GetCommand()) rootCmd.AddCommand(node.GetCommand()) rootCmd.AddCommand(kernel.GetCommand()) + rootCmd.AddCommand(group.GetCommand()) + } // GetRootCommand returns the root cobra.Command for the application. diff --git a/internal/app/wwctl/vnfs/build/main.go b/internal/app/wwctl/vnfs/build/main.go index e33a51bb..92590ae8 100644 --- a/internal/app/wwctl/vnfs/build/main.go +++ b/internal/app/wwctl/vnfs/build/main.go @@ -2,7 +2,7 @@ package build import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/assets" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/vnfs" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/spf13/cobra" @@ -10,12 +10,18 @@ import ( ) func CobraRunE(cmd *cobra.Command, args []string) error { - var nodes []assets.NodeInfo + var nodes []node.NodeInfo set := make(map[string]int) + n, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + if len(args) == 1 && ByNode == true { var err error - nodes, err = assets.SearchByName(args[0]) + nodes, err = n.SearchByName(args[0]) if err != nil { wwlog.Printf(wwlog.ERROR, "Could not find nodes for search term: %s\n", args[0]) os.Exit(1) @@ -27,7 +33,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } else if BuildAll == true { var err error - nodes, err = assets.FindAllNodes() + nodes, err = n.FindAllNodes() if err != nil { wwlog.Printf(wwlog.ERROR, "Could not get list of nodes: %s\n", err) os.Exit(1) diff --git a/internal/app/wwctl/vnfs/list/main.go b/internal/app/wwctl/vnfs/list/main.go new file mode 100644 index 00000000..045fb2df --- /dev/null +++ b/internal/app/wwctl/vnfs/list/main.go @@ -0,0 +1,27 @@ +package list + +import ( + "fmt" + "github.com/hpcng/warewulf/internal/pkg/config" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" + "io/ioutil" + "os" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + config := config.New() + + files, err := ioutil.ReadDir(config.VnfsImageParentDir()) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + for _, f := range files { + fmt.Println(f.Name()) + } + + fmt.Printf("VNFS LIST: work in progress: %s\n", config.VnfsImageParentDir()) + return nil +} \ No newline at end of file diff --git a/internal/app/wwctl/vnfs/list/root.go b/internal/app/wwctl/vnfs/list/root.go new file mode 100644 index 00000000..42ce77dc --- /dev/null +++ b/internal/app/wwctl/vnfs/list/root.go @@ -0,0 +1,25 @@ +package list + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + Use: "list", + Short: "List VNFS images", + Long: "List VNFS images ", + RunE: CobraRunE, + } + SystemOverlay bool + BuildAll bool +) + +func init() { + baseCmd.PersistentFlags().BoolVarP(&SystemOverlay, "system", "s", false, "Show System Overlays as well") + baseCmd.PersistentFlags().BoolVarP(&BuildAll, "all", "a", false, "Build all overlays (runtime and system)") + +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/vnfs/root.go b/internal/app/wwctl/vnfs/root.go index ab32a8d6..851d1d2b 100644 --- a/internal/app/wwctl/vnfs/root.go +++ b/internal/app/wwctl/vnfs/root.go @@ -2,6 +2,7 @@ package vnfs import ( "github.com/hpcng/warewulf/internal/app/wwctl/vnfs/build" + "github.com/hpcng/warewulf/internal/app/wwctl/vnfs/list" "github.com/spf13/cobra" ) @@ -16,7 +17,7 @@ var ( func init() { baseCmd.AddCommand(build.GetCommand()) - + baseCmd.AddCommand(list.GetCommand()) } // GetRootCommand returns the root cobra.Command for the application. diff --git a/internal/pkg/assets/assets.go b/internal/pkg/assets/assets.go deleted file mode 100644 index e027ad53..00000000 --- a/internal/pkg/assets/assets.go +++ /dev/null @@ -1,337 +0,0 @@ -package assets - -import ( - "fmt" - "github.com/hpcng/warewulf/internal/pkg/config" - "github.com/hpcng/warewulf/internal/pkg/util" - "github.com/hpcng/warewulf/internal/pkg/vnfs" - "github.com/hpcng/warewulf/internal/pkg/wwlog" - "gopkg.in/yaml.v2" - "io/ioutil" - // "os" - - // "os" - "regexp" - - "github.com/hpcng/warewulf/internal/pkg/errors" -) - -const ConfigFile = "/etc/warewulf/nodes.conf" -const LocalStateDir = "/var/warewulf" - -func init() { - //TODO: Check to make sure nodes.conf is found - -} - -type nodeYaml struct { - NodeGroups map[string]nodeGroup //`yaml:"nodegroups"` -} - -type nodeGroup struct { - Comment string - Vnfs string - Ipxe string `yaml:"ipxe template"` - SystemOverlay string `yaml:"system overlay""` - RuntimeOverlay string `yaml:"runtime overlay""` - DomainSuffix string `yaml:"domain suffix"` - KernelVersion string `yaml:"kernel version"` - KernelArgs string `yaml:"kernel args"` - Nodes map[string]nodeEntry -} - -type nodeEntry struct { - Hostname string - Vnfs string - Ipxe string `yaml:"ipxe template"` - SystemOverlay string `yaml:"system overlay"` - RuntimeOverlay string `yaml:"runtime overlay"` - DomainSuffix string `yaml:"domain suffix"` - KernelVersion string `yaml:"kernel version"` - KernelArgs string `yaml:"kernel args"` - IpmiIpaddr string `yaml:"ipmi ipaddr"` - NetDevs map[string]netDevs -} - -type netDevs struct { - Type string - Hwaddr string - Ipaddr string - Netmask string - Gateway string -} - -type NodeInfo struct { - GroupName string - HostName string - DomainName string - Fqdn string - Vnfs string - VnfsDir string - Ipxe string - SystemOverlay string - RuntimeOverlay string - KernelVersion string - KernelArgs string - IpmiIpaddr string - NetDevs map[string]netDevs -} - -func FindAllNodes() ([]NodeInfo, error) { - var c nodeYaml - var ret []NodeInfo - config := config.New() - - - wwlog.Printf(wwlog.DEBUG, "Opening configuration file: %s\n", ConfigFile) - data, err := ioutil.ReadFile(ConfigFile) - if err != nil { - fmt.Printf("error reading node configuration file\n") - return nil, err - } - - err = yaml.Unmarshal(data, &c) - if err != nil { - return nil, err - } - - for groupname, group := range c.NodeGroups { - for _, node := range group.Nodes { - var n NodeInfo - - n.GroupName = groupname - n.HostName = node.Hostname - n.IpmiIpaddr = node.IpmiIpaddr - - n.Vnfs = group.Vnfs - n.SystemOverlay = group.SystemOverlay - n.RuntimeOverlay = group.RuntimeOverlay - n.KernelVersion = group.KernelVersion - n.KernelArgs = group.KernelArgs - n.DomainName = group.DomainSuffix - n.Ipxe = group.Ipxe - n.NetDevs = node.NetDevs - - if node.KernelVersion != "" { - n.KernelVersion = node.KernelVersion - } - if node.Vnfs != "" { - n.Vnfs = node.Vnfs - } - if node.SystemOverlay != "" { - n.SystemOverlay = node.SystemOverlay - } - if node.RuntimeOverlay != "" { - n.RuntimeOverlay = node.RuntimeOverlay - } - if node.DomainSuffix != "" { - n.DomainName = node.DomainSuffix - } - if node.Ipxe != "" { - n.Ipxe = node.Ipxe - } - if node.KernelArgs != "" { - n.KernelArgs = node.KernelArgs - } - - if n.RuntimeOverlay == "" { - n.RuntimeOverlay = "default" - } - if n.SystemOverlay == "" { - n.SystemOverlay = "default" - } - if n.Ipxe == "" { - n.Ipxe = "default" - } - - if n.DomainName != "" { - n.Fqdn = node.Hostname + "." + n.DomainName - } else { - n.Fqdn = node.Hostname - } - - util.ValidateOrDie(n.Fqdn, "group name", n.GroupName, "^[a-zA-Z0-9-._]+$") - util.ValidateOrDie(n.Fqdn, "vnfs", n.Vnfs, "^[a-zA-Z0-9-._:/]+$") - util.ValidateOrDie(n.Fqdn, "system overlay", n.SystemOverlay, "^[a-zA-Z0-9-._]+$") - util.ValidateOrDie(n.Fqdn, "runtime overlay", n.RuntimeOverlay, "^[a-zA-Z0-9-._]+$") - util.ValidateOrDie(n.Fqdn, "domain suffix", n.DomainName, "^[a-zA-Z0-9-._]+$") - util.ValidateOrDie(n.Fqdn, "hostname", n.HostName, "^[a-zA-Z0-9-_]+$") - util.ValidateOrDie(n.Fqdn, "kernel version", n.KernelVersion, "^[a-zA-Z0-9-._]+$") - - v := vnfs.New(n.Vnfs) - n.VnfsDir = config.VnfsChroot(v.NameClean()) - - ret = append(ret, n) - } - } - - return ret, nil -} - - -func FindByHwaddr(hwa string) (NodeInfo, error) { - var ret NodeInfo - - nodeList, err := FindAllNodes() - if err != nil { - return ret, err - } - - for _, node := range nodeList { - for _, dev := range node.NetDevs { - if dev.Hwaddr == hwa { - return node, nil - } - } - } - - return ret, errors.New("No nodes found with HW Addr: " + hwa) -} - -func FindByIpaddr(ipaddr string) (NodeInfo, error) { - var ret NodeInfo - - nodeList, err := FindAllNodes() - if err != nil { - return ret, err - } - - for _, node := range nodeList { - for _, dev := range node.NetDevs { - if dev.Ipaddr == ipaddr { - return node, nil - } - } - } - - return ret, errors.New("No nodes found with IP Addr: " + ipaddr) -} - -func SearchByName(search string) ([]NodeInfo, error) { - var ret []NodeInfo - - nodeList, err := FindAllNodes() - if err != nil { - return ret, err - } - - for _, node := range nodeList { - b, _ := regexp.MatchString(search, node.Fqdn) - if b == true { - ret = append(ret, node) - } - } - - return ret, nil -} - -func SearchByNameList(searchList []string) ([]NodeInfo, error) { - var ret []NodeInfo - - nodeList, err := FindAllNodes() - if err != nil { - return ret, err - } - - for _, search := range searchList { - for _, node := range nodeList { - b, _ := regexp.MatchString(search, node.Fqdn) - if b == true { - ret = append(ret, node) - } - } - } - - return ret, nil -} - -/* -func FindAllVnfs() ([]string, error) { - var ret []string - set := make(map[string]bool) - - nodeList, err := FindAllNodes() - if err != nil { - return ret, err - } - - for _, node := range nodeList { - if node.Vnfs != "" { - set[node.Vnfs] = true - } - } - - for entry := range set { - ret = append(ret, entry) - } - - return ret, nil -} - -func FindAllKernels() ([]string, error) { - var ret []string - set := make(map[string]bool) - - nodeList, err := FindAllNodes() - if err != nil { - return ret, err - } - - for _, node := range nodeList { - if node.KernelVersion != "" { - set[node.KernelVersion] = true - } - } - - for entry := range set { - ret = append(ret, entry) - } - - return ret, nil -} - -func ListSystemOverlays() ([]string, error) { - var ret []string - set := make(map[string]bool) - - nodeList, err := FindAllNodes() - if err != nil { - return ret, err - } - - for _, node := range nodeList { - if node.SystemOverlay != "" { - set[node.SystemOverlay] = true - } - } - - for entry := range set { - ret = append(ret, entry) - } - - return ret, nil -} - -func ListRuntimeOverlays() ([]string, error) { - var ret []string - set := make(map[string]bool) - - nodeList, err := FindAllNodes() - if err != nil { - return ret, err - } - - for _, node := range nodeList { - if node.RuntimeOverlay != "" { - set[node.RuntimeOverlay] = true - } - } - - for entry := range set { - ret = append(ret, entry) - } - - return ret, nil -} - -*/ diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index 60276073..5c95def5 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -57,10 +57,10 @@ func init() { c.Editor = "vi" } - util.ValidateOrDie("warewulf.conf", "warewulfd ipaddr", c.Ipaddr, "^[0-9]+.[0-9]+.[0-9]+.[0-9]+$") - util.ValidateOrDie("warewulf.conf", "system config dir", c.SysConfDir, "^[a-zA-Z0-9-._:/]+$") - util.ValidateOrDie("warewulf.conf", "local state dir", c.LocalStateDir, "^[a-zA-Z0-9-._:/]+$") - util.ValidateOrDie("warewulf.conf", "default editor", c.LocalStateDir, "^[a-zA-Z0-9-._:/]+$") + util.ValidateOrDie("warewulfd ipaddr", c.Ipaddr, "^[0-9]+.[0-9]+.[0-9]+.[0-9]+$") + util.ValidateOrDie("system config dir", c.SysConfDir, "^[a-zA-Z0-9-._:/]+$") + util.ValidateOrDie("local state dir", c.LocalStateDir, "^[a-zA-Z0-9-._:/]+$") + util.ValidateOrDie("default editor", c.LocalStateDir, "^[a-zA-Z0-9-._:/]+$") } @@ -84,6 +84,14 @@ func (self *Config) RuntimeOverlayDir() string { return path.Join(self.OverlayDir(), "/runtime") } +func (self *Config) VnfsImageParentDir() string { + return fmt.Sprintf("%s/provision/vnfs/", self.LocalStateDir) +} + +func (self *Config) VnfsChrootParentDir() string { + return fmt.Sprintf("%s/chroot/", self.LocalStateDir) +} + func (self *Config) SystemOverlaySource(overlayName string) string { if overlayName == "" { wwlog.Printf(wwlog.ERROR, "System overlay name is not defined\n") @@ -141,20 +149,6 @@ func (self *Config) KmodsImage(kernelVersion string) string { return fmt.Sprintf("%s/provision/kernel/kmods-%s.img", self.LocalStateDir, kernelVersion) } -func (self *Config) VnfsImage(vnfsNameClean string) string { - if vnfsNameClean == "" { - wwlog.Printf(wwlog.ERROR, "VNFS name is not defined\n") - return "" - } - - if util.TaintCheck(vnfsNameClean, "^[a-zA-Z0-9-._:]+$") == false { - wwlog.Printf(wwlog.ERROR, "Runtime overlay name contains illegal characters: %s\n", vnfsNameClean) - return "" - } - - return fmt.Sprintf("%s/provision/vnfs/%s.img.gz", self.LocalStateDir, vnfsNameClean) -} - func (self *Config) SystemOverlayImage(nodeName string) string { if nodeName == "" { wwlog.Printf(wwlog.ERROR, "Node name is not defined\n") @@ -183,6 +177,21 @@ func (self *Config) RuntimeOverlayImage(nodeName string) string { return fmt.Sprintf("%s/provision/overlays/runtime/%s.img", self.LocalStateDir, nodeName) } + +func (self *Config) VnfsImage(vnfsNameClean string) string { + if vnfsNameClean == "" { + wwlog.Printf(wwlog.ERROR, "VNFS name is not defined\n") + return "" + } + + if util.TaintCheck(vnfsNameClean, "^[a-zA-Z0-9-._:]+$") == false { + wwlog.Printf(wwlog.ERROR, "Runtime overlay name contains illegal characters: %s\n", vnfsNameClean) + return "" + } + + return path.Join(self.VnfsImageParentDir(), vnfsNameClean) +} + func (self *Config) VnfsChroot(vnfsNameClean string) string { if vnfsNameClean == "" { wwlog.Printf(wwlog.ERROR, "VNFS name is not defined\n") @@ -194,6 +203,6 @@ func (self *Config) VnfsChroot(vnfsNameClean string) string { return "" } - return fmt.Sprintf("%s/chroot/%s.img", self.LocalStateDir, vnfsNameClean) + return path.Join(self.VnfsChrootParentDir(), vnfsNameClean) } diff --git a/internal/pkg/node/node.go b/internal/pkg/node/node.go new file mode 100644 index 00000000..4f559210 --- /dev/null +++ b/internal/pkg/node/node.go @@ -0,0 +1,530 @@ +package node + +import ( + "fmt" + "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" + "regexp" + "strings" +) + +const ConfigFile = "/etc/warewulf/nodes.conf" +const LocalStateDir = "/var/warewulf" + +func init() { + //TODO: Check to make sure nodes.conf is found + +} + +type nodeYaml struct { + NodeGroups map[string]*nodeGroup //`yaml:"nodegroups"` +} + +type nodeGroup struct { + Comment string + Vnfs string `yaml:"vnfs"` + Ipxe string `yaml:"ipxe template,omitempty"` + SystemOverlay string `yaml:"system overlay,omitempty""` + RuntimeOverlay string `yaml:"runtime overlay""` + DomainSuffix string `yaml:"domain suffix"` + KernelVersion string `yaml:"kernel version"` + KernelArgs string `yaml:"kernel args"` + IpmiUserName string `yaml:"ipmi username,omitempty"` + IpmiPassword string `yaml:"ipmi password,omitempty"` + Nodes map[string]*nodeEntry +} + +type nodeEntry struct { + Hostname string `yaml:"hostname,omitempty"` + Vnfs string `yaml:"vnfs,omitempty"` + Ipxe string `yaml:"ipxe template,omitempty"` + SystemOverlay string `yaml:"system overlay,omitempty"` + RuntimeOverlay string `yaml:"runtime overlay,omitempty"` + DomainSuffix string `yaml:"domain suffix,omitempty"` + KernelVersion string `yaml:"kernel version,omitempty"` + KernelArgs string `yaml:"kernel args,omitempty"` + IpmiIpaddr string `yaml:"ipmi ipaddr,omitempty"` + IpmiUserName string `yaml:"ipmi username,omitempty"` + IpmiPassword string `yaml:"ipmi password,omitempty"` + NetDevs map[string]*netDevs +} + +type netDevs struct { + Type string `yaml:"type,omitempty"` + Hwaddr string + Ipaddr string + Netmask string + Gateway string`yaml:"gateway,omitempty"` +} + +type NodeInfo struct { + Id string + Gid string + Uid string + GroupName string + HostName string + DomainName string + Fqdn string + Vnfs string + Ipxe string + SystemOverlay string + RuntimeOverlay string + KernelVersion string + KernelArgs string + IpmiIpaddr string + IpmiUserName string + IpmiPassword string + NetDevs map[string]*netDevs +} + +type GroupInfo struct { + Id string + GroupName string + DomainName string + Vnfs string + Ipxe string + SystemOverlay string + RuntimeOverlay string + KernelVersion string + KernelArgs string + IpmiUserName string + IpmiPassword string +} + +func New() (nodeYaml, error) { + var ret nodeYaml + + wwlog.Printf(wwlog.DEBUG, "Opening node configuration file: %s\n", ConfigFile) + data, err := ioutil.ReadFile(ConfigFile) + if err != nil { + fmt.Printf("error reading node configuration file\n") + return ret, err + } + + err = yaml.Unmarshal(data, &ret) + if err != nil { + return ret, err + } + + return ret, nil +} + +func (self *nodeYaml) AddGroup(groupID string) error { + var group nodeGroup + + if _, ok := self.NodeGroups[groupID]; ok { + return errors.New("Group name already exists: " + groupID) + } + + self.NodeGroups[groupID] = &group + self.NodeGroups[groupID].DomainSuffix = groupID + + return nil +} + +func (self *nodeYaml) AddNode(groupID string, nodeID string) error { + var node nodeEntry + + wwlog.Printf(wwlog.VERBOSE, "Adding new node: %s/%s\n", groupID, nodeID) + + if _, ok := self.NodeGroups[groupID]; ok { + if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { + return errors.New("Nodename already exists in group: " + nodeID) + } + } else { + return errors.New("Group does not exist: "+groupID) + } + + self.NodeGroups[groupID].Nodes[nodeID] = &node + self.NodeGroups[groupID].Nodes[nodeID].Hostname = nodeID + + return nil +} + +func (self *nodeYaml) DelNode(groupID string, nodeID string) error { + + if _, ok := self.NodeGroups[groupID]; ok { + if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { + delete(self.NodeGroups[groupID].Nodes, nodeID) + wwlog.Printf(wwlog.VERBOSE, "Deleting node: %s/%s\n", groupID, nodeID) + } else { + return errors.New("Node '"+nodeID+"' was not found in group '"+groupID+"'") + } + } else { + return errors.New("Group '"+groupID+"' was not found") + } + + return nil +} + +func (self *nodeYaml) DelNodeNet(groupID string, nodeID string, netDev string) error { + + if _, ok := self.NodeGroups[groupID]; ok { + if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { + if _, ok := self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev]; ok { + wwlog.Printf(wwlog.VERBOSE, "Deleting node network device: %s/%s:%s\n", groupID, nodeID, netDev) + delete(self.NodeGroups[groupID].Nodes[nodeID].NetDevs, netDev) + } else { + return errors.New("Network device '"+netDev+"' was not found in node '"+groupID+"/"+nodeID+"'") + } + } else { + return errors.New("Node '"+nodeID+"' was not found in group '"+groupID+"'") + } + } else { + return errors.New("Group '"+groupID+"' was not found") + } + + return nil +} + + +func (self *nodeYaml) DelGroup(groupname string) error { + if _, ok := self.NodeGroups[groupname]; ok { + delete(self.NodeGroups, groupname) + } else { + return errors.New("Node group undefined: " + groupname) + } + + return nil +} + +func (self *nodeYaml) SetGroupVal(groupID string, entry string, value string) error { + if strings.ToUpper(value) == "UNDEF" || strings.ToUpper(value) == "NIL" || strings.ToUpper(value) == "DEL" { + value = "" + } + + if _, ok := self.NodeGroups[groupID]; ok { + wwlog.Printf(wwlog.VERBOSE, "Setting group %s to: %s = '%s'\n", groupID, entry, value ) + + switch strings.ToUpper(entry) { + case "VNFS": + util.ValidateOrDie("VNFS", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Vnfs = value + case "KERNEL": + util.ValidateOrDie("Kernel Version", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].KernelVersion = value + case "DOMAINSUFFIX": + util.ValidateOrDie("Domain", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].DomainSuffix = value + case "IPXE": + util.ValidateOrDie("iPXE Template", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Ipxe = value + case "SYSTEMOVERLAY": + util.ValidateOrDie("System Overlay", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].SystemOverlay = value + case "RUNTIMEOVERLAY": + util.ValidateOrDie("Runtime Overlay", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].RuntimeOverlay = value + case "IPMIUSERNAME": + util.ValidateOrDie("IPMI Username", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].IpmiUserName = value + case "IPMIPASSWORD": + util.ValidateOrDie("IPMI Password", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].IpmiPassword = value + + } + } else { + return errors.New("Group does not exist: " +groupID) + } + + return nil +} + +func (self *nodeYaml) SetNodeVal(groupID string, nodeID string, entry string, value string) error { + if strings.ToUpper(value) == "UNDEF" || strings.ToUpper(value) == "NIL" || strings.ToUpper(value) == "DEL" { + value = "" + } + if _, ok := self.NodeGroups[groupID]; ok { + if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { + wwlog.Printf(wwlog.VERBOSE, "Setting node %s/%s to: %s = '%s'\n", groupID, nodeID, entry, value ) + + switch strings.ToUpper(entry) { + case "VNFS": + util.ValidateOrDie("VNFS", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Nodes[nodeID].Vnfs = value + case "KERNEL": + util.ValidateOrDie("Kernel Version", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Nodes[nodeID].KernelVersion = value + case "DOMAINSUFFIX": + util.ValidateOrDie("Domain", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Nodes[nodeID].DomainSuffix = value + case "IPXE": + util.ValidateOrDie("iPXE Template", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Nodes[nodeID].Ipxe = value + case "SYSTEMOVERLAY": + util.ValidateOrDie("System Overlay", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Nodes[nodeID].SystemOverlay = value + case "RUNTIMEOVERLAY": + util.ValidateOrDie("Runtime Overlay", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Nodes[nodeID].RuntimeOverlay = value + case "HOSTNAME": + util.ValidateOrDie("Hostname", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Nodes[nodeID].Hostname = value + case "IPMIIPADDR": + util.ValidateOrDie("IPMI IP Address", entry, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") + self.NodeGroups[groupID].Nodes[nodeID].IpmiIpaddr = value + case "IPMIUSERNAME": + util.ValidateOrDie("IPMI Username", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Nodes[nodeID].IpmiUserName = value + case "IPMIPASSWORD": + util.ValidateOrDie("IPMI Password", entry, "^[a-zA-Z0-9-._]*$") + self.NodeGroups[groupID].Nodes[nodeID].IpmiPassword = value + + } + } else { + return errors.New("Node does not exist: " +groupID+ "/" +nodeID) + } + } else { + return errors.New("Group does not exist: " +groupID) + } + + return nil +} + +func (self *nodeYaml) SetNodeNet(groupID string, nodeID string, netDev string, entry string, value string) error { + if strings.ToUpper(value) == "UNDEF" || strings.ToUpper(value) == "NIL" || strings.ToUpper(value) == "DEL" { + value = "" + } + + if _, ok := self.NodeGroups[groupID]; ok { + if _, ok := self.NodeGroups[groupID].Nodes[nodeID]; ok { + if _, ok := self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev]; ok { + wwlog.Printf(wwlog.VERBOSE, "Editing existing node NetDev entry for node: %s/%s\n", groupID, nodeID) + } else { + var nd netDevs + self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev] = &nd + } + } else { + return errors.New("Node does not exist: "+groupID+"/"+nodeID) + } + } else { + return errors.New("Group does not exist: "+groupID) + } + + switch strings.ToUpper(entry) { + case "IPADDR": + util.ValidateOrDie("IP address", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") + self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Ipaddr = value + case "NETMASK": + util.ValidateOrDie("Netmask", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") + self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Netmask = value + case "GATEWAY": + util.ValidateOrDie("Gateway", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") + self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Gateway = value + case "TYPE": + util.ValidateOrDie("Network device type", value, "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$") + self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Type = value + case "HWADDR": + util.ValidateOrDie("HW address", value, "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$") + self.NodeGroups[groupID].Nodes[nodeID].NetDevs[netDev].Hwaddr = value + + } + + return nil +} + +func (self *nodeYaml) Persist() error { + + out, err := yaml.Marshal(self) + if err != nil { + return err + } + + file, err := os.OpenFile(ConfigFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + defer file.Close() + + _, err = file.WriteString(string(out)) + if err != nil { + return err + } + + return nil +} + + +func (self *nodeYaml) FindAllGroups() ([]GroupInfo, error) { + var ret []GroupInfo + + for groupname, group := range self.NodeGroups { + var g GroupInfo + + g.Id = groupname + g.GroupName = groupname + g.RuntimeOverlay = group.RuntimeOverlay + g.SystemOverlay = group.SystemOverlay + g.Ipxe = group.Ipxe + g.KernelVersion = group.KernelVersion + g.KernelArgs = group.KernelArgs + g.Vnfs = group.Vnfs + g.IpmiUserName = group.IpmiUserName + g.IpmiPassword = group.IpmiPassword + g.DomainName = group.DomainSuffix + + // TODO: Validate or die on all inputs + + ret = append(ret, g) + } + return ret, nil +} + + +func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) { + var ret []NodeInfo + + for groupname, group := range self.NodeGroups { + for nodename, node := range group.Nodes { + var n NodeInfo + + n.Id = nodename + n.Gid = groupname +// n.Uid = groupname + ":" + nodename + n.GroupName = groupname + n.HostName = node.Hostname + n.IpmiIpaddr = node.IpmiIpaddr + + n.Vnfs = group.Vnfs + n.SystemOverlay = group.SystemOverlay + n.RuntimeOverlay = group.RuntimeOverlay + n.KernelVersion = group.KernelVersion + n.KernelArgs = group.KernelArgs + n.DomainName = group.DomainSuffix + n.Ipxe = group.Ipxe + n.IpmiUserName = group.IpmiUserName + n.IpmiPassword = group.IpmiPassword + + n.NetDevs = node.NetDevs + + if node.IpmiUserName != "" { + n.IpmiUserName = node.IpmiUserName + } + if node.IpmiPassword != "" { + n.IpmiPassword = node.IpmiPassword + } + if node.KernelVersion != "" { + n.KernelVersion = node.KernelVersion + } + if node.Vnfs != "" { + n.Vnfs = node.Vnfs + } + if node.SystemOverlay != "" { + n.SystemOverlay = node.SystemOverlay + } + if node.RuntimeOverlay != "" { + n.RuntimeOverlay = node.RuntimeOverlay + } + if node.DomainSuffix != "" { + n.DomainName = node.DomainSuffix + } + if node.Ipxe != "" { + n.Ipxe = node.Ipxe + } + if node.KernelArgs != "" { + n.KernelArgs = node.KernelArgs + } + + if n.RuntimeOverlay == "" { + n.RuntimeOverlay = "default" + } + if n.SystemOverlay == "" { + n.SystemOverlay = "default" + } + if n.Ipxe == "" { + n.Ipxe = "default" + } + if n.HostName == "" { + n.HostName = nodename + } + + if n.DomainName != "" { + n.Fqdn = node.Hostname + "." + n.DomainName + } else { + n.Fqdn = node.Hostname + } + + util.ValidateOrDie(n.Fqdn +":group name", n.GroupName, "^[a-zA-Z0-9-._]*$") + util.ValidateOrDie(n.Fqdn +":vnfs", n.Vnfs, "^[a-zA-Z0-9-._:/]*$") + util.ValidateOrDie(n.Fqdn +":system overlay", n.SystemOverlay, "^[a-zA-Z0-9-._]*$") + util.ValidateOrDie(n.Fqdn +":runtime overlay", n.RuntimeOverlay, "^[a-zA-Z0-9-._]*$") + util.ValidateOrDie(n.Fqdn +":domain suffix", n.DomainName, "^[a-zA-Z0-9-._]*$") + util.ValidateOrDie(n.Fqdn +":hostname", n.HostName, "^[a-zA-Z0-9-_]*$") + util.ValidateOrDie(n.Fqdn +":kernel version", n.KernelVersion, "^[a-zA-Z0-9-._]*$") + + ret = append(ret, n) + } + } + + return ret, nil +} + +func (nodes *nodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) { + var ret NodeInfo + + n, _ := nodes.FindAllNodes() + + for _, node := range n { + for _, dev := range node.NetDevs { + if dev.Hwaddr == hwa { + return node, nil + } + } + } + + return ret, errors.New("No nodes found with HW Addr: " + hwa) +} + +func (nodes *nodeYaml) FindByIpaddr(ipaddr string) (NodeInfo, error) { + var ret NodeInfo + + n, _ := nodes.FindAllNodes() + + for _, node := range n { + for _, dev := range node.NetDevs { + if dev.Ipaddr == ipaddr { + return node, nil + } + } + } + + return ret, errors.New("No nodes found with IP Addr: " + ipaddr) +} + +func (nodes *nodeYaml) SearchByName(search string) ([]NodeInfo, error) { + var ret []NodeInfo + + n, _ := nodes.FindAllNodes() + + for _, node := range n { + b, _ := regexp.MatchString(search, node.Fqdn) + if b == true { + ret = append(ret, node) + } + } + + return ret, nil +} + +func (nodes *nodeYaml) SearchByNameList(searchList []string) ([]NodeInfo, error) { + var ret []NodeInfo + + n, _ := nodes.FindAllNodes() + + for _, search := range searchList { + for _, node := range n { + b, _ := regexp.MatchString(search, node.Fqdn) + if b == true { + ret = append(ret, node) + } + } + } + + return ret, nil +} diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index 409842c5..3e5a9721 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -3,14 +3,13 @@ package overlay import ( "github.com/hpcng/warewulf/internal/pkg/config" "github.com/hpcng/warewulf/internal/pkg/util" - "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/hpcng/warewulf/internal/pkg/vnfs" + "github.com/hpcng/warewulf/internal/pkg/wwlog" "io/ioutil" "path" "strings" ) - func templateFileInclude(path string) string { wwlog.Printf(wwlog.DEBUG, "Including file into template: %s\n", path) content, err := ioutil.ReadFile(path) diff --git a/internal/pkg/overlay/runtime.go b/internal/pkg/overlay/runtime.go index cc7192fb..e95cdbdd 100644 --- a/internal/pkg/overlay/runtime.go +++ b/internal/pkg/overlay/runtime.go @@ -2,10 +2,11 @@ package overlay import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/assets" "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/vnfs" "github.com/hpcng/warewulf/internal/pkg/wwlog" "io/ioutil" "os" @@ -53,7 +54,7 @@ func RuntimeOverlayInit(name string) error { } -func RuntimeBuild(nodeList []assets.NodeInfo, force bool) error { +func RuntimeBuild(nodeList []node.NodeInfo, force bool) error { config := config.New() wwlog.SetIndent(4) @@ -62,6 +63,9 @@ func RuntimeBuild(nodeList []assets.NodeInfo, force bool) error { if node.RuntimeOverlay != "" { OverlayDir := config.RuntimeOverlaySource(node.RuntimeOverlay) OverlayFile := config.RuntimeOverlayImage(node.Fqdn) + vnfs := vnfs.New(node.Vnfs) + + vnfsDir := config.VnfsChroot(vnfs.NameClean()) wwlog.Printf(wwlog.VERBOSE, "Building Runtime Overlay for: %s\n", node.Fqdn) @@ -71,11 +75,11 @@ func RuntimeBuild(nodeList []assets.NodeInfo, force bool) error { } if util.IsDir(OverlayDir) == false { - wwlog.Printf(wwlog.WARN, "%-35s: Skipped (unknown runtime overlay)\n", node.Fqdn) + wwlog.Printf(wwlog.WARN, "%-35s: Skipped (runtime overlay template not found)\n", node.Fqdn) continue } - if util.IsDir(node.VnfsDir) == false { + if util.IsDir(vnfsDir) == false { wwlog.Printf(wwlog.WARN, "%-35s: Skipped (VNFS not imported)\n", node.Fqdn) continue } diff --git a/internal/pkg/overlay/system.go b/internal/pkg/overlay/system.go index 88c529b3..89453e62 100644 --- a/internal/pkg/overlay/system.go +++ b/internal/pkg/overlay/system.go @@ -2,10 +2,11 @@ package overlay import ( "fmt" - "github.com/hpcng/warewulf/internal/pkg/assets" "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/vnfs" "github.com/hpcng/warewulf/internal/pkg/wwlog" "io/ioutil" "os" @@ -53,7 +54,7 @@ func SystemOverlayInit(name string) error { } -func SystemBuild(nodeList []assets.NodeInfo, force bool) error { +func SystemBuild(nodeList []node.NodeInfo, force bool) error { config := config.New() wwlog.SetIndent(4) @@ -62,6 +63,9 @@ func SystemBuild(nodeList []assets.NodeInfo, force bool) error { if node.SystemOverlay != "" { OverlayDir := config.SystemOverlaySource(node.SystemOverlay) OverlayFile := config.SystemOverlayImage(node.Fqdn) + vnfs := vnfs.New(node.Vnfs) + + vnfsDir := config.VnfsChroot(vnfs.NameClean()) wwlog.Printf(wwlog.VERBOSE, "Building System Overlay for: %s\n", node.Fqdn) @@ -71,11 +75,11 @@ func SystemBuild(nodeList []assets.NodeInfo, force bool) error { } if util.IsDir(OverlayDir) == false { - wwlog.Printf(wwlog.WARN, "%-35s: Skipped (unknown system overlay)\n", node.Fqdn) + wwlog.Printf(wwlog.WARN, "%-35s: Skipped (system overlay template not found)\n", node.Fqdn) continue } - if util.IsDir(node.VnfsDir) == false { + if util.IsDir(vnfsDir) == false { wwlog.Printf(wwlog.WARN, "%-35s: Skipped (VNFS not imported)\n", node.Fqdn) continue } diff --git a/internal/pkg/util/util.go b/internal/pkg/util/util.go index aaa030cd..e7889073 100644 --- a/internal/pkg/util/util.go +++ b/internal/pkg/util/util.go @@ -111,9 +111,9 @@ func TaintCheck(pattern string, expr string) bool { return false } -func ValidateOrDie(hostname string, name string, pattern string, expr string) { +func ValidateOrDie(message string, pattern string, expr string) { if TaintCheck(pattern, expr) == false { - wwlog.Printf(wwlog.ERROR, "Entry '%s:%s' contains illegal characters: '%s'\n", hostname, name, pattern) + wwlog.Printf(wwlog.ERROR, "%s does not validate: '%s'\n", message, pattern) os.Exit(1) } } @@ -181,4 +181,4 @@ func ShaSumFile(file string) (string, error) { } return fmt.Sprintf("%x", h.Sum(nil)), nil -} \ No newline at end of file +}