This commit is contained in:
Gregory Kurtzer
2021-08-20 08:11:15 -07:00
21 changed files with 208 additions and 46 deletions

View File

@@ -12,10 +12,14 @@ GO_TOOLS_VENDOR := $(addprefix vendor/, $(GO_TOOLS))
GOLANGCI_LINT := $(TOOLS_BIN)/golangci-lint
GOLANGCI_LINT_VERSION := v1.31.0
# use GOPROXY for older git clients and speed up downloads
GOPROXY ?= https://proxy.golang.org
export GOPROXY
# built tags needed for wwbuild binary
WW_BUILD_GO_BUILD_TAGS := containers_image_openpgp containers_image_ostree
all: setup_tools vendor wwctl wwclient
all: setup_tools vendor wwctl wwclient bash_completion man_page
# set the go tools into the tools bin.
setup_tools: $(GO_TOOLS_BIN) $(GOLANGCI_LINT)
@@ -53,6 +57,11 @@ files: all
install -d -m 0755 $(DESTDIR)/etc/warewulf/
install -d -m 0755 $(DESTDIR)/etc/warewulf/ipxe
install -d -m 0755 $(DESTDIR)/var/lib/tftpboot/warewulf/ipxe/
install -d -m 0755 $(DESTDIR)/etc/bash_completion.d/
install -d -m 0755 $(DESTDIR)/usr/share/man/man1
./bash_completion $(DESTDIR)/etc/bash_completion.d/warewulf
./man_page $(DESTDIR)/usr/share/man/man1
gzip $(DESTDIR)/usr/share/man/man1/wwctl*1
test -f $(DESTDIR)/etc/warewulf/warewulf.conf || install -m 644 etc/warewulf.conf $(DESTDIR)/etc/warewulf/
test -f $(DESTDIR)/etc/warewulf/hosts.tmpl || install -m 644 etc/hosts.tmpl $(DESTDIR)/etc/warewulf/
cp -r etc/dhcp $(DESTDIR)/etc/warewulf/
@@ -85,6 +94,12 @@ wwctl:
wwclient:
cd cmd/wwclient; CGO_ENABLED=0 GOOS=linux go build -mod vendor -a -ldflags '-extldflags -static' -o ../../wwclient
bash_completion:
cd cmd/bash_completion; go build -mod vendor -tags "$(WW_BUILD_GO_BUILD_TAGS)" -o ../../bash_completion
man_page:
cd cmd/man_page; go build -mod vendor -tags "$(WW_BUILD_GO_BUILD_TAGS)" -o ../../man_page
dist: vendor
rm -rf _dist/warewulf-$(VERSION)
mkdir -p _dist/warewulf-$(VERSION)
@@ -98,6 +113,8 @@ clean:
rm -f wwctl
rm -rf _dist
rm -f warewulf-$(VERSION).tar.gz
rm -f bash_completion
rm -f man_page
install: files

View File

@@ -0,0 +1,23 @@
// usage: ./bash_completion <FILE>
package main
import (
"fmt"
"os"
"github.com/hpcng/warewulf/internal/app/wwctl"
)
func main() {
fh, err := os.Create(os.Args[1])
if err != nil {
fmt.Println(err)
return
}
defer fh.Close()
if err := wwctl.GenBashCompletion(fh); err != nil {
fmt.Println(err)
return
}
}

16
cmd/man_page/man_page.go Normal file
View File

@@ -0,0 +1,16 @@
// usage: ./bash_completion <FILE>
package main
import (
"fmt"
"os"
"github.com/hpcng/warewulf/internal/app/wwctl"
)
func main() {
if err := wwctl.GenManTree(os.Args[1]); err != nil {
fmt.Println(err)
return
}
}

View File

@@ -9,3 +9,4 @@ func main() {
root.Execute()
}

View File

