Merge pull request #3 from gmkurtzer/node_discovery
I've been testing this over and over, lots of good features and it is working so I'm merging. :)
This commit is contained in:
6
Makefile
6
Makefile
@@ -40,7 +40,7 @@ lint:
|
|||||||
@echo Running golangci-lint...
|
@echo Running golangci-lint...
|
||||||
@$(GOLANGCI_LINT) run --build-tags "$(WW_BUILD_GO_BUILD_TAGS)" ./...
|
@$(GOLANGCI_LINT) run --build-tags "$(WW_BUILD_GO_BUILD_TAGS)" ./...
|
||||||
|
|
||||||
all: vendor warewulfd wwctl wwclient
|
all: vendor wwctl wwclient
|
||||||
|
|
||||||
files: all
|
files: all
|
||||||
install -d -m 0755 /var/warewulf/
|
install -d -m 0755 /var/warewulf/
|
||||||
@@ -60,9 +60,6 @@ services: files
|
|||||||
# sudo systemctl enable tftp
|
# sudo systemctl enable tftp
|
||||||
# sudo systemctl restart tftp
|
# sudo systemctl restart tftp
|
||||||
|
|
||||||
warewulfd:
|
|
||||||
cd cmd/warewulfd; go build -mod vendor -tags "$(WW_BUILD_GO_BUILD_TAGS)" -o ../../warewulfd
|
|
||||||
|
|
||||||
wwctl:
|
wwctl:
|
||||||
cd cmd/wwctl; go build -mod vendor -tags "$(WW_BUILD_GO_BUILD_TAGS)" -o ../../wwctl
|
cd cmd/wwctl; go build -mod vendor -tags "$(WW_BUILD_GO_BUILD_TAGS)" -o ../../wwctl
|
||||||
|
|
||||||
@@ -70,7 +67,6 @@ wwclient:
|
|||||||
cd cmd/wwclient; CGO_ENABLED=0 GOOS=linux go build -mod vendor -a -ldflags '-extldflags -static' -o ../../wwclient
|
cd cmd/wwclient; CGO_ENABLED=0 GOOS=linux go build -mod vendor -a -ldflags '-extldflags -static' -o ../../wwclient
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f warewulfd
|
|
||||||
rm -f wwclient
|
rm -f wwclient
|
||||||
rm -f wwctl
|
rm -f wwctl
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/hpcng/warewulf/internal/app/warewulfd"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
root := warewulfd.GetRootCommand()
|
|
||||||
|
|
||||||
root.Execute()
|
|
||||||
}
|
|
||||||
12
etc/ipxe/unconfigured.ipxe
Normal file
12
etc/ipxe/unconfigured.ipxe
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#!ipxe
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo ================================================================================
|
||||||
|
echo Warewulf v4
|
||||||
|
echo
|
||||||
|
echo MESSAGE: This node is unconfigured. Please have your system administrator add a
|
||||||
|
echo configuration for this node with HW address: {{$.Hwaddr}}
|
||||||
|
echo
|
||||||
|
echo Rebooting in 1 minute...
|
||||||
|
sleep 60
|
||||||
|
reboot
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
nodeprofiles:
|
|
||||||
default:
|
|
||||||
comment: "This profile is automatically included for each node"
|
|
||||||
container name: ""
|
|
||||||
kernel version: ""
|
|
||||||
kernel args: crashkernel=no quiet
|
|
||||||
|
|
||||||
nodes: {}
|
|
||||||
1
go.mod
1
go.mod
@@ -42,6 +42,7 @@ require (
|
|||||||
github.com/prometheus/common v0.6.0 // indirect
|
github.com/prometheus/common v0.6.0 // indirect
|
||||||
github.com/prometheus/procfs v0.0.3 // indirect
|
github.com/prometheus/procfs v0.0.3 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
||||||
|
github.com/sevlyar/go-daemon v0.1.5 // indirect
|
||||||
github.com/sirupsen/logrus v1.7.0 // indirect
|
github.com/sirupsen/logrus v1.7.0 // indirect
|
||||||
github.com/spf13/cobra v1.1.1
|
github.com/spf13/cobra v1.1.1
|
||||||
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 // indirect
|
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 // indirect
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -201,6 +201,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
|
|||||||
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=
|
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/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
|
||||||
|
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||||
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
||||||
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
@@ -340,6 +342,8 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
|
|||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
|
github.com/sevlyar/go-daemon v0.1.5 h1:Zy/6jLbM8CfqJ4x4RPr7MJlSKt90f00kNM1D401C+Qk=
|
||||||
|
github.com/sevlyar/go-daemon v0.1.5/go.mod h1:6dJpPatBT9eUwM5VCw9Bt6CdX9Tk6UWvhW3MebLDRKE=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
package response
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
)
|
|
||||||
|
|
||||||
type iPxeTemplate struct {
|
|
||||||
Hostname string
|
|
||||||
Fqdn string
|
|
||||||
ContainerName string
|
|
||||||
Hwaddr string
|
|
||||||
Ipaddr string
|
|
||||||
Port string
|
|
||||||
KernelArgs string
|
|
||||||
KernelVersion string
|
|
||||||
}
|
|
||||||
|
|
||||||
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 := nodes.FindByHwaddr(hwaddr)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Could not find HW Addr: %s: %s\n", hwaddr, err)
|
|
||||||
w.WriteHeader(404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if node.Id.Defined() == true {
|
|
||||||
conf, err := warewulfconf.New()
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("IPXE: %15s: %s\n", node.Id.Get(), req.URL.Path)
|
|
||||||
|
|
||||||
// TODO: Fix template path to use config package
|
|
||||||
ipxeTemplate := fmt.Sprintf("/etc/warewulf/ipxe/%s.ipxe", node.Ipxe.Get())
|
|
||||||
|
|
||||||
tmpl, err := template.ParseFiles(ipxeTemplate)
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var replace iPxeTemplate
|
|
||||||
|
|
||||||
replace.Fqdn = node.Id.Get()
|
|
||||||
replace.Ipaddr = conf.Ipaddr
|
|
||||||
replace.Port = strconv.Itoa(conf.Warewulf.Port)
|
|
||||||
replace.Hostname = node.Id.Get()
|
|
||||||
replace.Hwaddr = url[2]
|
|
||||||
replace.ContainerName = node.ContainerName.Get()
|
|
||||||
replace.KernelArgs = node.KernelArgs.Get()
|
|
||||||
replace.KernelVersion = node.KernelVersion.Get()
|
|
||||||
|
|
||||||
err = tmpl.Execute(w, replace)
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("SEND: %15s: %s\n", node.Id.Get(), ipxeTemplate)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
log.Printf("ERROR: iPXE request from unknown Node (hwaddr=%s)\n", url[2])
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package warewulfd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
baseCmd = &cobra.Command{
|
|
||||||
Use: "warewulfd",
|
|
||||||
Short: "Warewulf Daemon Service",
|
|
||||||
Long: "This is the primary Warewulf service for provisioning nodes",
|
|
||||||
RunE: CobraRunE,
|
|
||||||
PersistentPreRunE: rootPersistentPreRunE,
|
|
||||||
}
|
|
||||||
verboseArg bool
|
|
||||||
debugArg bool
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
baseCmd.PersistentFlags().BoolVarP(&verboseArg, "verbose", "v", false, "Run with increased verbosity.")
|
|
||||||
baseCmd.PersistentFlags().BoolVarP(&debugArg, "debug", "d", false, "Run with debugging messages enabled.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRootCommand returns the root cobra.Command for the application.
|
|
||||||
func GetRootCommand() *cobra.Command {
|
|
||||||
return baseCmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func rootPersistentPreRunE(cmd *cobra.Command, args []string) error {
|
|
||||||
if verboseArg == true {
|
|
||||||
wwlog.SetLevel(wwlog.VERBOSE)
|
|
||||||
} else if debugArg == true {
|
|
||||||
wwlog.SetLevel(wwlog.DEBUG)
|
|
||||||
} else {
|
|
||||||
wwlog.SetLevel(wwlog.INFO)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package warewulfd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/hpcng/warewulf/internal/app/warewulfd/response"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO: https://github.com/danderson/netboot/blob/master/pixiecore/dhcp.go
|
|
||||||
// TODO: https://github.com/pin/tftp
|
|
||||||
|
|
||||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
|
||||||
|
|
||||||
http.HandleFunc("/ipxe/", response.IpxeSend)
|
|
||||||
http.HandleFunc("/kernel/", response.KernelSend)
|
|
||||||
http.HandleFunc("/kmods/", response.KmodsSend)
|
|
||||||
http.HandleFunc("/container/", response.ContainerSend)
|
|
||||||
http.HandleFunc("/overlay-system/", response.SystemOverlaySend)
|
|
||||||
http.HandleFunc("/overlay-runtime", response.RuntimeOverlaySend)
|
|
||||||
|
|
||||||
http.ListenAndServe(":9873", nil)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
package service
|
package configure
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hpcng/warewulf/internal/app/wwctl/service/dhcp"
|
"github.com/hpcng/warewulf/internal/app/wwctl/configure/dhcp"
|
||||||
"github.com/hpcng/warewulf/internal/app/wwctl/service/tftp"
|
"github.com/hpcng/warewulf/internal/app/wwctl/configure/tftp"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
baseCmd = &cobra.Command{
|
baseCmd = &cobra.Command{
|
||||||
Use: "service",
|
Use: "configure",
|
||||||
Short: "Initialize Warewulf services",
|
Short: "Configure Warewulf services",
|
||||||
Long: "Warewulf Service Initialization",
|
Long: "Warewulf Service Initialization",
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,13 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
container.Build(c, BuildForce)
|
output, err := container.Build(c, BuildForce)
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "Could not build container %s: %s\n", c, err)
|
||||||
|
os.Exit(1)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%-20s: %s\n", c, output)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if SetDefault == true {
|
if SetDefault == true {
|
||||||
|
|||||||
44
internal/app/wwctl/container/delete/main.go
Normal file
44
internal/app/wwctl/container/delete/main.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package delete
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/container"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
|
nodeDB, err := node.New()
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "Could not open nodeDB: %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes, _ := nodeDB.FindAllNodes()
|
||||||
|
|
||||||
|
ARG_LOOP:
|
||||||
|
for _, arg := range args {
|
||||||
|
for _, n := range nodes {
|
||||||
|
if n.ContainerName.Get() == arg {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "Container is configured for nodes, skipping: %s\n", arg)
|
||||||
|
continue ARG_LOOP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if container.ValidSource(arg) == false {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "Container name is not a valid source: %s\n", arg)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err := container.DeleteSource(arg)
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "Could not remove source: %s\n", arg)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Container has been deleted: %s\n", arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
25
internal/app/wwctl/container/delete/root.go
Normal file
25
internal/app/wwctl/container/delete/root.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package delete
|
||||||
|
|
||||||
|
import "github.com/spf13/cobra"
|
||||||
|
|
||||||
|
var (
|
||||||
|
baseCmd = &cobra.Command{
|
||||||
|
Use: "delete",
|
||||||
|
Short: "Delete Source OCI VNFS images",
|
||||||
|
Long: "Delete Source OCI VNFS images ",
|
||||||
|
RunE: CobraRunE,
|
||||||
|
Args: cobra.MinimumNArgs(1),
|
||||||
|
}
|
||||||
|
SetForce bool
|
||||||
|
SetUpdate bool
|
||||||
|
SetBuild bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRootCommand returns the root cobra.Command for the application.
|
||||||
|
func GetCommand() *cobra.Command {
|
||||||
|
return baseCmd
|
||||||
|
}
|
||||||
@@ -4,10 +4,11 @@ import "github.com/spf13/cobra"
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
baseCmd = &cobra.Command{
|
baseCmd = &cobra.Command{
|
||||||
Use: "__child",
|
Use: "__child",
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
Args: cobra.MinimumNArgs(1),
|
Args: cobra.MinimumNArgs(1),
|
||||||
|
FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -36,5 +36,14 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Rebuilding container...\n")
|
||||||
|
output, err := container.Build(containerName, false)
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "Could not build container %s: %s\n", containerName, err)
|
||||||
|
os.Exit(1)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s\n", output)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,12 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
baseCmd = &cobra.Command{
|
baseCmd = &cobra.Command{
|
||||||
Use: "exec",
|
Use: "exec",
|
||||||
Short: "Spawn any command inside a Warewulf container",
|
Short: "Spawn any command inside a Warewulf container",
|
||||||
Long: "Run a command inside a Warewulf container ",
|
Long: "Run a command inside a Warewulf container ",
|
||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
Args: cobra.MinimumNArgs(1),
|
Args: cobra.MinimumNArgs(1),
|
||||||
|
FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
nconfig, _ := node.New()
|
nodeDB, _ := node.New()
|
||||||
nodes, _ := nconfig.FindAllNodes()
|
nodes, _ := nodeDB.FindAllNodes()
|
||||||
nodemap := make(map[string]int)
|
nodemap := make(map[string]int)
|
||||||
|
|
||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package pull
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/container"
|
"github.com/hpcng/warewulf/internal/pkg/container"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -50,9 +51,35 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if SetBuild == true {
|
fmt.Printf("Building container: %s\n", name)
|
||||||
fmt.Printf("Building container: %s\n", name)
|
output, err := container.Build(name, true)
|
||||||
container.Build(name, false)
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "Could not build container %s: %s\n", name, err)
|
||||||
|
os.Exit(1)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s: %s\n", name, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
if SetDefault == true {
|
||||||
|
nodeDB, err := node.New()
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Don't loop through profiles, instead have a nodeDB function that goes directly to the map
|
||||||
|
profiles, _ := nodeDB.FindAllProfiles()
|
||||||
|
for _, profile := range profiles {
|
||||||
|
wwlog.Printf(wwlog.DEBUG, "Looking for profile default: %s\n", profile.Id.Get())
|
||||||
|
if profile.Id.Get() == "default" {
|
||||||
|
wwlog.Printf(wwlog.DEBUG, "Found profile default, setting container name to: %s\n", name)
|
||||||
|
profile.ContainerName.Set(name)
|
||||||
|
nodeDB.ProfileUpdate(profile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nodeDB.Persist()
|
||||||
|
fmt.Printf("Set default profile to container: %s\n", name)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -10,15 +10,17 @@ var (
|
|||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
Args: cobra.MinimumNArgs(1),
|
Args: cobra.MinimumNArgs(1),
|
||||||
}
|
}
|
||||||
SetForce bool
|
SetForce bool
|
||||||
SetUpdate bool
|
SetUpdate bool
|
||||||
SetBuild bool
|
SetBuild bool
|
||||||
|
SetDefault bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
baseCmd.PersistentFlags().BoolVarP(&SetForce, "force", "f", false, "Force overwrite of an existing container")
|
baseCmd.PersistentFlags().BoolVarP(&SetForce, "force", "f", false, "Force overwrite of an existing container")
|
||||||
baseCmd.PersistentFlags().BoolVarP(&SetUpdate, "update", "u", false, "Update and overwrite an existing container")
|
baseCmd.PersistentFlags().BoolVarP(&SetUpdate, "update", "u", false, "Update and overwrite an existing container")
|
||||||
baseCmd.PersistentFlags().BoolVarP(&SetBuild, "build", "b", false, "Build container when after pulling")
|
baseCmd.PersistentFlags().BoolVarP(&SetBuild, "build", "b", false, "Build container when after pulling")
|
||||||
|
baseCmd.PersistentFlags().BoolVar(&SetDefault, "setdefault", false, "Set this container for the default profile")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package container
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hpcng/warewulf/internal/app/wwctl/container/build"
|
"github.com/hpcng/warewulf/internal/app/wwctl/container/build"
|
||||||
|
"github.com/hpcng/warewulf/internal/app/wwctl/container/delete"
|
||||||
"github.com/hpcng/warewulf/internal/app/wwctl/container/exec"
|
"github.com/hpcng/warewulf/internal/app/wwctl/container/exec"
|
||||||
"github.com/hpcng/warewulf/internal/app/wwctl/container/list"
|
"github.com/hpcng/warewulf/internal/app/wwctl/container/list"
|
||||||
"github.com/hpcng/warewulf/internal/app/wwctl/container/pull"
|
"github.com/hpcng/warewulf/internal/app/wwctl/container/pull"
|
||||||
@@ -22,7 +23,7 @@ func init() {
|
|||||||
baseCmd.AddCommand(list.GetCommand())
|
baseCmd.AddCommand(list.GetCommand())
|
||||||
baseCmd.AddCommand(pull.GetCommand())
|
baseCmd.AddCommand(pull.GetCommand())
|
||||||
baseCmd.AddCommand(exec.GetCommand())
|
baseCmd.AddCommand(exec.GetCommand())
|
||||||
|
baseCmd.AddCommand(delete.GetCommand())
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootCommand returns the root cobra.Command for the application.
|
// GetRootCommand returns the root cobra.Command for the application.
|
||||||
|
|||||||
@@ -12,10 +12,12 @@ import (
|
|||||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
err := kernel.Build(arg)
|
output, err := kernel.Build(arg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
wwlog.Printf(wwlog.ERROR, "Failed building kernel: %s\n", err)
|
wwlog.Printf(wwlog.ERROR, "Failed building kernel: %s\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s: %s\n", arg, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,17 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if SetDiscoverable == true {
|
||||||
|
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting node to discoverable\n", n.Id.Get())
|
||||||
|
|
||||||
|
n.Discoverable.SetB(true)
|
||||||
|
err := nodeDB.NodeUpdate(n)
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeDB.Persist()
|
nodeDB.Persist()
|
||||||
|
|||||||
@@ -10,13 +10,14 @@ var (
|
|||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
Args: cobra.MinimumNArgs(1),
|
Args: cobra.MinimumNArgs(1),
|
||||||
}
|
}
|
||||||
SetGroup string
|
SetGroup string
|
||||||
SetController string
|
SetController string
|
||||||
SetNetDev string
|
SetNetDev string
|
||||||
SetIpaddr string
|
SetIpaddr string
|
||||||
SetNetmask string
|
SetNetmask string
|
||||||
SetGateway string
|
SetGateway string
|
||||||
SetHwaddr string
|
SetHwaddr string
|
||||||
|
SetDiscoverable bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -27,6 +28,7 @@ func init() {
|
|||||||
baseCmd.PersistentFlags().StringVarP(&SetNetmask, "netmask", "M", "", "Set the node's network device netmask")
|
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(&SetGateway, "gateway", "G", "", "Set the node's network device gateway")
|
||||||
baseCmd.PersistentFlags().StringVarP(&SetHwaddr, "hwaddr", "H", "", "Set the node's network device HW address")
|
baseCmd.PersistentFlags().StringVarP(&SetHwaddr, "hwaddr", "H", "", "Set the node's network device HW address")
|
||||||
|
baseCmd.PersistentFlags().BoolVar(&SetDiscoverable, "discoverable", false, "Make this node discoverable")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
|||||||
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "ClusterName", node.ClusterName.Source(), node.ClusterName.Print())
|
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "ClusterName", node.ClusterName.Source(), node.ClusterName.Print())
|
||||||
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "Profiles", "--", strings.Join(node.Profiles, ","))
|
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "Profiles", "--", strings.Join(node.Profiles, ","))
|
||||||
|
|
||||||
|
fmt.Printf("%-20s %-18s %-12s %t\n", node.Id.Get(), "Disabled", node.Disabled.Source(), node.Disabled.PrintB())
|
||||||
|
fmt.Printf("%-20s %-18s %-12s %t\n", node.Id.Get(), "Discoverable", node.Discoverable.Source(), node.Discoverable.PrintB())
|
||||||
|
|
||||||
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "ContainerName", node.ContainerName.Source(), node.ContainerName.Print())
|
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "ContainerName", node.ContainerName.Source(), node.ContainerName.Print())
|
||||||
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "KernelVersion", node.KernelVersion.Source(), node.KernelVersion.Print())
|
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "KernelVersion", node.KernelVersion.Source(), node.KernelVersion.Print())
|
||||||
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "KernelArgs", node.KernelArgs.Source(), node.KernelArgs.Print())
|
fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), "KernelArgs", node.KernelArgs.Source(), node.KernelArgs.Print())
|
||||||
|
|||||||
@@ -185,6 +185,27 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if SetDiscoverable == true {
|
||||||
|
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting node to discoverable\n", n.Id.Get())
|
||||||
|
|
||||||
|
n.Discoverable.SetB(true)
|
||||||
|
err := nodeDB.NodeUpdate(n)
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if SetUndiscoverable == true {
|
||||||
|
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting node to undiscoverable\n", n.Id.Get())
|
||||||
|
|
||||||
|
n.Discoverable.SetB(false)
|
||||||
|
err := nodeDB.NodeUpdate(n)
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(SetAddProfile) > 0 {
|
if len(SetAddProfile) > 0 {
|
||||||
for _, p := range SetAddProfile {
|
for _, p := range SetAddProfile {
|
||||||
wwlog.Printf(wwlog.VERBOSE, "Node: %s, adding profile to '%s'\n", n.Id.Get(), p)
|
wwlog.Printf(wwlog.VERBOSE, "Node: %s, adding profile to '%s'\n", n.Id.Get(), p)
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ var (
|
|||||||
SetDelProfile []string
|
SetDelProfile []string
|
||||||
SetForce bool
|
SetForce bool
|
||||||
SetInit string
|
SetInit string
|
||||||
|
SetDiscoverable bool
|
||||||
|
SetUndiscoverable bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -61,6 +63,8 @@ func init() {
|
|||||||
|
|
||||||
baseCmd.PersistentFlags().BoolVarP(&SetYes, "yes", "y", false, "Set 'yes' to all questions asked")
|
baseCmd.PersistentFlags().BoolVarP(&SetYes, "yes", "y", false, "Set 'yes' to all questions asked")
|
||||||
baseCmd.PersistentFlags().BoolVarP(&SetForce, "force", "f", false, "Force configuration (even on error)")
|
baseCmd.PersistentFlags().BoolVarP(&SetForce, "force", "f", false, "Force configuration (even on error)")
|
||||||
|
baseCmd.PersistentFlags().BoolVar(&SetDiscoverable, "discoverable", false, "Make this node discoverable")
|
||||||
|
baseCmd.PersistentFlags().BoolVar(&SetUndiscoverable, "undiscoverable", false, "Remove the discoverable flag")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package wwctl
|
package wwctl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/hpcng/warewulf/internal/app/wwctl/configure"
|
||||||
"github.com/hpcng/warewulf/internal/app/wwctl/container"
|
"github.com/hpcng/warewulf/internal/app/wwctl/container"
|
||||||
"github.com/hpcng/warewulf/internal/app/wwctl/kernel"
|
"github.com/hpcng/warewulf/internal/app/wwctl/kernel"
|
||||||
"github.com/hpcng/warewulf/internal/app/wwctl/node"
|
"github.com/hpcng/warewulf/internal/app/wwctl/node"
|
||||||
"github.com/hpcng/warewulf/internal/app/wwctl/overlay"
|
"github.com/hpcng/warewulf/internal/app/wwctl/overlay"
|
||||||
"github.com/hpcng/warewulf/internal/app/wwctl/profile"
|
"github.com/hpcng/warewulf/internal/app/wwctl/profile"
|
||||||
"github.com/hpcng/warewulf/internal/app/wwctl/ready"
|
"github.com/hpcng/warewulf/internal/app/wwctl/ready"
|
||||||
"github.com/hpcng/warewulf/internal/app/wwctl/service"
|
"github.com/hpcng/warewulf/internal/app/wwctl/server"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -37,8 +38,9 @@ func init() {
|
|||||||
rootCmd.AddCommand(kernel.GetCommand())
|
rootCmd.AddCommand(kernel.GetCommand())
|
||||||
// rootCmd.AddCommand(group.GetCommand())
|
// rootCmd.AddCommand(group.GetCommand())
|
||||||
rootCmd.AddCommand(profile.GetCommand())
|
rootCmd.AddCommand(profile.GetCommand())
|
||||||
rootCmd.AddCommand(service.GetCommand())
|
rootCmd.AddCommand(configure.GetCommand())
|
||||||
rootCmd.AddCommand(ready.GetCommand())
|
rootCmd.AddCommand(ready.GetCommand())
|
||||||
|
rootCmd.AddCommand(server.GetCommand())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
29
internal/app/wwctl/server/root.go
Normal file
29
internal/app/wwctl/server/root.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hpcng/warewulf/internal/app/wwctl/server/start"
|
||||||
|
"github.com/hpcng/warewulf/internal/app/wwctl/server/status"
|
||||||
|
"github.com/hpcng/warewulf/internal/app/wwctl/server/stop"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
baseCmd = &cobra.Command{
|
||||||
|
Use: "server",
|
||||||
|
Short: "Warewulf server process commands",
|
||||||
|
Long: "Warewulf profiles...",
|
||||||
|
}
|
||||||
|
test bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
baseCmd.AddCommand(start.GetCommand())
|
||||||
|
baseCmd.AddCommand(status.GetCommand())
|
||||||
|
baseCmd.AddCommand(stop.GetCommand())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRootCommand returns the root cobra.Command for the application.
|
||||||
|
func GetCommand() *cobra.Command {
|
||||||
|
return baseCmd
|
||||||
|
}
|
||||||
11
internal/app/wwctl/server/start/main.go
Normal file
11
internal/app/wwctl/server/start/main.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package start
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
|
return warewulfd.DaemonStart()
|
||||||
|
}
|
||||||
20
internal/app/wwctl/server/start/root.go
Normal file
20
internal/app/wwctl/server/start/root.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package start
|
||||||
|
|
||||||
|
import "github.com/spf13/cobra"
|
||||||
|
|
||||||
|
var (
|
||||||
|
baseCmd = &cobra.Command{
|
||||||
|
Use: "start",
|
||||||
|
Short: "Start Warewulf server",
|
||||||
|
Long: "Warewulf Server ",
|
||||||
|
RunE: CobraRunE,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRootCommand returns the root cobra.Command for the application.
|
||||||
|
func GetCommand() *cobra.Command {
|
||||||
|
return baseCmd
|
||||||
|
}
|
||||||
11
internal/app/wwctl/server/status/main.go
Normal file
11
internal/app/wwctl/server/status/main.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package status
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||||
|
warewulfd.DaemonStatus()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
20
internal/app/wwctl/server/status/root.go
Normal file
20
internal/app/wwctl/server/status/root.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package status
|
||||||
|
|
||||||
|
import "github.com/spf13/cobra"
|
||||||
|
|
||||||
|
var (
|
||||||
|
baseCmd = &cobra.Command{
|
||||||
|
Use: "status",
|
||||||
|
Short: "Warewulf server status",
|
||||||
|
Long: "Warewulf Server ",
|
||||||
|
RunE: CobraRunE,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRootCommand returns the root cobra.Command for the application.
|
||||||
|
func GetCommand() *cobra.Command {
|
||||||
|
return baseCmd
|
||||||
|
}
|
||||||
11
internal/app/wwctl/server/stop/main.go
Normal file
11
internal/app/wwctl/server/stop/main.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package stop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||||
|
warewulfd.DaemonStop()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
20
internal/app/wwctl/server/stop/root.go
Normal file
20
internal/app/wwctl/server/stop/root.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package stop
|
||||||
|
|
||||||
|
import "github.com/spf13/cobra"
|
||||||
|
|
||||||
|
var (
|
||||||
|
baseCmd = &cobra.Command{
|
||||||
|
Use: "stop",
|
||||||
|
Short: "Stop Warewulf server",
|
||||||
|
Long: "Warewulf Server ",
|
||||||
|
RunE: CobraRunE,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRootCommand returns the root cobra.Command for the application.
|
||||||
|
func GetCommand() *cobra.Command {
|
||||||
|
return baseCmd
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package container
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/errors"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
"os"
|
"os"
|
||||||
@@ -9,46 +10,40 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Build(name string, buildForce bool) {
|
func Build(name string, buildForce bool) (string, error) {
|
||||||
|
|
||||||
rootfsPath := RootFsDir(name)
|
rootfsPath := RootFsDir(name)
|
||||||
imagePath := ImageFile(name)
|
imagePath := ImageFile(name)
|
||||||
|
|
||||||
if ValidSource(name) == false {
|
if ValidSource(name) == false {
|
||||||
wwlog.Printf(wwlog.INFO, "%-35s: Skipping (bad path)\n", name)
|
return "", errors.New("Container does not exist")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if buildForce == false {
|
if buildForce == false {
|
||||||
wwlog.Printf(wwlog.DEBUG, "Checking if there have been any updates to the VNFS directory\n")
|
wwlog.Printf(wwlog.DEBUG, "Checking if there have been any updates to the VNFS directory\n")
|
||||||
if util.PathIsNewer(rootfsPath, imagePath) {
|
if util.PathIsNewer(rootfsPath, imagePath) {
|
||||||
wwlog.Printf(wwlog.INFO, "%-35s: Skipping, VNFS is current\n", name)
|
return "Skipping (VNFS is current)", nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wwlog.Printf(wwlog.DEBUG, "Making parent directory for: %s\n", name)
|
wwlog.Printf(wwlog.DEBUG, "Making parent directory for: %s\n", name)
|
||||||
err := os.MkdirAll(path.Dir(imagePath), 0755)
|
err := os.MkdirAll(path.Dir(imagePath), 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("ERROR: %s\n", err)
|
return "Failed creating directory", err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wwlog.Printf(wwlog.DEBUG, "Making parent directory for: %s\n", rootfsPath)
|
wwlog.Printf(wwlog.DEBUG, "Making parent directory for: %s\n", rootfsPath)
|
||||||
err = os.MkdirAll(path.Dir(rootfsPath), 0755)
|
err = os.MkdirAll(path.Dir(rootfsPath), 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("ERROR: %s\n", err)
|
return "Failed creating directory", err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wwlog.Printf(wwlog.DEBUG, "Building VNFS image: '%s' -> '%s'\n", rootfsPath, imagePath)
|
wwlog.Printf(wwlog.DEBUG, "Building VNFS image: '%s' -> '%s'\n", rootfsPath, imagePath)
|
||||||
cmd := fmt.Sprintf("cd %s; find . | cpio --quiet -o -H newc | gzip -c > \"%s\"", rootfsPath, imagePath)
|
cmd := fmt.Sprintf("cd %s; find . | cpio --quiet -o -H newc | gzip -c > \"%s\"", rootfsPath, imagePath)
|
||||||
err = exec.Command("/bin/sh", "-c", cmd).Run()
|
err = exec.Command("/bin/sh", "-c", cmd).Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
wwlog.Printf(wwlog.ERROR, "Failed building VNFS: %s\n", err)
|
return "Failed building VNFS", err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wwlog.Printf(wwlog.INFO, "%-35s: Done\n", name)
|
return "Done", nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,9 +77,15 @@ func ValidSource(name string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if util.IsDir(fullPath) == false {
|
if util.IsDir(fullPath) == false {
|
||||||
wwlog.Printf(wwlog.WARN, "Location is not a VNFS source directory: %s\n", name)
|
wwlog.Printf(wwlog.VERBOSE, "Location is not a VNFS source directory: %s\n", name)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DeleteSource(name string) error {
|
||||||
|
fullPath := SourceDir(name)
|
||||||
|
|
||||||
|
return os.RemoveAll(fullPath)
|
||||||
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func ListKernels() ([]string, error) {
|
|||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Build(kernelVersion string) error {
|
func Build(kernelVersion string) (string, error) {
|
||||||
|
|
||||||
kernelImage := "/boot/vmlinuz-" + kernelVersion
|
kernelImage := "/boot/vmlinuz-" + kernelVersion
|
||||||
kernelDrivers := "/lib/modules/" + kernelVersion
|
kernelDrivers := "/lib/modules/" + kernelVersion
|
||||||
@@ -81,20 +81,19 @@ func Build(kernelVersion string) error {
|
|||||||
os.MkdirAll(path.Dir(driversDestination), 0755)
|
os.MkdirAll(path.Dir(driversDestination), 0755)
|
||||||
|
|
||||||
if util.IsFile(kernelImage) == false {
|
if util.IsFile(kernelImage) == false {
|
||||||
return errors.New("Could not locate kernel image: " + kernelImage)
|
return "", errors.New("Could not locate kernel image")
|
||||||
}
|
}
|
||||||
|
|
||||||
if util.IsDir(kernelDrivers) == false {
|
if util.IsDir(kernelDrivers) == false {
|
||||||
return errors.New("Could not locate kernel drivers: " + kernelDrivers)
|
return "", errors.New("Could not locate kernel drivers")
|
||||||
}
|
}
|
||||||
|
|
||||||
wwlog.Printf(wwlog.VERBOSE, "Setting up Kernel\n")
|
wwlog.Printf(wwlog.VERBOSE, "Setting up Kernel\n")
|
||||||
if _, err := os.Stat(kernelImage); err == nil {
|
if _, err := os.Stat(kernelImage); err == nil {
|
||||||
err := util.CopyFile(kernelImage, kernelDestination)
|
err := util.CopyFile(kernelImage, kernelDestination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
wwlog.Printf(wwlog.INFO, "%-45s: Done\n", "vmlinuz-"+kernelVersion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wwlog.Printf(wwlog.VERBOSE, "Building Kernel driver image\n")
|
wwlog.Printf(wwlog.VERBOSE, "Building Kernel driver image\n")
|
||||||
@@ -102,10 +101,9 @@ func Build(kernelVersion string) error {
|
|||||||
cmd := fmt.Sprintf("cd /; find .%s | cpio --quiet -o -H newc -F \"%s\"", kernelDrivers, driversDestination)
|
cmd := fmt.Sprintf("cd /; find .%s | cpio --quiet -o -H newc -F \"%s\"", kernelDrivers, driversDestination)
|
||||||
err := exec.Command("/bin/sh", "-c", cmd).Run()
|
err := exec.Command("/bin/sh", "-c", cmd).Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
wwlog.Printf(wwlog.INFO, "%-45s: Done\n", "kmods-"+kernelVersion+".img")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return "Done", nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -73,6 +74,9 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) {
|
|||||||
n.SystemOverlay.Set(node.SystemOverlay)
|
n.SystemOverlay.Set(node.SystemOverlay)
|
||||||
n.RuntimeOverlay.Set(node.RuntimeOverlay)
|
n.RuntimeOverlay.Set(node.RuntimeOverlay)
|
||||||
|
|
||||||
|
n.Discoverable.SetB(node.Discoverable)
|
||||||
|
n.Disabled.SetB(node.Disabled)
|
||||||
|
|
||||||
for devname, netdev := range node.NetDevs {
|
for devname, netdev := range node.NetDevs {
|
||||||
if _, ok := n.NetDevs[devname]; !ok {
|
if _, ok := n.NetDevs[devname]; !ok {
|
||||||
var netdev NetDevEntry
|
var netdev NetDevEntry
|
||||||
@@ -111,6 +115,9 @@ func (self *nodeYaml) FindAllNodes() ([]NodeInfo, error) {
|
|||||||
n.SystemOverlay.SetAlt(self.NodeProfiles[p].SystemOverlay, pstring)
|
n.SystemOverlay.SetAlt(self.NodeProfiles[p].SystemOverlay, pstring)
|
||||||
n.RuntimeOverlay.SetAlt(self.NodeProfiles[p].RuntimeOverlay, pstring)
|
n.RuntimeOverlay.SetAlt(self.NodeProfiles[p].RuntimeOverlay, pstring)
|
||||||
|
|
||||||
|
n.Disabled.SetAltB(self.NodeProfiles[p].Disabled, pstring)
|
||||||
|
n.Discoverable.SetAltB(self.NodeProfiles[p].Discoverable, pstring)
|
||||||
|
|
||||||
for devname, netdev := range self.NodeProfiles[p].NetDevs {
|
for devname, netdev := range self.NodeProfiles[p].NetDevs {
|
||||||
if _, ok := n.NetDevs[devname]; !ok {
|
if _, ok := n.NetDevs[devname]; !ok {
|
||||||
var netdev NetDevEntry
|
var netdev NetDevEntry
|
||||||
@@ -154,6 +161,9 @@ func (self *nodeYaml) FindAllProfiles() ([]NodeInfo, error) {
|
|||||||
p.RuntimeOverlay.Set(profile.RuntimeOverlay)
|
p.RuntimeOverlay.Set(profile.RuntimeOverlay)
|
||||||
p.SystemOverlay.Set(profile.SystemOverlay)
|
p.SystemOverlay.Set(profile.SystemOverlay)
|
||||||
|
|
||||||
|
p.Disabled.SetB(profile.Disabled)
|
||||||
|
p.Discoverable.SetB(profile.Discoverable)
|
||||||
|
|
||||||
for devname, netdev := range profile.NetDevs {
|
for devname, netdev := range profile.NetDevs {
|
||||||
if _, ok := p.NetDevs[devname]; !ok {
|
if _, ok := p.NetDevs[devname]; !ok {
|
||||||
var netdev NetDevEntry
|
var netdev NetDevEntry
|
||||||
@@ -174,9 +184,40 @@ func (self *nodeYaml) FindAllProfiles() ([]NodeInfo, error) {
|
|||||||
|
|
||||||
ret = append(ret, p)
|
ret = append(ret, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort.Slice(ret, func(i, j int) bool {
|
||||||
|
if ret[i].ClusterName.Get() < ret[j].ClusterName.Get() {
|
||||||
|
return true
|
||||||
|
} else if ret[i].ClusterName.Get() == ret[j].ClusterName.Get() {
|
||||||
|
if ret[i].Id.Get() < ret[j].Id.Get() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *nodeYaml) FindDiscoverableNode() (NodeInfo, string, error) {
|
||||||
|
var ret NodeInfo
|
||||||
|
|
||||||
|
nodes, _ := self.FindAllNodes()
|
||||||
|
|
||||||
|
for _, node := range nodes {
|
||||||
|
if node.Discoverable.GetB() == false {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for netdev, dev := range node.NetDevs {
|
||||||
|
if dev.Hwaddr.Defined() == false {
|
||||||
|
return node, netdev, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, "", errors.New("No unconfigured nodes found")
|
||||||
|
}
|
||||||
|
|
||||||
func (self *nodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) {
|
func (self *nodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) {
|
||||||
var ret NodeInfo
|
var ret NodeInfo
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package node
|
package node
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
"os"
|
"os"
|
||||||
@@ -30,6 +31,7 @@ type NodeConf struct {
|
|||||||
RuntimeOverlay string `yaml:"runtime overlay files,omitempty"`
|
RuntimeOverlay string `yaml:"runtime overlay files,omitempty"`
|
||||||
SystemOverlay string `yaml:"system overlay files,omitempty"`
|
SystemOverlay string `yaml:"system overlay files,omitempty"`
|
||||||
Init string `yaml:"init,omitempty"`
|
Init string `yaml:"init,omitempty"`
|
||||||
|
Discoverable bool `yaml:"discoverable,omitempty"`
|
||||||
Profiles []string `yaml:"profiles,omitempty"`
|
Profiles []string `yaml:"profiles,omitempty"`
|
||||||
NetDevs map[string]*NetDevs `yaml:"network devices,omitempty"`
|
NetDevs map[string]*NetDevs `yaml:"network devices,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -71,6 +73,8 @@ type NodeInfo struct {
|
|||||||
IpmiPassword Entry
|
IpmiPassword Entry
|
||||||
RuntimeOverlay Entry
|
RuntimeOverlay Entry
|
||||||
SystemOverlay Entry
|
SystemOverlay Entry
|
||||||
|
Discoverable Entry
|
||||||
|
Disabled Entry
|
||||||
Init Entry //TODO: Finish adding this...
|
Init Entry //TODO: Finish adding this...
|
||||||
Profiles []string
|
Profiles []string
|
||||||
GroupProfiles []string
|
GroupProfiles []string
|
||||||
@@ -89,7 +93,20 @@ type NetDevEntry struct {
|
|||||||
func init() {
|
func init() {
|
||||||
//TODO: Check to make sure nodes.conf is found
|
//TODO: Check to make sure nodes.conf is found
|
||||||
if util.IsFile(ConfigFile) == false {
|
if util.IsFile(ConfigFile) == false {
|
||||||
wwlog.Printf(wwlog.ERROR, "Configuration file not found: %s\n", ConfigFile)
|
c, err := os.OpenFile(ConfigFile, os.O_RDWR|os.O_CREATE, 0644)
|
||||||
os.Exit(1)
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "Could not create new configuration file: %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(c, "nodeprofiles:\n")
|
||||||
|
fmt.Fprintf(c, " default:\n")
|
||||||
|
fmt.Fprintf(c, " comment: This profile is automatically included for each node\n")
|
||||||
|
fmt.Fprintf(c, " kernel args: crashkernel=no quiet\n")
|
||||||
|
fmt.Fprintf(c, "nodes: {}\n")
|
||||||
|
|
||||||
|
c.Close()
|
||||||
|
|
||||||
|
wwlog.Printf(wwlog.INFO, "Created default node configuration\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,8 +41,10 @@ func (self *Entry) SetAlt(val string, from string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Entry) SetAltB(val bool, from string) {
|
func (self *Entry) SetAltB(val bool, from string) {
|
||||||
self.altbool = val
|
if val == true {
|
||||||
self.from = from
|
self.altbool = val
|
||||||
|
self.from = from
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,6 +108,13 @@ func (self *Entry) Print() string {
|
|||||||
return "--"
|
return "--"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *Entry) PrintB() bool {
|
||||||
|
if self.from == "" {
|
||||||
|
return self.bool
|
||||||
|
}
|
||||||
|
return self.altbool
|
||||||
|
}
|
||||||
|
|
||||||
func (self *Entry) Source() string {
|
func (self *Entry) Source() string {
|
||||||
if self.value != "" && self.altvalue != "" {
|
if self.value != "" && self.altvalue != "" {
|
||||||
return "SUPERSEDED"
|
return "SUPERSEDED"
|
||||||
|
|||||||
@@ -66,6 +66,10 @@ func (self *nodeYaml) NodeUpdate(node NodeInfo) error {
|
|||||||
self.Nodes[nodeID].IpmiPassword = node.IpmiPassword.GetReal()
|
self.Nodes[nodeID].IpmiPassword = node.IpmiPassword.GetReal()
|
||||||
self.Nodes[nodeID].RuntimeOverlay = node.RuntimeOverlay.GetReal()
|
self.Nodes[nodeID].RuntimeOverlay = node.RuntimeOverlay.GetReal()
|
||||||
self.Nodes[nodeID].SystemOverlay = node.SystemOverlay.GetReal()
|
self.Nodes[nodeID].SystemOverlay = node.SystemOverlay.GetReal()
|
||||||
|
|
||||||
|
self.Nodes[nodeID].Disabled = node.Disabled.GetRealB()
|
||||||
|
self.Nodes[nodeID].Discoverable = node.Discoverable.GetRealB()
|
||||||
|
|
||||||
self.Nodes[nodeID].Profiles = node.Profiles
|
self.Nodes[nodeID].Profiles = node.Profiles
|
||||||
self.Nodes[nodeID].NetDevs = make(map[string]*NetDevs)
|
self.Nodes[nodeID].NetDevs = make(map[string]*NetDevs)
|
||||||
|
|
||||||
@@ -138,6 +142,10 @@ func (self *nodeYaml) ProfileUpdate(profile NodeInfo) error {
|
|||||||
self.NodeProfiles[profileID].IpmiPassword = profile.IpmiPassword.GetReal()
|
self.NodeProfiles[profileID].IpmiPassword = profile.IpmiPassword.GetReal()
|
||||||
self.NodeProfiles[profileID].RuntimeOverlay = profile.RuntimeOverlay.GetReal()
|
self.NodeProfiles[profileID].RuntimeOverlay = profile.RuntimeOverlay.GetReal()
|
||||||
self.NodeProfiles[profileID].SystemOverlay = profile.SystemOverlay.GetReal()
|
self.NodeProfiles[profileID].SystemOverlay = profile.SystemOverlay.GetReal()
|
||||||
|
|
||||||
|
self.NodeProfiles[profileID].Disabled = profile.Disabled.GetRealB()
|
||||||
|
self.NodeProfiles[profileID].Discoverable = profile.Discoverable.GetRealB()
|
||||||
|
|
||||||
self.NodeProfiles[profileID].Profiles = profile.Profiles
|
self.NodeProfiles[profileID].Profiles = profile.Profiles
|
||||||
self.NodeProfiles[profileID].NetDevs = make(map[string]*NetDevs)
|
self.NodeProfiles[profileID].NetDevs = make(map[string]*NetDevs)
|
||||||
|
|
||||||
|
|||||||
@@ -118,9 +118,13 @@ func buildOverlay(nodeList []node.NodeInfo, overlayType string) error {
|
|||||||
var OverlayFile string
|
var OverlayFile string
|
||||||
|
|
||||||
if overlayType == "runtime" {
|
if overlayType == "runtime" {
|
||||||
|
wwlog.Printf(wwlog.VERBOSE, "Building runtime overlay for: %s\n", n.Id.Get())
|
||||||
|
|
||||||
OverlayDir = config.RuntimeOverlaySource(n.RuntimeOverlay.Get())
|
OverlayDir = config.RuntimeOverlaySource(n.RuntimeOverlay.Get())
|
||||||
OverlayFile = config.RuntimeOverlayImage(n.Id.Get())
|
OverlayFile = config.RuntimeOverlayImage(n.Id.Get())
|
||||||
} else if overlayType == "system" {
|
} else if overlayType == "system" {
|
||||||
|
wwlog.Printf(wwlog.VERBOSE, "Building system overlay for: %s\n", n.Id.Get())
|
||||||
|
|
||||||
OverlayDir = config.SystemOverlaySource(n.RuntimeOverlay.Get())
|
OverlayDir = config.SystemOverlaySource(n.RuntimeOverlay.Get())
|
||||||
OverlayFile = config.SystemOverlayImage(n.Id.Get())
|
OverlayFile = config.SystemOverlayImage(n.Id.Get())
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package response
|
package warewulfd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hpcng/warewulf/internal/pkg/container"
|
"github.com/hpcng/warewulf/internal/pkg/container"
|
||||||
114
internal/pkg/warewulfd/daemon.go
Normal file
114
internal/pkg/warewulfd/daemon.go
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
package warewulfd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
WAREWULFD_PIDFILE = "/tmp/warewulfd.pid"
|
||||||
|
WAREWULFD_LOGFILE = "/tmp/warewulfd.log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DaemonStart() error {
|
||||||
|
|
||||||
|
if os.Getenv("WAREWULFD_BACKGROUND") == "1" {
|
||||||
|
RunServer()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
os.Setenv("WAREWULFD_BACKGROUND", "1")
|
||||||
|
|
||||||
|
f, err := os.OpenFile(WAREWULFD_LOGFILE, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := os.OpenFile(WAREWULFD_PIDFILE, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command(os.Args[0], "server", "start")
|
||||||
|
cmd.Stdout = f
|
||||||
|
cmd.Stderr = f
|
||||||
|
cmd.Start()
|
||||||
|
pid := cmd.Process.Pid
|
||||||
|
|
||||||
|
fmt.Fprintf(p, "%d", pid)
|
||||||
|
|
||||||
|
p.Close()
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
DaemonStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DaemonStatus() error {
|
||||||
|
|
||||||
|
if util.IsFile(WAREWULFD_PIDFILE) == false {
|
||||||
|
wwlog.Printf(wwlog.INFO, "Warewulf daemon process not running (%s)\n", WAREWULFD_PIDFILE)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dat, err := ioutil.ReadFile(WAREWULFD_PIDFILE)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pid, _ := strconv.Atoi(string(dat))
|
||||||
|
process, err := os.FindProcess(pid)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to find process: %s\n", err)
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
err := process.Signal(syscall.Signal(0))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("SIGCONT on pid %d returned: %v\n", pid, err)
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Warewulf daemon is running at PID: %d\n", pid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DaemonStop() error {
|
||||||
|
|
||||||
|
if util.IsFile(WAREWULFD_PIDFILE) == false {
|
||||||
|
wwlog.Printf(wwlog.INFO, "Warewulf daemon process not running (%s)\n", WAREWULFD_PIDFILE)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dat, err := ioutil.ReadFile(WAREWULFD_PIDFILE)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pid, _ := strconv.Atoi(string(dat))
|
||||||
|
process, err := os.FindProcess(pid)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to find process: %s\n", err)
|
||||||
|
} else {
|
||||||
|
err := process.Signal(syscall.Signal(15))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("SIGCONT on pid %d returned: %v\n", pid, err)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Terminated Warewulf process at PID: %d\n", pid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Remove(WAREWULFD_PIDFILE)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
144
internal/pkg/warewulfd/ipxe.go
Normal file
144
internal/pkg/warewulfd/ipxe.go
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
package warewulfd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
type iPxeTemplate struct {
|
||||||
|
Message string
|
||||||
|
WaitTime string
|
||||||
|
Hostname string
|
||||||
|
Fqdn string
|
||||||
|
ContainerName string
|
||||||
|
Hwaddr string
|
||||||
|
Ipaddr string
|
||||||
|
Port string
|
||||||
|
KernelArgs string
|
||||||
|
KernelVersion string
|
||||||
|
}
|
||||||
|
|
||||||
|
func IpxeSend(w http.ResponseWriter, req *http.Request) {
|
||||||
|
url := strings.Split(req.URL.Path, "/")
|
||||||
|
var unconfiguredNode bool
|
||||||
|
|
||||||
|
nodeDB, err := node.New()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Could not read node configuration file: %s\n", err)
|
||||||
|
w.WriteHeader(503)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if url[2] == "" {
|
||||||
|
log.Printf("ERROR: Bad iPXE request from %s\n", req.RemoteAddr)
|
||||||
|
w.WriteHeader(404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conf, err := warewulfconf.New()
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||||
|
w.WriteHeader(503)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
hwaddr := strings.ReplaceAll(url[2], "-", ":")
|
||||||
|
|
||||||
|
n, err := nodeDB.FindByHwaddr(hwaddr)
|
||||||
|
if err != nil {
|
||||||
|
// If we failed to find a node, let's see if we can add one...
|
||||||
|
var netdev string
|
||||||
|
|
||||||
|
wwlog.Printf(wwlog.VERBOSE, "Node was not found, looking for discoverable nodes...\n")
|
||||||
|
|
||||||
|
n, netdev, err = nodeDB.FindDiscoverableNode()
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.WARN, "No nodes are set as discoverable...\n")
|
||||||
|
unconfiguredNode = true
|
||||||
|
|
||||||
|
} else {
|
||||||
|
wwlog.Printf(wwlog.INFO, "Adding new configuration to discoverable node: %s\n", n.Id.Get())
|
||||||
|
|
||||||
|
n.NetDevs[netdev].Hwaddr.Set(hwaddr)
|
||||||
|
n.Discoverable.SetB(false)
|
||||||
|
err := nodeDB.NodeUpdate(n)
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "Could not add discovered configuration for node: %s\n", n.Id.Get())
|
||||||
|
unconfiguredNode = true
|
||||||
|
} else {
|
||||||
|
err := nodeDB.Persist()
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "Could not persist new node configuration while adding node: %s\n", n.Id.Get())
|
||||||
|
unconfiguredNode = true
|
||||||
|
} else {
|
||||||
|
wwlog.Printf(wwlog.INFO, "Building System Overlay:\n")
|
||||||
|
_ = overlay.BuildSystemOverlay([]node.NodeInfo{n})
|
||||||
|
wwlog.Printf(wwlog.INFO, "Building Runtime Overlay:\n")
|
||||||
|
_ = overlay.BuildRuntimeOverlay([]node.NodeInfo{n})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if unconfiguredNode == true {
|
||||||
|
log.Printf("UNCONFIGURED NODE: %15s\n", hwaddr)
|
||||||
|
|
||||||
|
tmpl, err := template.ParseFiles("/etc/warewulf/ipxe/unconfigured.ipxe")
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var replace iPxeTemplate
|
||||||
|
|
||||||
|
replace.Hwaddr = hwaddr
|
||||||
|
|
||||||
|
err = tmpl.Execute(w, replace)
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log.Printf("IPXE: %15s: %s\n", n.Id.Get(), req.URL.Path)
|
||||||
|
|
||||||
|
ipxeTemplate := fmt.Sprintf("/etc/warewulf/ipxe/%s.ipxe", n.Ipxe.Get())
|
||||||
|
|
||||||
|
tmpl, err := template.ParseFiles(ipxeTemplate)
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var replace iPxeTemplate
|
||||||
|
|
||||||
|
replace.Fqdn = n.Id.Get()
|
||||||
|
replace.Ipaddr = conf.Ipaddr
|
||||||
|
replace.Port = strconv.Itoa(conf.Warewulf.Port)
|
||||||
|
replace.Hostname = n.Id.Get()
|
||||||
|
replace.Hwaddr = url[2]
|
||||||
|
replace.ContainerName = n.ContainerName.Get()
|
||||||
|
replace.KernelArgs = n.KernelArgs.Get()
|
||||||
|
replace.KernelVersion = n.KernelVersion.Get()
|
||||||
|
|
||||||
|
err = tmpl.Execute(w, replace)
|
||||||
|
if err != nil {
|
||||||
|
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("SEND: %15s: %s\n", n.Id.Get(), ipxeTemplate)
|
||||||
|
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package response
|
package warewulfd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hpcng/warewulf/internal/pkg/kernel"
|
"github.com/hpcng/warewulf/internal/pkg/kernel"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package response
|
package warewulfd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hpcng/warewulf/internal/pkg/kernel"
|
"github.com/hpcng/warewulf/internal/pkg/kernel"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package response
|
package warewulfd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package response
|
package warewulfd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hpcng/warewulf/internal/pkg/config"
|
"github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package response
|
package warewulfd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
27
internal/pkg/warewulfd/warewulfd.go
Normal file
27
internal/pkg/warewulfd/warewulfd.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package warewulfd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: https://github.com/danderson/netboot/blob/master/pixiecore/dhcp.go
|
||||||
|
// TODO: https://github.com/pin/tftp
|
||||||
|
|
||||||
|
func RunServer() error {
|
||||||
|
|
||||||
|
wwlog.Printf(wwlog.DEBUG, "Registering handlers for the web service\n")
|
||||||
|
|
||||||
|
http.HandleFunc("/ipxe/", IpxeSend)
|
||||||
|
http.HandleFunc("/kernel/", KernelSend)
|
||||||
|
http.HandleFunc("/kmods/", KmodsSend)
|
||||||
|
http.HandleFunc("/container/", ContainerSend)
|
||||||
|
http.HandleFunc("/overlay-system/", SystemOverlaySend)
|
||||||
|
http.HandleFunc("/overlay-runtime", RuntimeOverlaySend)
|
||||||
|
|
||||||
|
wwlog.Printf(wwlog.VERBOSE, "Starting HTTPD REST service\n")
|
||||||
|
|
||||||
|
http.ListenAndServe(":9873", nil)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user