@@ -49,6 +49,8 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiNetmask", node.IpmiNetmask.Source(), node.IpmiNetmask.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiGateway", node.IpmiGateway.Source(), node.IpmiGateway.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiUserName", node.IpmiUserName.Source(), node.IpmiUserName.Print())
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "IpmiInterface", node.IpmiInterface.Source(), node.IpmiInterface.Print())
for name, netdev := range node.NetDevs {
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), name+":HWADDR", netdev.Hwaddr.Source(), netdev.Hwaddr.Print())
@@ -79,11 +81,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
}
} else if ShowIpmi {
fmt.Printf("%-22s %-16s %-20s %-20s\n", "NODE NAME", "IPMI IPADDR", "IPMI USERNAME", "IPMI PASSWORD")
fmt.Printf("%-22s %-16s %-20s %-20s\n", "NODE NAME", "IPMI IPADDR", "IPMI USERNAME", "IPMI PASSWORD IPMI INTERFACE")
fmt.Println(strings.Repeat("=", 80))
for _, node := range node.FilterByName(nodes, args) {
fmt.Printf("%-22s %-16s %-20s %-20s\n", node.Id.Get(), node.IpmiIpaddr.Print(), node.IpmiUserName.Print(), node.IpmiPassword.Print())
fmt.Printf("%-22s %-16s %-20s %-20s\n", node.Id.Get(), node.IpmiIpaddr.Print(), node.IpmiUserName.Print(), node.IpmiPassword.Print(), node.IpmiInterface.Print())
}
} else if ShowLong {

View File

@@ -48,12 +48,16 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
wwlog.Printf(wwlog.ERROR, "%s: No IPMI IP address\n", node.Id.Get())
continue
}
var ipmiInterface = "lan"
if node.IpmiInterface.Get() != "" {
ipmiInterface = node.IpmiInterface.Get()
}
ipmiCmd := power.IPMI{
NodeName: node.Id.Get(),
HostName: node.IpmiIpaddr.Get(),
User: node.IpmiUserName.Get(),
Password: node.IpmiPassword.Get(),
NodeName: node.Id.Get(),
HostName: node.IpmiIpaddr.Get(),
User: node.IpmiUserName.Get(),
Password: node.IpmiPassword.Get(),
Interface: ipmiInterface,
AuthType: "MD5",
}

View File

@@ -175,6 +175,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
n.IpmiPassword.Set(SetIpmiPassword)
}
if SetIpmiInterface != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI IP interface to: %s\n", n.Id.Get(), SetIpmiInterface)
n.IpmiInterface.Set(SetIpmiInterface)
}
if SetDiscoverable == true {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting node to discoverable\n", n.Id.Get())
n.Discoverable.SetB(true)

View File

@@ -31,6 +31,7 @@ var (
SetIpmiGateway string
SetIpmiUsername string
SetIpmiPassword string
SetIpmiInterface string
SetNodeAll bool
SetYes bool
SetProfile string
@@ -63,6 +64,7 @@ func init() {
baseCmd.PersistentFlags().StringVar(&SetIpmiGateway, "ipmigateway", "", "Set the node's IPMI gateway")
baseCmd.PersistentFlags().StringVar(&SetIpmiUsername, "ipmiuser", "", "Set the node's IPMI username")
baseCmd.PersistentFlags().StringVar(&SetIpmiPassword, "ipmipass", "", "Set the node's IPMI password")
baseCmd.PersistentFlags().StringVar(&SetIpmiInterface, "ipmiinterface", "", "Set the node's IPMI interface (defaults to lan if empty)")
baseCmd.PersistentFlags().StringSliceVar(&SetAddProfile, "addprofile", []string{}, "Add Profile(s) to node")
baseCmd.PersistentFlags().StringSliceVar(&SetDelProfile, "delprofile", []string{}, "Remove Profile(s) to node")

View File

@@ -48,12 +48,16 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
wwlog.Printf(wwlog.ERROR, "%s: No IPMI IP address\n", node.Id.Get())
continue
}
var ipmiInterface = "lan"
if node.IpmiInterface.Get() != "" {
ipmiInterface = node.IpmiInterface.Get()
}
ipmiCmd := power.IPMI{
NodeName: node.Id.Get(),
HostName: node.IpmiIpaddr.Get(),
User: node.IpmiUserName.Get(),
Password: node.IpmiPassword.Get(),
NodeName: node.Id.Get(),
HostName: node.IpmiIpaddr.Get(),
User: node.IpmiUserName.Get(),
Password: node.IpmiPassword.Get(),
Interface: ipmiInterface,
AuthType: "MD5",
}

View File

@@ -48,12 +48,16 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
wwlog.Printf(wwlog.ERROR, "%s: No IPMI IP address\n", node.Id.Get())
continue
}
var ipmiInterface = "lan"
if node.IpmiInterface.Get() != "" {
ipmiInterface = node.IpmiInterface.Get()
}
ipmiCmd := power.IPMI{
NodeName: node.Id.Get(),
HostName: node.IpmiIpaddr.Get(),
User: node.IpmiUserName.Get(),
Password: node.IpmiPassword.Get(),
NodeName: node.Id.Get(),
HostName: node.IpmiIpaddr.Get(),
User: node.IpmiUserName.Get(),
Password: node.IpmiPassword.Get(),
Interface: ipmiInterface,
AuthType: "MD5",
}

View File

@@ -48,12 +48,16 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
wwlog.Printf(wwlog.ERROR, "%s: No IPMI IP address\n", node.Id.Get())
continue
}
var ipmiInterface = "lan"
if node.IpmiInterface.Get() != "" {
ipmiInterface = node.IpmiInterface.Get()
}
ipmiCmd := power.IPMI{
NodeName: node.Id.Get(),
HostName: node.IpmiIpaddr.Get(),
User: node.IpmiUserName.Get(),
Password: node.IpmiPassword.Get(),
NodeName: node.Id.Get(),
HostName: node.IpmiIpaddr.Get(),
User: node.IpmiUserName.Get(),
Password: node.IpmiPassword.Get(),
Interface: ipmiInterface,
AuthType: "MD5",
}

View File

@@ -132,6 +132,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
p.IpmiPassword.Set(SetIpmiPassword)
}
if SetIpmiInterface != "" {
wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting IPMI username to: %s\n", p.Id, SetIpmiInterface)
p.IpmiInterface.Set(SetIpmiInterface)
}
if SetNetDevDel == true {
if SetNetDev == "" {
wwlog.Printf(wwlog.ERROR, "You must include the '--netdev' option\n")

View File

@@ -25,6 +25,7 @@ var (
SetIpmiGateway string
SetIpmiUsername string
SetIpmiPassword string
SetIpmiInterface string
SetNetDev string
SetIpaddr string
SetNetmask string
@@ -56,6 +57,7 @@ func init() {
baseCmd.PersistentFlags().StringVar(&SetIpmiGateway, "ipmigateway", "", "Set the node's IPMI gateway")
baseCmd.PersistentFlags().StringVar(&SetIpmiUsername, "ipmiuser", "", "Set the node's IPMI username")
baseCmd.PersistentFlags().StringVar(&SetIpmiPassword, "ipmipass", "", "Set the node's IPMI password")
baseCmd.PersistentFlags().StringVar(&SetIpmiInterface, "ipmiinterface", "", "Set the node's IPMI interface (defaults to lan if empty)")
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")

View File

@@ -1,6 +1,7 @@
package wwctl
import (
"io"
"github.com/hpcng/warewulf/internal/app/wwctl/configure"
"github.com/hpcng/warewulf/internal/app/wwctl/container"
"github.com/hpcng/warewulf/internal/app/wwctl/kernel"
@@ -12,6 +13,7 @@ import (
"github.com/hpcng/warewulf/internal/app/wwctl/server"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
"github.com/spf13/cobra/doc"
)
var (
@@ -59,3 +61,16 @@ func rootPersistentPreRunE(cmd *cobra.Command, args []string) error {
}
return nil
}
// GenBashCompletionFile
func GenBashCompletion(w io.Writer) error {
return rootCmd.GenBashCompletion(w)
}
func GenManTree(fileName string) error{
header := &doc.GenManHeader{
Title: "MINE",
Section: "1",
}
return doc.GenManTree(rootCmd,header,fileName)
}

View File

@@ -75,6 +75,7 @@ func (config *nodeYaml) FindAllNodes() ([]NodeInfo, error) {
n.IpmiGateway.Set(node.IpmiGateway)
n.IpmiUserName.Set(node.IpmiUserName)
n.IpmiPassword.Set(node.IpmiPassword)
n.IpmiInterface.Set(node.IpmiInterface)
n.SystemOverlay.Set(node.SystemOverlay)
n.RuntimeOverlay.Set(node.RuntimeOverlay)
n.Root.Set(node.Root)
@@ -123,6 +124,7 @@ func (config *nodeYaml) FindAllNodes() ([]NodeInfo, error) {
n.IpmiGateway.SetAlt(config.NodeProfiles[p].IpmiGateway, p)
n.IpmiUserName.SetAlt(config.NodeProfiles[p].IpmiUserName, p)
n.IpmiPassword.SetAlt(config.NodeProfiles[p].IpmiPassword, p)
n.IpmiInterface.SetAlt(config.NodeProfiles[p].IpmiInterface, p)
n.SystemOverlay.SetAlt(config.NodeProfiles[p].SystemOverlay, p)
n.RuntimeOverlay.SetAlt(config.NodeProfiles[p].RuntimeOverlay, p)
n.Root.SetAlt(config.NodeProfiles[p].Root, p)
@@ -190,6 +192,7 @@ func (config *nodeYaml) FindAllProfiles() ([]NodeInfo, error) {
p.IpmiGateway.Set(profile.IpmiGateway)
p.IpmiUserName.Set(profile.IpmiUserName)
p.IpmiPassword.Set(profile.IpmiPassword)
p.IpmiInterface.Set(profile.IpmiInterface)
p.RuntimeOverlay.Set(profile.RuntimeOverlay)
p.SystemOverlay.Set(profile.SystemOverlay)
p.Root.Set(profile.Root)

View File

@@ -29,6 +29,7 @@ type NodeConf struct {
IpmiIpaddr string `yaml:"ipmi ipaddr,omitempty"`
IpmiNetmask string `yaml:"ipmi netmask,omitempty"`
IpmiGateway string `yaml:"ipmi gateway,omitempty"`
IpmiInterface string `yaml:"ipmi interface,omitempty"`
RuntimeOverlay string `yaml:"runtime overlay,omitempty"`
SystemOverlay string `yaml:"system overlay,omitempty"`
Init string `yaml:"init,omitempty"`
@@ -44,6 +45,8 @@ type NetDevs struct {
Default bool `yaml:"default"`
Hwaddr string
Ipaddr string
IpCIDR string
Prefix string
Netmask string
Gateway string `yaml:"gateway,omitempty"`
}
@@ -75,6 +78,7 @@ type NodeInfo struct {
IpmiGateway Entry
IpmiUserName Entry
IpmiPassword Entry
IpmiInterface Entry
RuntimeOverlay Entry
SystemOverlay Entry
Root Entry
@@ -91,6 +95,8 @@ type NetDevEntry struct {
Default Entry `yaml:"default"`
Hwaddr Entry
Ipaddr Entry
IpCIDR Entry
Prefix Entry
Netmask Entry
Gateway Entry `yaml:"gateway,omitempty"`
}
@@ -101,7 +107,8 @@ func init() {
c, err := os.OpenFile(ConfigFile, os.O_RDWR|os.O_CREATE, 0644)
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not create new configuration file: %s\n", err)
os.Exit(1)
// just return silently, as init is also called for bash_completion
return
}
fmt.Fprintf(c, "nodeprofiles:\n")

View File

@@ -66,6 +66,7 @@ func (config *nodeYaml) NodeUpdate(node NodeInfo) error {
config.Nodes[nodeID].IpmiGateway = node.IpmiGateway.GetReal()
config.Nodes[nodeID].IpmiUserName = node.IpmiUserName.GetReal()
config.Nodes[nodeID].IpmiPassword = node.IpmiPassword.GetReal()
config.Nodes[nodeID].IpmiInterface = node.IpmiInterface.GetReal()
config.Nodes[nodeID].RuntimeOverlay = node.RuntimeOverlay.GetReal()
config.Nodes[nodeID].SystemOverlay = node.SystemOverlay.GetReal()
config.Nodes[nodeID].Root = node.Root.GetReal()
@@ -149,6 +150,7 @@ func (config *nodeYaml) ProfileUpdate(profile NodeInfo) error {
config.NodeProfiles[profileID].IpmiGateway = profile.IpmiGateway.GetReal()
config.NodeProfiles[profileID].IpmiUserName = profile.IpmiUserName.GetReal()
config.NodeProfiles[profileID].IpmiPassword = profile.IpmiPassword.GetReal()
config.NodeProfiles[profileID].IpmiInterface = profile.IpmiInterface.GetReal()
config.NodeProfiles[profileID].RuntimeOverlay = profile.RuntimeOverlay.GetReal()
config.NodeProfiles[profileID].SystemOverlay = profile.SystemOverlay.GetReal()
config.NodeProfiles[profileID].Root = profile.Root.GetReal()

View File

@@ -3,11 +3,13 @@ package overlay
import (
"fmt"
"io/ioutil"
"net"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"strconv"
"strings"
"text/template"
@@ -19,17 +21,18 @@ import (
)
type TemplateStruct struct {
Id string
Hostname string
ClusterName string
Container string
Init string
Root string
IpmiIpaddr string
IpmiNetmask string
IpmiGateway string
IpmiUserName string
IpmiPassword string
Id string
Hostname string
ClusterName string
Container string
Init string
Root string
IpmiIpaddr string
IpmiNetmask string
IpmiGateway string
IpmiUserName string
IpmiPassword string
IpmiInterface string
NetDevs map[string]*node.NetDevs
Keys map[string]string
AllNodes []node.NodeInfo
@@ -149,6 +152,7 @@ func buildOverlay(nodeList []node.NodeInfo, overlayType string) error {
t.IpmiGateway = n.IpmiGateway.Get()
t.IpmiUserName = n.IpmiUserName.Get()
t.IpmiPassword = n.IpmiPassword.Get()
t.IpmiInterface = n.IpmiInterface.Get()
t.NetDevs = make(map[string]*node.NetDevs)
t.Keys = make(map[string]string)
for devname, netdev := range n.NetDevs {
@@ -160,6 +164,13 @@ func buildOverlay(nodeList []node.NodeInfo, overlayType string) error {
t.NetDevs[devname].Gateway = netdev.Gateway.Get()
t.NetDevs[devname].Type = netdev.Type.Get()
t.NetDevs[devname].Default = netdev.Default.GetB()
mask := net.IPMask(net.ParseIP(netdev.Netmask.Get()).To4())
ipaddr := net.ParseIP(netdev.Ipaddr.Get()).To4()
netaddr := net.IPNet{IP: ipaddr,Mask: mask}
netPrefix, _ := net.IPMask(net.ParseIP(netdev.Netmask.Get()).To4()).Size()
t.NetDevs[devname].Prefix = strconv.Itoa(netPrefix)
t.NetDevs[devname].IpCIDR = netaddr.String()
}
for keyname, key := range n.Keys {
t.Keys[keyname] = key.Get()

View File

@@ -11,11 +11,12 @@ type IPMIResult struct {
}
type IPMI struct {
NodeName string
HostName string
User string
Password string
AuthType string
NodeName string
HostName string
User string
Password string
AuthType string
Interface string
result IPMIResult
}
@@ -27,9 +28,12 @@ func (ipmi *IPMI) Command(ipmiArgs []string) ([]byte, error) {
var args []string
args = append(args, "-I", "lan", "-H", ipmi.HostName, "-U", ipmi.User, "-P", ipmi.Password)
if ipmi.Interface == "" {
ipmi.Interface = "lanplus"
}
args = append(args, "-I", ipmi.Interface, "-H", ipmi.HostName, "-U", ipmi.User, "-P", ipmi.Password)
args = append(args, ipmiArgs...)
ipmiCmd := exec.Command("/usr/bin/ipmitool", args...)
ipmiCmd := exec.Command("ipmitool", args...)
return ipmiCmd.CombinedOutput()
}
@@ -37,9 +41,13 @@ func (ipmi *IPMI) InteractiveCommand(ipmiArgs []string) error {
var args []string
args = append(args, "-I", "lanplus", "-H", ipmi.HostName, "-U", ipmi.User, "-P", ipmi.Password)
if ipmi.Interface == "" {
ipmi.Interface = "lan"
}
args = append(args, "-I", ipmi.Interface, "-H", ipmi.HostName, "-U", ipmi.User, "-P", ipmi.Password)
args = append(args, ipmiArgs...)
ipmiCmd := exec.Command("/usr/bin/ipmitool", args...)
ipmiCmd := exec.Command("ipmitool", args...)
ipmiCmd.Stdout = os.Stdout
ipmiCmd.Stdin = os.Stdin
ipmiCmd.Stderr = os.Stderr

View File

@@ -1,7 +1,6 @@
package warewulfconf
import (
"os"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
@@ -52,6 +51,7 @@ func init() {
//TODO: Check to make sure nodes.conf is found
if util.IsFile(ConfigFile) == false {
wwlog.Printf(wwlog.ERROR, "Configuration file not found: %s\n", ConfigFile)
os.Exit(1)
// fail silently as this also called by bash_completion
return
}
}

View File

@@ -0,0 +1,27 @@
<interface origin="static generated warewulf config">
<name>eth0</name>
<control>
<mode>boot</mode>
</control>
<firewall/>
<link/>
<ipv4>
<enabled>true</enabled>
<arp-verify>true</arp-verify>
</ipv4>
<ipv4:static>
<address>
<local>{{$.NetDevs.eth0.IpCIDR}}</local>
</address>
<route>
<nexthop>
<gateway>{{$.NetDevs.eth0.Gateway}}</gateway>
</nexthop>
</route>
</ipv4:static>
<ipv6>
<enabled>true</enabled>
<privacy>prefer-public</privacy>
<accept-redirects>false</accept-redirects>
</ipv6>
</interface>