Merge branch 'development' into issue/690
This commit is contained in:
3
.github/workflows/lint.yaml
vendored
3
.github/workflows/lint.yaml
vendored
@@ -21,7 +21,8 @@ jobs:
|
||||
go: [ '1.17' ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Create config
|
||||
run: make config
|
||||
- name: Setup go ${{ matrix.go }}
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -25,6 +25,7 @@
|
||||
/etc/bash_completion.d/
|
||||
warewulf.spec
|
||||
internal/pkg/buildconfig/setconfigs.go
|
||||
internal/pkg/warewulfconf/buildconfig.go
|
||||
include/systemd/warewulfd.service
|
||||
_dist/
|
||||
config
|
||||
@@ -38,3 +39,4 @@ Defaults.mk
|
||||
/etc/wwapird.conf
|
||||
.dist/
|
||||
userdocs/_*
|
||||
userdocs/reference/*
|
||||
|
||||
11
CHANGELOG.md
11
CHANGELOG.md
@@ -21,6 +21,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- The primary hostname and warewulf server fqdn are now the canonical name in
|
||||
`/etc/hosts`
|
||||
- new subcommand `wwctl genconf` is available with following subcommands:
|
||||
* `completions` which will create the files used for bash-completion. Also
|
||||
fish an zsh completions can be generated
|
||||
* `defaults` which will generate a valid `defaults.conf`
|
||||
* `man` which will generate the man pages in the specified directory
|
||||
* `reference` which will generate a reference documentation for the wwctl commands
|
||||
* `warwulfconf print` which will print the used `warewulf.conf`. If there is no valid
|
||||
`warewulf.conf` a valid configuration is provided, prefilled with default values
|
||||
and an IP configuration derived from the network configuration of the host
|
||||
- All paths can now be configured in `warewulf.conf`, check the paths section of of
|
||||
`wwctl --emptyconf genconfig warewulfconf print` for the available paths.
|
||||
- Added experimental dnsmasq support.
|
||||
|
||||
## [4.4.0] 2023-01-18
|
||||
|
||||
72
Makefile
72
Makefile
@@ -88,6 +88,11 @@ GO_TOOLS_VENDOR := $(addprefix vendor/, $(GO_TOOLS))
|
||||
GOLANGCI_LINT := $(TOOLS_BIN)/golangci-lint
|
||||
GOLANGCI_LINT_VERSION := v1.50.0
|
||||
|
||||
# helper functions
|
||||
godeps=$(shell go list -deps -f '{{if not .Standard}}{{ $$dep := . }}{{range .GoFiles}}{{$$dep.Dir}}/{{.}} {{end}}{{end}}' $(1) | sed "s%${PWD}/%%g")
|
||||
WWCTL_DEPS:=$(call godeps,cmd/wwctl/main.go)
|
||||
WWCLIENT_DEPS:=$(call godeps,cmd/wwclient/main.go)
|
||||
|
||||
# use GOPROXY for older git clients and speed up downloads
|
||||
GOPROXY ?= https://proxy.golang.org
|
||||
export GOPROXY
|
||||
@@ -96,7 +101,7 @@ export GOPROXY
|
||||
WW_GO_BUILD_TAGS := containers_image_openpgp containers_image_ostree
|
||||
|
||||
# Default target
|
||||
all: config vendor wwctl wwclient bash_completion.d man_pages config_defaults print_defaults wwapid wwapic wwapird print_mnts
|
||||
all: config vendor wwctl wwclient man_pages wwapid wwapic wwapird
|
||||
|
||||
# Validate source and build all packages
|
||||
build: lint test-it vet all
|
||||
@@ -178,7 +183,7 @@ files: all
|
||||
test -f $(DESTDIR)$(WWCONFIGDIR)/wwapic.conf || install -m 644 etc/wwapic.conf $(DESTDIR)$(WWCONFIGDIR)
|
||||
test -f $(DESTDIR)$(WWCONFIGDIR)/wwapid.conf || install -m 644 etc/wwapid.conf $(DESTDIR)$(WWCONFIGDIR)
|
||||
test -f $(DESTDIR)$(WWCONFIGDIR)/wwapird.conf || install -m 644 etc/wwapird.conf $(DESTDIR)$(WWCONFIGDIR)
|
||||
test -f $(DESTDIR)$(WWCONFIGDIR)/defaults.conf || ./print_defaults > $(DESTDIR)$(WWCONFIGDIR)/defaults.conf
|
||||
test -f $(DESTDIR)$(DATADIR)/warewulf/defaults.conf || ./wwctl --emptyconf genconfig defaults > $(DESTDIR)$(DATADIR)/warewulf/defaults.conf
|
||||
cp -r etc/examples $(DESTDIR)$(WWCONFIGDIR)/
|
||||
cp -r etc/ipxe $(DESTDIR)$(WWCONFIGDIR)/
|
||||
cp -r overlays/* $(DESTDIR)$(WWOVERLAYDIR)/
|
||||
@@ -191,13 +196,14 @@ files: all
|
||||
chmod 600 $(DESTDIR)$(WWOVERLAYDIR)/wwinit/warewulf/config.ww
|
||||
chmod 750 $(DESTDIR)$(WWOVERLAYDIR)/host
|
||||
install -m 0755 wwctl $(DESTDIR)$(BINDIR)
|
||||
install -m 0755 wwclient $(DESTDIR)$(WWOVERLAYDIR)/wwinit/$(WWCLIENTDIR)/wwclient
|
||||
install -m 0755 wwapic $(DESTDIR)$(BINDIR)
|
||||
install -m 0755 wwapid $(DESTDIR)$(BINDIR)
|
||||
install -m 0755 wwapird $(DESTDIR)$(BINDIR)
|
||||
install -m 0644 include/firewalld/warewulf.xml $(DESTDIR)$(FIREWALLDDIR)
|
||||
install -m 0644 include/systemd/warewulfd.service $(DESTDIR)$(SYSTEMDDIR)
|
||||
install -m 0644 LICENSE.md $(DESTDIR)$(WWDOCDIR)
|
||||
cp bash_completion.d/warewulf $(DESTDIR)$(BASHCOMPDIR)
|
||||
./wwctl genconfig completions > $(DESTDIR)$(BASHCOMPDIR)/wwctl
|
||||
cp man_pages/*.1* $(DESTDIR)$(MANDIR)/man1/
|
||||
cp man_pages/*.5* $(DESTDIR)$(MANDIR)/man5/
|
||||
install -m 0644 staticfiles/README-ipxe.md $(DESTDIR)$(WWDATADIR)/ipxe
|
||||
@@ -210,53 +216,28 @@ init:
|
||||
cp -r tftpboot/* $(WWTFTPDIR)/ipxe/
|
||||
restorecon -r $(WWTFTPDIR)
|
||||
|
||||
wwctl:
|
||||
cd cmd/wwctl; GOOS=linux go build -mod vendor -tags "$(WW_GO_BUILD_TAGS)" -o ../../wwctl
|
||||
wwctl: $(WWCTL_DEPS)
|
||||
@echo Building "$@"
|
||||
@cd cmd/wwctl; GOOS=linux go build -mod vendor -tags "$(WW_GO_BUILD_TAGS)" \
|
||||
-ldflags "-X 'github.com/hpcng/warewulf/internal/pkg/warewulfconf.ConfigFile=$(SYSCONFDIR)/warewulf/warewulf.conf'" \
|
||||
-o ../../wwctl
|
||||
|
||||
wwclient:
|
||||
cd cmd/wwclient; CGO_ENABLED=0 GOOS=linux go build -mod vendor -a -ldflags "-extldflags -static \
|
||||
wwclient: $(WWCLIENT_DEPS)
|
||||
@echo Building "$@"
|
||||
@cd cmd/wwclient; CGO_ENABLED=0 GOOS=linux go build -mod vendor -a -ldflags "-extldflags -static \
|
||||
-X 'github.com/hpcng/warewulf/internal/pkg/warewulfconf.ConfigFile=/etc/warewulf/warewulf.conf'" -o ../../wwclient
|
||||
|
||||
install_wwclient: wwclient
|
||||
install -m 0755 wwclient $(DESTDIR)$(WWOVERLAYDIR)/wwinit/$(WWCLIENTDIR)/wwclient
|
||||
|
||||
bash_completion:
|
||||
cd cmd/bash_completion && go build -ldflags="-X 'github.com/hpcng/warewulf/internal/pkg/warewulfconf.ConfigFile=./etc/warewulf.conf'\
|
||||
-X 'github.com/hpcng/warewulf/internal/pkg/node.ConfigFile=./etc/nodes.conf'"\
|
||||
-mod vendor -tags "$(WW_GO_BUILD_TAGS)" -o ../../bash_completion
|
||||
|
||||
bash_completion.d: bash_completion
|
||||
install -d -m 0755 bash_completion.d
|
||||
./bash_completion bash_completion.d/warewulf
|
||||
|
||||
man_page:
|
||||
cd cmd/man_page && go build -ldflags="-X 'github.com/hpcng/warewulf/internal/pkg/warewulfconf.ConfigFile=./etc/warewulf.conf'\
|
||||
-X 'github.com/hpcng/warewulf/internal/pkg/node.ConfigFile=./etc/nodes.conf'"\
|
||||
-mod vendor -tags "$(WW_GO_BUILD_TAGS)" -o ../../man_page
|
||||
|
||||
man_pages: man_page
|
||||
man_pages: wwctl
|
||||
install -d man_pages
|
||||
./man_page ./man_pages
|
||||
./wwctl --emptyconf genconfig man man_pages
|
||||
cp docs/man/man5/*.5 ./man_pages/
|
||||
cd man_pages; for i in wwctl*1 *.5; do echo "Compressing manpage: $$i"; gzip --force $$i; done
|
||||
|
||||
config_defaults: vendor cmd/config_defaults/config_defaults.go
|
||||
cd cmd/config_defaults && go build -ldflags="-X 'github.com/hpcng/warewulf/internal/pkg/warewulfconf.ConfigFile=./etc/warewulf.conf'\
|
||||
-X 'github.com/hpcng/warewulf/internal/pkg/node.ConfigFile=./etc/nodes.conf'"\
|
||||
-mod vendor -tags "$(WW_GO_BUILD_TAGS)" -o ../../config_defaults
|
||||
|
||||
print_defaults: vendor cmd/print_defaults/print_defaults.go
|
||||
cd cmd/print_defaults && go build -ldflags="-X 'github.com/hpcng/warewulf/internal/pkg/warewulfconf.ConfigFile=./etc/warewulf.conf'" -o ../../print_defaults
|
||||
|
||||
|
||||
update_configuration: vendor cmd/update_configuration/update_configuration.go
|
||||
cd cmd/update_configuration && go build -ldflags="-X 'github.com/hpcng/warewulf/internal/pkg/warewulfconf.ConfigFile=./etc/warewulf.conf'\
|
||||
-X 'github.com/hpcng/warewulf/internal/pkg/node.ConfigFile=./etc/nodes.conf'"\
|
||||
-mod vendor -tags "$(WW_GO_BUILD_TAGS)" -o ../../update_configuration
|
||||
|
||||
warewulfconf: config_defaults
|
||||
./config_defaults
|
||||
|
||||
dist: vendor config
|
||||
rm -rf .dist/$(WAREWULF)-$(VERSION) $(WAREWULF)-$(VERSION).tar.gz
|
||||
mkdir -p .dist/$(WAREWULF)-$(VERSION)
|
||||
@@ -264,6 +245,12 @@ dist: vendor config
|
||||
cd .dist; tar -czf ../$(WAREWULF)-$(VERSION).tar.gz $(WAREWULF)-$(VERSION)
|
||||
rm -rf .dist
|
||||
|
||||
reference: wwctl
|
||||
./wwctl --emptyconf genconfig reference userdocs/reference/
|
||||
|
||||
latexpdf: reference
|
||||
make -C userdocs latexpdf
|
||||
|
||||
## wwapi generate code from protobuf. Requires protoc and protoc-grpc-gen-gateway to generate code.
|
||||
## To setup latest protoc:
|
||||
## Download the protobuf-all-[VERSION].tar.gz from https://github.com/protocolbuffers/protobuf/releases
|
||||
@@ -274,7 +261,7 @@ dist: vendor config
|
||||
## sudo make install
|
||||
## sudo ldconfig # refresh shared library cache.
|
||||
## To setup protoc-gen-grpc-gateway, see https://github.com/grpc-ecosystem/grpc-gateway
|
||||
proto:
|
||||
proto:
|
||||
rm -rf internal/pkg/api/routes/wwapiv1/
|
||||
protoc -I internal/pkg/api/routes/v1 -I=. \
|
||||
--grpc-gateway_out=. \
|
||||
@@ -297,22 +284,17 @@ contclean:
|
||||
rm -f wwctl
|
||||
rm -rf .dist
|
||||
rm -f $(WAREWULF)-$(VERSION).tar.gz
|
||||
rm -f bash_completion
|
||||
rm -rf bash_completion.d
|
||||
rm -f man_page
|
||||
rm -rf man_pages
|
||||
rm -f warewulf.spec
|
||||
rm -f config
|
||||
rm -f Defaults.mk
|
||||
rm -rf $(TOOLS_DIR)
|
||||
rm -f config_defaults
|
||||
rm -f update_configuration
|
||||
rm -f print_defaults
|
||||
rm -f etc/wwapi{c,d,rd}.conf
|
||||
|
||||
clean: contclean
|
||||
rm -rf vendor
|
||||
|
||||
install: files install_wwclient
|
||||
install: files
|
||||
|
||||
debinstall: files debfiles
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
// usage: ./bash_completion <FILE>
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl"
|
||||
"os"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package main
|
||||
|
||||
// Regenerates the default configuration files
|
||||
// Keeps the current content and adds missing default values
|
||||
// Won't create a new file, but will update a blank file
|
||||
|
||||
//TODO: Add nodes.conf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
)
|
||||
|
||||
func main() {
|
||||
tmpConf, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = tmpConf.Persist()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
// Generate man pages for wwctl command.
|
||||
// usage: ./man_page <DIRECTORY>
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
if err := wwctl.GenManTree(os.Args[1]); err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||
)
|
||||
|
||||
/*
|
||||
Print the build in defaults for the nodes.
|
||||
Called via Makefile so that there is single upstream
|
||||
source of the defaults which is FallBackConf
|
||||
*/
|
||||
|
||||
func main() {
|
||||
fmt.Println(node.FallBackConf)
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/hpcng/warewulf/cmd/update_configuration/vers42"
|
||||
"github.com/hpcng/warewulf/cmd/update_configuration/vers43"
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
@@ -125,7 +124,7 @@ func main() {
|
||||
var endVers int
|
||||
var startVers int
|
||||
flag.StringVar(&confFile, "f", "", "Config file for update")
|
||||
flag.IntVar(&endVers, "e", buildconfig.WWVer, "Final version of configuration file")
|
||||
flag.IntVar(&endVers, "e", 0, "Final version of configuration file")
|
||||
flag.IntVar(&startVers, "s", 0, "Start version of configuration file, 0 is for autodetection")
|
||||
flag.BoolVar(&nowrite, "n", false, "Do not write, just print new conf to terminal")
|
||||
flag.BoolVar(&quiet, "q", false, "Do not print what the program is doing")
|
||||
|
||||
1
go.mod
1
go.mod
@@ -3,7 +3,6 @@ module github.com/hpcng/warewulf
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/brotherpowers/ipsubnet v0.0.0-20170914094241-30bc98f0a5b1
|
||||
github.com/containers/image/v5 v5.7.0
|
||||
github.com/containers/storage v1.30.0
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e
|
||||
|
||||
2
go.sum
2
go.sum
@@ -98,8 +98,6 @@ github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngE
|
||||
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/brotherpowers/ipsubnet v0.0.0-20170914094241-30bc98f0a5b1 h1:80OMQcGycPqKFFabSaxOagCh7mgspnMl/X3YGmNi+j0=
|
||||
github.com/brotherpowers/ipsubnet v0.0.0-20170914094241-30bc98f0a5b1/go.mod h1:mm9ZF6W76SwZtJpYzrVmTMuzmIhPX0SIuEosW/OTFd4=
|
||||
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
|
||||
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/api/apiconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
@@ -24,9 +24,10 @@ import (
|
||||
|
||||
func main() {
|
||||
log.Println("Client running")
|
||||
conf := warewulfconf.New()
|
||||
|
||||
// Read the config file.
|
||||
config, err := apiconfig.NewClient(path.Join(buildconfig.SYSCONFDIR(), "warewulf/wwapic.conf"))
|
||||
config, err := apiconfig.NewClient(path.Join(conf.Paths.Sysconfdir, "warewulf/wwapic.conf"))
|
||||
if err != nil {
|
||||
log.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
"github.com/hpcng/warewulf/internal/pkg/api/container"
|
||||
apinode "github.com/hpcng/warewulf/internal/pkg/api/node"
|
||||
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/version"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials"
|
||||
@@ -34,8 +34,9 @@ var apiVersion string
|
||||
func main() {
|
||||
log.Println("Server running")
|
||||
|
||||
conf := warewulfconf.New()
|
||||
// Read the config file.
|
||||
config, err := apiconfig.NewServer(path.Join(buildconfig.SYSCONFDIR(), "warewulf/wwapid.conf"))
|
||||
config, err := apiconfig.NewServer(path.Join(conf.Paths.Sysconfdir, "warewulf/wwapid.conf"))
|
||||
if err != nil {
|
||||
log.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
@@ -18,20 +18,20 @@ import (
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/api/apiconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
|
||||
gw "github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
|
||||
|
||||
"path"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
)
|
||||
|
||||
func run() error {
|
||||
|
||||
log.Println("test0")
|
||||
|
||||
conf := warewulfconf.New()
|
||||
// Read the config file.
|
||||
config, err := apiconfig.NewClientServer(path.Join(buildconfig.SYSCONFDIR(), "warewulf/wwapird.conf"))
|
||||
config, err := apiconfig.NewClientServer(path.Join(conf.Paths.Sysconfdir, "warewulf/wwapird.conf"))
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to read config file, err: %v", err)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
|
||||
"github.com/coreos/go-systemd/daemon"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/pidfile"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
@@ -50,10 +49,7 @@ func GetRootCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
conf, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conf := warewulfconf.New()
|
||||
|
||||
pid, err := pidfile.Write(PIDFile)
|
||||
if err != nil && pid == -1 {
|
||||
@@ -62,7 +58,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
return errors.New("found pidfile " + PIDFile + " not starting")
|
||||
}
|
||||
|
||||
if os.Args[0] == path.Join(buildconfig.WWCLIENTDIR(), "wwclient") {
|
||||
if os.Args[0] == path.Join(conf.Paths.WWClientdir, "wwclient") {
|
||||
err := os.Chdir("/")
|
||||
if err != nil {
|
||||
wwlog.Error("failed to change dir: %s", err)
|
||||
@@ -74,7 +70,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
fmt.Printf("Called via: %s\n", os.Args[0])
|
||||
fmt.Printf("Runtime overlay is being put in '/warewulf/wwclient-test' rather than '/'\n")
|
||||
fmt.Printf("For full functionality call with: %s\n", path.Join(buildconfig.WWCLIENTDIR(), "wwclient"))
|
||||
fmt.Printf("For full functionality call with: %s\n", path.Join(conf.Paths.WWClientdir, "wwclient"))
|
||||
err := os.MkdirAll("/warewulf/wwclient-test", 0755)
|
||||
if err != nil {
|
||||
wwlog.Error("failed to create dir: %s", err)
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
if os.Getpid() != 1 {
|
||||
wwlog.Error("PID is not 1: %d", os.Getpid())
|
||||
os.Exit(1)
|
||||
@@ -33,10 +33,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
wwlog.Error("Unknown Warewulf container: %s", containerName)
|
||||
os.Exit(1)
|
||||
}
|
||||
conf, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
wwlog.Verbose("Couldn't get warewulf ocnfiguration: %s", err)
|
||||
}
|
||||
conf := warewulfconf.New()
|
||||
mountPts := conf.MountsContainer
|
||||
mountPts = append(container.InitMountPnts(binds), mountPts...)
|
||||
// check for valid mount points
|
||||
|
||||
23
internal/app/wwctl/genconf/completions/main.go
Normal file
23
internal/app/wwctl/genconf/completions/main.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package completions
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
myArg := "bash"
|
||||
if len(args) == 1 {
|
||||
myArg = args[0]
|
||||
}
|
||||
switch myArg {
|
||||
case "zsh":
|
||||
err = cmd.Parent().Parent().GenZshCompletion(os.Stdout)
|
||||
case "fish":
|
||||
err = cmd.Parent().Parent().GenFishCompletion(os.Stdout, true)
|
||||
default:
|
||||
err = cmd.Parent().Parent().GenBashCompletion(os.Stdout)
|
||||
}
|
||||
return
|
||||
}
|
||||
22
internal/app/wwctl/genconf/completions/root.go
Normal file
22
internal/app/wwctl/genconf/completions/root.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package completions
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
Use: "completions",
|
||||
Short: "shell completion",
|
||||
Long: "This command generates the bash completions if no argument is given.",
|
||||
RunE: CobraRunE,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Aliases: []string{"bash"},
|
||||
}
|
||||
Zsh bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
}
|
||||
|
||||
func GetCommand() *cobra.Command {
|
||||
return baseCmd
|
||||
}
|
||||
13
internal/app/wwctl/genconf/dfaults/main.go
Normal file
13
internal/app/wwctl/genconf/dfaults/main.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package dfaults
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
fmt.Println(node.FallBackConf)
|
||||
return
|
||||
}
|
||||
21
internal/app/wwctl/genconf/dfaults/root.go
Normal file
21
internal/app/wwctl/genconf/dfaults/root.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package dfaults
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
Use: "defaults",
|
||||
Short: "print defaults",
|
||||
Long: "This command prints the fallbacks which are used if defaults.conf isn't present",
|
||||
RunE: CobraRunE,
|
||||
Args: cobra.NoArgs,
|
||||
Aliases: []string{"dfaults"},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
}
|
||||
|
||||
func GetCommand() *cobra.Command {
|
||||
return baseCmd
|
||||
}
|
||||
15
internal/app/wwctl/genconf/man/main.go
Normal file
15
internal/app/wwctl/genconf/man/main.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package man
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/cobra/doc"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
header := &doc.GenManHeader{
|
||||
Title: "WWCTL",
|
||||
Section: "1",
|
||||
}
|
||||
err = doc.GenManTree(cmd.Parent().Parent(), header, args[0])
|
||||
return
|
||||
}
|
||||
23
internal/app/wwctl/genconf/man/root.go
Normal file
23
internal/app/wwctl/genconf/man/root.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package man
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
Use: "man",
|
||||
Short: "manpage generation",
|
||||
Long: "This command generates the man pages for all commands, needs target dir as argument",
|
||||
RunE: CobraRunE,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Aliases: []string{"man_pages"},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
}
|
||||
|
||||
func GetCommand() *cobra.Command {
|
||||
return baseCmd
|
||||
}
|
||||
17
internal/app/wwctl/genconf/reference/main.go
Normal file
17
internal/app/wwctl/genconf/reference/main.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package reference
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/cobra/doc"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
linkHandler := func(name, ref string) string {
|
||||
return fmt.Sprintf(":ref:`%s <%s>`", name, ref)
|
||||
}
|
||||
err = doc.GenReSTTreeCustom(cmd.Parent().Parent(), args[0], func(arg string) string { return "" }, linkHandler)
|
||||
//err = doc.GenReSTTree(cmd.Parent().Parent(), args[0])
|
||||
return
|
||||
}
|
||||
22
internal/app/wwctl/genconf/reference/root.go
Normal file
22
internal/app/wwctl/genconf/reference/root.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package reference
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
Use: "reference",
|
||||
Short: "reference generation",
|
||||
Long: "This command generates the references in ReStructured Text, needs target dir as argument",
|
||||
RunE: CobraRunE,
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
}
|
||||
|
||||
func GetCommand() *cobra.Command {
|
||||
return baseCmd
|
||||
}
|
||||
35
internal/app/wwctl/genconf/root.go
Normal file
35
internal/app/wwctl/genconf/root.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package genconf
|
||||
|
||||
import (
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/genconf/completions"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/genconf/dfaults"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/genconf/man"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/genconf/reference"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/genconf/warewulfconf"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
Use: "genconfig",
|
||||
Short: "Generate various configurations",
|
||||
Long: "This command will allow you to generate different configurations like bash-completions.",
|
||||
Args: cobra.ExactArgs(0),
|
||||
Aliases: []string{"cnf"},
|
||||
}
|
||||
ListFull bool
|
||||
WWctlRoot *cobra.Command
|
||||
)
|
||||
|
||||
func init() {
|
||||
baseCmd.AddCommand(completions.GetCommand())
|
||||
baseCmd.AddCommand(man.GetCommand())
|
||||
baseCmd.AddCommand(reference.GetCommand())
|
||||
baseCmd.AddCommand(dfaults.GetCommand())
|
||||
baseCmd.AddCommand(warewulfconf.GetCommand())
|
||||
}
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
func GetCommand() *cobra.Command {
|
||||
return baseCmd
|
||||
}
|
||||
19
internal/app/wwctl/genconf/warewulfconf/print/main.go
Normal file
19
internal/app/wwctl/genconf/warewulfconf/print/main.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package print
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
conf := warewulfconf.New()
|
||||
buffer, err := yaml.Marshal(&conf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println(string(buffer))
|
||||
return
|
||||
}
|
||||
22
internal/app/wwctl/genconf/warewulfconf/print/root.go
Normal file
22
internal/app/wwctl/genconf/warewulfconf/print/root.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package print
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
Use: "print",
|
||||
Short: "print wareweulf.conf",
|
||||
Long: "This command prints the actual used warewulf.conf, can be used to create an empty valid warewulf.conf",
|
||||
RunE: CobraRunE,
|
||||
Args: cobra.ExactArgs(0),
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
}
|
||||
|
||||
func GetCommand() *cobra.Command {
|
||||
return baseCmd
|
||||
}
|
||||
27
internal/app/wwctl/genconf/warewulfconf/root.go
Normal file
27
internal/app/wwctl/genconf/warewulfconf/root.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package warewulfconf
|
||||
|
||||
import (
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/genconf/warewulfconf/print"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
Use: "warewulfconf",
|
||||
Short: "access warewulf.conf",
|
||||
Long: "Commands for accessing the actual used warewulf.conf",
|
||||
Args: cobra.ExactArgs(0),
|
||||
Aliases: []string{"cnf"},
|
||||
}
|
||||
ListFull bool
|
||||
WWctlRoot *cobra.Command
|
||||
)
|
||||
|
||||
func init() {
|
||||
baseCmd.AddCommand(print.GetCommand())
|
||||
}
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
func GetCommand() *cobra.Command {
|
||||
return baseCmd
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package add
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
apinode "github.com/hpcng/warewulf/internal/pkg/api/node"
|
||||
@@ -11,24 +9,33 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
// remove the default network as the all network values are assigned
|
||||
// to this network
|
||||
if NetName != "" {
|
||||
netDev := *NodeConf.NetDevs["default"]
|
||||
NodeConf.NetDevs[NetName] = &netDev
|
||||
delete(NodeConf.NetDevs, "default")
|
||||
|
||||
/*
|
||||
RunE needs a function of type func(*cobraCommand,[]string) err, but
|
||||
in order to avoid global variables which mess up testing a function of
|
||||
the required type is returned
|
||||
*/
|
||||
func CobraRunE(vars *variables) func(cmd *cobra.Command, args []string) error {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
// remove the default network as all network values are assigned
|
||||
// to this network
|
||||
if _, ok := vars.nodeConf.NetDevs["default"]; ok && vars.netName != "" {
|
||||
netDev := *vars.nodeConf.NetDevs["default"]
|
||||
vars.nodeConf.NetDevs[vars.netName] = &netDev
|
||||
delete(vars.nodeConf.NetDevs, "default")
|
||||
} else {
|
||||
if vars.nodeConf.NetDevs["default"].Empty() {
|
||||
delete(vars.nodeConf.NetDevs, "default")
|
||||
}
|
||||
}
|
||||
buffer, err := yaml.Marshal(vars.nodeConf)
|
||||
if err != nil {
|
||||
wwlog.Error("Cant marshall nodeInfo", err)
|
||||
return err
|
||||
}
|
||||
set := wwapiv1.NodeAddParameter{
|
||||
NodeConfYaml: string(buffer[:]),
|
||||
NodeNames: args,
|
||||
}
|
||||
return apinode.NodeAdd(&set)
|
||||
}
|
||||
buffer, err := yaml.Marshal(NodeConf)
|
||||
if err != nil {
|
||||
wwlog.Error("Cant marshall nodeInfo", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
set := wwapiv1.NodeAddParameter{
|
||||
NodeConfYaml: string(buffer[:]),
|
||||
NodeNames: args,
|
||||
}
|
||||
|
||||
return apinode.NodeAdd(&set)
|
||||
}
|
||||
|
||||
221
internal/app/wwctl/node/add/main_test.go
Normal file
221
internal/app/wwctl/node/add/main_test.go
Normal file
@@ -0,0 +1,221 @@
|
||||
package add
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Add(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
wantErr bool
|
||||
stdout string
|
||||
outDb string
|
||||
}{
|
||||
{name: "single node add",
|
||||
args: []string{"n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
`},
|
||||
{name: "single node add, profile foo",
|
||||
args: []string{"--profile=foo", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- foo
|
||||
`},
|
||||
{name: "single node add with Kernel args",
|
||||
args: []string{"--kernelargs=foo", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
kernel:
|
||||
args: foo
|
||||
profiles:
|
||||
- default
|
||||
`},
|
||||
{name: "double node add explicit",
|
||||
args: []string{"n01", "n02"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
n02:
|
||||
profiles:
|
||||
- default
|
||||
`},
|
||||
{name: "single node with ipaddr6",
|
||||
args: []string{"--ipaddr6=fdaa::1", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
default:
|
||||
ip6addr: fdaa::1
|
||||
`},
|
||||
{name: "single node with ipaddr",
|
||||
args: []string{"--ipaddr=10.0.0.1", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
default:
|
||||
ipaddr: 10.0.0.1
|
||||
`},
|
||||
{name: "three nodes with ipaddr",
|
||||
args: []string{"--ipaddr=10.10.0.1", "n[01-02,03]"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
default:
|
||||
ipaddr: 10.10.0.1
|
||||
n02:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
default:
|
||||
ipaddr: 10.10.0.2
|
||||
n03:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
default:
|
||||
ipaddr: 10.10.0.3
|
||||
`},
|
||||
{name: "three nodes with ipaddr different network",
|
||||
args: []string{"--ipaddr=10.10.0.1", "--netname=foo", "n[01-03]"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
foo:
|
||||
ipaddr: 10.10.0.1
|
||||
n02:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
foo:
|
||||
ipaddr: 10.10.0.2
|
||||
n03:
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
foo:
|
||||
ipaddr: 10.10.0.3
|
||||
`},
|
||||
{name: "three nodes with ipaddr different network, with ipmiaddr",
|
||||
args: []string{"--ipaddr=10.10.0.1", "--netname=foo", "--ipmiaddr=10.20.0.1", "n[01-03]"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
ipmi:
|
||||
ipaddr: 10.20.0.1
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
foo:
|
||||
ipaddr: 10.10.0.1
|
||||
n02:
|
||||
ipmi:
|
||||
ipaddr: 10.20.0.2
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
foo:
|
||||
ipaddr: 10.10.0.2
|
||||
n03:
|
||||
ipmi:
|
||||
ipaddr: 10.20.0.3
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
foo:
|
||||
ipaddr: 10.10.0.3
|
||||
`},
|
||||
}
|
||||
conf_yml := `
|
||||
WW_INTERNAL: 0
|
||||
`
|
||||
nodes_yml := `
|
||||
WW_INTERNAL: 43
|
||||
`
|
||||
conf := warewulfconf.New()
|
||||
err := conf.Read([]byte(conf_yml))
|
||||
assert.NoError(t, err)
|
||||
db, err := node.TestNew([]byte(nodes_yml))
|
||||
assert.NoError(t, err)
|
||||
warewulfd.SetNoDaemon()
|
||||
for _, tt := range tests {
|
||||
db, err = node.TestNew([]byte(nodes_yml))
|
||||
assert.NoError(t, err)
|
||||
t.Logf("Running test: %s\n", tt.name)
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
baseCmd := GetCommand()
|
||||
baseCmd.SetArgs(tt.args)
|
||||
buf := new(bytes.Buffer)
|
||||
baseCmd.SetOut(buf)
|
||||
baseCmd.SetErr(buf)
|
||||
err = baseCmd.Execute()
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Got unwanted error: %s", err)
|
||||
t.FailNow()
|
||||
}
|
||||
dump := string(db.DBDump())
|
||||
if dump != tt.outDb {
|
||||
t.Errorf("DB dump is wrong, got:'%s'\nwant:'%s'", dump, tt.outDb)
|
||||
t.FailNow()
|
||||
}
|
||||
if buf.String() != tt.stdout {
|
||||
t.Errorf("Got wrong output, got:'%s'\nwant:'%s'", buf.String(), tt.stdout)
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -10,23 +10,26 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
// Holds the variables which are needed in CobraRunE
|
||||
type variables struct {
|
||||
netName string
|
||||
nodeConf node.NodeConf
|
||||
}
|
||||
|
||||
// Returns the newly created command
|
||||
func GetCommand() *cobra.Command {
|
||||
vars := variables{}
|
||||
vars.nodeConf = node.NewConf()
|
||||
baseCmd := &cobra.Command{
|
||||
DisableFlagsInUseLine: true,
|
||||
Use: "add [OPTIONS] NODENAME",
|
||||
Short: "Add new node to Warewulf",
|
||||
Long: "This command will add a new node named NODENAME to Warewulf.",
|
||||
RunE: CobraRunE,
|
||||
RunE: CobraRunE(&vars),
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
}
|
||||
NodeConf node.NodeConf
|
||||
NetName string
|
||||
)
|
||||
|
||||
func init() {
|
||||
NodeConf = node.NewConf()
|
||||
NodeConf.CreateFlags(baseCmd, []string{})
|
||||
baseCmd.PersistentFlags().StringVar(&NetName, "netname", "", "Set network name for network options")
|
||||
vars.nodeConf.CreateFlags(baseCmd, []string{"tagdel", "nettagdel", "ipmitagdel"})
|
||||
baseCmd.PersistentFlags().StringVar(&vars.netName, "netname", "", "Set network name for network options")
|
||||
|
||||
// register the command line completions
|
||||
if err := baseCmd.RegisterFlagCompletionFunc("container", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
@@ -65,9 +68,6 @@ func init() {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
func GetCommand() *cobra.Command {
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
return baseCmd
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package nodestatus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -19,15 +18,11 @@ import (
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
|
||||
controller, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
wwlog.Error("%s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
controller := warewulfconf.New()
|
||||
|
||||
if controller.Ipaddr == "" {
|
||||
wwlog.Error("The Warewulf Server IP Address is not properly configured")
|
||||
os.Exit(1)
|
||||
return fmt.Errorf("warewulf Server IP Address is not properly configured")
|
||||
|
||||
}
|
||||
|
||||
for {
|
||||
|
||||
@@ -14,11 +14,7 @@ import (
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
controller, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
wwlog.Error("%s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
controller := warewulfconf.New()
|
||||
nodeDB, err := node.New()
|
||||
if err != nil {
|
||||
wwlog.Error("Could not open node configuration: %s", err)
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package wwctl
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/configure"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/container"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/genconf"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/kernel"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/node"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/overlay"
|
||||
@@ -12,11 +15,9 @@ import (
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/ssh"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/version"
|
||||
"github.com/hpcng/warewulf/internal/pkg/help"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/cobra/doc"
|
||||
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -29,9 +30,11 @@ var (
|
||||
SilenceUsage: true,
|
||||
SilenceErrors: true,
|
||||
}
|
||||
verboseArg bool
|
||||
DebugFlag bool
|
||||
LogLevel int
|
||||
verboseArg bool
|
||||
DebugFlag bool
|
||||
LogLevel int
|
||||
WarewulfConfArg string
|
||||
AllowEmptyConf bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -39,9 +42,11 @@ func init() {
|
||||
rootCmd.PersistentFlags().BoolVarP(&DebugFlag, "debug", "d", false, "Run with debugging messages enabled.")
|
||||
rootCmd.PersistentFlags().IntVar(&LogLevel, "loglevel", wwlog.INFO, "Set log level to given string")
|
||||
_ = rootCmd.PersistentFlags().MarkHidden("loglevel")
|
||||
rootCmd.PersistentFlags().StringVar(&WarewulfConfArg, "warewulfconf", "", "Set the warewulf configuration file")
|
||||
rootCmd.PersistentFlags().BoolVar(&AllowEmptyConf, "emptyconf", false, "Allow empty configuration")
|
||||
_ = rootCmd.PersistentFlags().MarkHidden("emptyconf")
|
||||
rootCmd.SetUsageTemplate(help.UsageTemplate)
|
||||
rootCmd.SetHelpTemplate(help.HelpTemplate)
|
||||
|
||||
rootCmd.AddCommand(overlay.GetCommand())
|
||||
rootCmd.AddCommand(container.GetCommand())
|
||||
rootCmd.AddCommand(node.GetCommand())
|
||||
@@ -52,6 +57,7 @@ func init() {
|
||||
rootCmd.AddCommand(server.GetCommand())
|
||||
rootCmd.AddCommand(version.GetCommand())
|
||||
rootCmd.AddCommand(ssh.GetCommand())
|
||||
rootCmd.AddCommand(genconf.GetCommand())
|
||||
}
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
@@ -59,7 +65,7 @@ func GetRootCommand() *cobra.Command {
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
func rootPersistentPreRunE(cmd *cobra.Command, args []string) error {
|
||||
func rootPersistentPreRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
if DebugFlag {
|
||||
wwlog.SetLogLevel(wwlog.DEBUG)
|
||||
} else if verboseArg {
|
||||
@@ -70,21 +76,17 @@ func rootPersistentPreRunE(cmd *cobra.Command, args []string) error {
|
||||
if LogLevel != wwlog.INFO {
|
||||
wwlog.SetLogLevel(LogLevel)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// External functions not used by the wwctl command line
|
||||
|
||||
// Generate Bash completion file
|
||||
func GenBashCompletion(w io.Writer) error {
|
||||
return rootCmd.GenBashCompletion(w)
|
||||
}
|
||||
|
||||
// Generate man pages
|
||||
func GenManTree(fileName string) error {
|
||||
header := &doc.GenManHeader{
|
||||
Title: "WWCTL",
|
||||
Section: "1",
|
||||
conf := warewulfconf.New()
|
||||
if !AllowEmptyConf && !conf.Initialized() {
|
||||
if WarewulfConfArg != "" {
|
||||
err = conf.ReadConf(WarewulfConfArg)
|
||||
} else if os.Getenv("WAREWULFCONF") != "" {
|
||||
err = conf.ReadConf(os.Getenv("WAREWULFCONF"))
|
||||
} else {
|
||||
err = conf.ReadConf(warewulfconf.ConfigFile)
|
||||
}
|
||||
} else {
|
||||
err = conf.SetDynamicDefaults()
|
||||
}
|
||||
return doc.GenManTree(rootCmd, header, fileName)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -10,10 +10,7 @@ import (
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
|
||||
if SetForeground {
|
||||
conf, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not read Warewulf configuration file")
|
||||
}
|
||||
conf := warewulfconf.New()
|
||||
conf.Warewulf.Syslog = false
|
||||
return errors.Wrap(warewulfd.RunServer(), "failed to start Warewulf server")
|
||||
} else {
|
||||
|
||||
@@ -290,11 +290,7 @@ func NodeStatus(nodeNames []string) (nodeStatusResponse *wwapiv1.NodeStatusRespo
|
||||
Nodes map[string]*nodeStatusInternal `json:"nodes"`
|
||||
}
|
||||
|
||||
controller, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
wwlog.Error("%s", err)
|
||||
return
|
||||
}
|
||||
controller := warewulfconf.New()
|
||||
|
||||
if controller.Ipaddr == "" {
|
||||
err = fmt.Errorf("the Warewulf Server IP Address is not properly configured")
|
||||
|
||||
@@ -2,33 +2,35 @@ package batch
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
/* Submits 10 jobs into a pool that supports 2 simultaneous jobs, and
|
||||
tests that only two of the jobs ran at a time by capturing the time
|
||||
that they ran and comparing against the start time. */
|
||||
func TestBatchPool (t *testing.T) {
|
||||
pool := New(2)
|
||||
var times []time.Time
|
||||
for i := 0; i <= 10; i++ {
|
||||
pool.Submit(func() {
|
||||
times = append(times, time.Now())
|
||||
time.Sleep(1 * time.Second)
|
||||
})
|
||||
}
|
||||
startTime := time.Now()
|
||||
pool.Run()
|
||||
assert.Equal(t, 0 * time.Second, times[0].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 0 * time.Second, times[1].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 1 * time.Second, times[2].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 1 * time.Second, times[3].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 2 * time.Second, times[4].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 2 * time.Second, times[5].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 3 * time.Second, times[6].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 3 * time.Second, times[7].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 4 * time.Second, times[8].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 4 * time.Second, times[9].Sub(startTime).Round(time.Second))
|
||||
/*
|
||||
Submits 10 jobs into a pool that supports 2 simultaneous jobs, and
|
||||
|
||||
tests that only two of the jobs ran at a time by capturing the time
|
||||
that they ran and comparing against the start time.
|
||||
*/
|
||||
func TestBatchPool(t *testing.T) {
|
||||
/*
|
||||
pool := New(2)
|
||||
var times []time.Time
|
||||
for i := 0; i <= 10; i++ {
|
||||
pool.Submit(func() {
|
||||
times = append(times, time.Now())
|
||||
time.Sleep(1 * time.Second)
|
||||
})
|
||||
}
|
||||
startTime := time.Now()
|
||||
pool.Run()
|
||||
assert.Equal(t, 0 * time.Second, times[0].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 0 * time.Second, times[1].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 1 * time.Second, times[2].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 1 * time.Second, times[3].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 2 * time.Second, times[4].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 2 * time.Second, times[5].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 3 * time.Second, times[6].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 3 * time.Second, times[7].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 4 * time.Second, times[8].Sub(startTime).Round(time.Second))
|
||||
assert.Equal(t, 4 * time.Second, times[9].Sub(startTime).Round(time.Second))
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
package buildconfig
|
||||
|
||||
import "github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
|
||||
const WWVer = 43
|
||||
|
||||
var (
|
||||
bindir string = "UNDEF"
|
||||
sysconfdir string = "UNDEF"
|
||||
localstatedir string = "UNDEF"
|
||||
srvdir string = "UNDEF"
|
||||
tftpdir string = "UNDEF"
|
||||
firewallddir string = "UNDEF"
|
||||
systemddir string = "UNDEF"
|
||||
wwoverlaydir string = "UNDEF"
|
||||
wwchrootdir string = "UNDEF"
|
||||
wwprovisiondir string = "UNDEF"
|
||||
version string = "UNDEF"
|
||||
release string = "UNDEF"
|
||||
wwclientdir string = "UNDEF"
|
||||
datadir string = "UNDEF"
|
||||
tmpdir string = "UNDEF"
|
||||
)
|
||||
|
||||
func BINDIR() string {
|
||||
wwlog.Debug("BINDIR = '%s'", bindir)
|
||||
return bindir
|
||||
}
|
||||
|
||||
func DATADIR() string {
|
||||
wwlog.Debug("DATADIR = '%s'", datadir)
|
||||
return datadir
|
||||
}
|
||||
|
||||
func SYSCONFDIR() string {
|
||||
wwlog.Debug("SYSCONFDIR = '%s'", sysconfdir)
|
||||
return sysconfdir
|
||||
}
|
||||
|
||||
func LOCALSTATEDIR() string {
|
||||
wwlog.Debug("LOCALSTATEDIR = '%s'", localstatedir)
|
||||
return localstatedir
|
||||
}
|
||||
|
||||
func SRVDIR() string {
|
||||
wwlog.Debug("SRVDIR = '%s'", srvdir)
|
||||
return srvdir
|
||||
}
|
||||
|
||||
func TFTPDIR() string {
|
||||
wwlog.Debug("TFTPDIR = '%s'", tftpdir)
|
||||
return tftpdir
|
||||
}
|
||||
|
||||
func FIREWALLDDIR() string {
|
||||
wwlog.Debug("FIREWALLDDIR = '%s'", firewallddir)
|
||||
return firewallddir
|
||||
}
|
||||
|
||||
func SYSTEMDDIR() string {
|
||||
wwlog.Debug("SYSTEMDDIR = '%s'", systemddir)
|
||||
return systemddir
|
||||
}
|
||||
|
||||
func WWOVERLAYDIR() string {
|
||||
wwlog.Debug("WWOVERLAYDIR = '%s'", wwoverlaydir)
|
||||
return wwoverlaydir
|
||||
}
|
||||
|
||||
func WWCHROOTDIR() string {
|
||||
wwlog.Debug("WWCHROOTDIR = '%s'", wwchrootdir)
|
||||
return wwchrootdir
|
||||
}
|
||||
|
||||
func WWPROVISIONDIR() string {
|
||||
wwlog.Debug("WWPROVISIONDIR = '%s'", wwprovisiondir)
|
||||
return wwprovisiondir
|
||||
}
|
||||
|
||||
func VERSION() string {
|
||||
wwlog.Debug("VERSION = '%s'", version)
|
||||
return version
|
||||
}
|
||||
|
||||
func RELEASE() string {
|
||||
wwlog.Debug("RELEASE = '%s'", release)
|
||||
return release
|
||||
}
|
||||
|
||||
func WWCLIENTDIR() string {
|
||||
wwlog.Debug("WWCLIENTDIR = '%s'", wwclientdir)
|
||||
return wwclientdir
|
||||
}
|
||||
|
||||
func TMPDIR() string {
|
||||
wwlog.Debug("TMPDIR = '%s'", tmpdir)
|
||||
return tmpdir
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package buildconfig
|
||||
|
||||
func init() {
|
||||
bindir = "@BINDIR@"
|
||||
sysconfdir = "@SYSCONFDIR@"
|
||||
datadir = "@DATADIR@"
|
||||
localstatedir = "@LOCALSTATEDIR@"
|
||||
srvdir = "@SRVDIR@"
|
||||
tftpdir = "@TFTPDIR@"
|
||||
firewallddir = "@FIREWALLDDIR@"
|
||||
systemddir = "@SYSTEMDDIR@"
|
||||
wwoverlaydir = "@WWOVERLAYDIR@"
|
||||
wwchrootdir = "@WWCHROOTDIR@"
|
||||
wwprovisiondir = "@WWPROVISIONDIR@"
|
||||
version = "@VERSION@"
|
||||
release = "@RELEASE@"
|
||||
wwclientdir = "@WWCLIENTDIR@"
|
||||
tmpdir = "@TMPDIR@"
|
||||
}
|
||||
@@ -15,13 +15,9 @@ import (
|
||||
Configures the dhcpd server, when show is set to false, else the
|
||||
dhcp configuration is checked.
|
||||
*/
|
||||
func Dhcp() error {
|
||||
func Dhcp() (err error) {
|
||||
|
||||
controller, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
wwlog.Error("%s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
controller := warewulfconf.New()
|
||||
|
||||
if !controller.Dhcp.Enabled {
|
||||
wwlog.Info("This system is not configured as a Warewulf DHCP controller")
|
||||
@@ -51,5 +47,5 @@ func Dhcp() error {
|
||||
return errors.Wrap(err, "failed to start")
|
||||
}
|
||||
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package configure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
@@ -17,18 +16,11 @@ nfs server.
|
||||
*/
|
||||
func NFS() error {
|
||||
|
||||
controller, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
wwlog.Error("%s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
controller := warewulfconf.New()
|
||||
|
||||
if controller.Nfs.Enabled {
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
if controller.Warewulf.EnableHostOverlay {
|
||||
err = overlay.BuildHostOverlay()
|
||||
err := overlay.BuildHostOverlay()
|
||||
if err != nil {
|
||||
wwlog.Warn("host overlay could not be built: %s", err)
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -14,10 +14,10 @@ import (
|
||||
func SSH() error {
|
||||
if os.Getuid() == 0 {
|
||||
fmt.Printf("Updating system keys\n")
|
||||
conf := warewulfconf.New()
|
||||
wwkeydir := path.Join(conf.Paths.Sysconfdir, "warewulf/keys") + "/"
|
||||
|
||||
wwkeydir := path.Join(buildconfig.SYSCONFDIR(), "warewulf/keys") + "/"
|
||||
|
||||
err := os.MkdirAll(path.Join(buildconfig.SYSCONFDIR(), "warewulf/keys"), 0755)
|
||||
err := os.MkdirAll(path.Join(conf.Paths.Sysconfdir, "warewulf/keys"), 0755)
|
||||
if err != nil {
|
||||
wwlog.Error("Could not create base directory: %s", err)
|
||||
os.Exit(1)
|
||||
|
||||
@@ -5,21 +5,16 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func TFTP() error {
|
||||
var tftpdir string = path.Join(buildconfig.TFTPDIR(), "warewulf")
|
||||
controller, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
wwlog.Error("%s", err)
|
||||
return err
|
||||
}
|
||||
controller := warewulfconf.New()
|
||||
var tftpdir string = path.Join(controller.Paths.Tftpdir, "warewulf")
|
||||
|
||||
err = os.MkdirAll(tftpdir, 0755)
|
||||
err := os.MkdirAll(tftpdir, 0755)
|
||||
if err != nil {
|
||||
wwlog.Error("%s", err)
|
||||
return err
|
||||
@@ -32,7 +27,7 @@ func TFTP() error {
|
||||
continue
|
||||
}
|
||||
copyCheck[f] = true
|
||||
err = util.SafeCopyFile(path.Join(buildconfig.DATADIR(), f), path.Join(tftpdir, f))
|
||||
err = util.SafeCopyFile(path.Join(controller.Paths.Datadir, f), path.Join(tftpdir, f))
|
||||
if err != nil {
|
||||
wwlog.Warn("ipxe binary could not be copied, booting may not work: %s", err)
|
||||
}
|
||||
|
||||
@@ -3,11 +3,12 @@ package container
|
||||
import (
|
||||
"path"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
)
|
||||
|
||||
func SourceParentDir() string {
|
||||
return buildconfig.WWCHROOTDIR()
|
||||
conf := warewulfconf.New()
|
||||
return conf.Paths.WWChrootdir
|
||||
}
|
||||
|
||||
func SourceDir(name string) string {
|
||||
@@ -19,7 +20,8 @@ func RootFsDir(name string) string {
|
||||
}
|
||||
|
||||
func ImageParentDir() string {
|
||||
return path.Join(buildconfig.WWPROVISIONDIR(), "container/")
|
||||
conf := warewulfconf.New()
|
||||
return path.Join(conf.Paths.WWProvisiondir, "container/")
|
||||
}
|
||||
|
||||
func ImageFile(name string) string {
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
@@ -28,7 +28,8 @@ var (
|
||||
)
|
||||
|
||||
func KernelImageTopDir() string {
|
||||
return path.Join(buildconfig.WWPROVISIONDIR(), "kernel")
|
||||
conf := warewulfconf.New()
|
||||
return path.Join(conf.Paths.WWProvisiondir, "kernel")
|
||||
}
|
||||
|
||||
func KernelImage(kernelName string) string {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
@@ -16,6 +16,8 @@ import (
|
||||
var ConfigFile string
|
||||
var DefaultConfig string
|
||||
|
||||
var cachedDB NodeYaml
|
||||
|
||||
// used as fallback if DefaultConfig can't be read
|
||||
var FallBackConf = `---
|
||||
defaultnode:
|
||||
@@ -37,15 +39,25 @@ defaultnode:
|
||||
netmask: 255.255.255.0`
|
||||
|
||||
func init() {
|
||||
conf := warewulfconf.New()
|
||||
if ConfigFile == "" {
|
||||
ConfigFile = path.Join(buildconfig.SYSCONFDIR(), "warewulf/nodes.conf")
|
||||
ConfigFile = path.Join(conf.Paths.Sysconfdir, "warewulf/nodes.conf")
|
||||
}
|
||||
if DefaultConfig == "" {
|
||||
DefaultConfig = path.Join(buildconfig.SYSCONFDIR(), "warewulf/defaults.conf")
|
||||
DefaultConfig = path.Join(conf.Paths.Datadir, "warewulf/defaults.conf")
|
||||
}
|
||||
cachedDB.current = false
|
||||
cachedDB.persist = true
|
||||
}
|
||||
|
||||
/*
|
||||
Creates a new nodeDb object from the actual configuration
|
||||
*/
|
||||
func New() (NodeYaml, error) {
|
||||
if cachedDB.current {
|
||||
wwlog.Debug("Returning cached object")
|
||||
return cachedDB, nil
|
||||
}
|
||||
var ret NodeYaml
|
||||
|
||||
wwlog.Verbose("Opening node configuration file: %s", ConfigFile)
|
||||
@@ -61,10 +73,40 @@ func New() (NodeYaml, error) {
|
||||
}
|
||||
|
||||
wwlog.Debug("Returning node object")
|
||||
|
||||
cachedDB = ret
|
||||
cachedDB.current = true
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Creates a database object from a given buffer, always create
|
||||
a new object, never return the cached one.
|
||||
*/
|
||||
func TestNew(buffer []byte) (db NodeYaml, err error) {
|
||||
db.NodeProfiles = make(map[string]*NodeConf)
|
||||
db.Nodes = make(map[string]*NodeConf)
|
||||
err = yaml.Unmarshal(buffer, &db)
|
||||
db.persist = false
|
||||
cachedDB = db
|
||||
cachedDB.current = true
|
||||
wwlog.Debug("Created cached object")
|
||||
return
|
||||
}
|
||||
|
||||
func (config *NodeYaml) DBDump() (buffer []byte) {
|
||||
for _, n := range config.Nodes {
|
||||
n.Flatten()
|
||||
}
|
||||
for _, p := range config.NodeProfiles {
|
||||
p.Flatten()
|
||||
}
|
||||
buffer, err := yaml.Marshal(config)
|
||||
if err != nil {
|
||||
wwlog.Warn("porblems on dumping nodedb: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Get all the nodes of a configuration. This function also merges
|
||||
the nodes with the given profiles and set the default values
|
||||
@@ -72,12 +114,6 @@ for every node
|
||||
*/
|
||||
func (config *NodeYaml) FindAllNodes() ([]NodeInfo, error) {
|
||||
var ret []NodeInfo
|
||||
/*
|
||||
wwconfig, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
*/
|
||||
var defConf map[string]*NodeConf
|
||||
wwlog.Verbose("Opening defaults from file failed %s\n", DefaultConfig)
|
||||
defData, err := os.ReadFile(DefaultConfig)
|
||||
|
||||
@@ -10,6 +10,8 @@ type NodeYaml struct {
|
||||
WWInternal int `yaml:"WW_INTERNAL"`
|
||||
NodeProfiles map[string]*NodeConf
|
||||
Nodes map[string]*NodeConf
|
||||
current bool
|
||||
persist bool
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -382,3 +382,30 @@ func GetByName(node interface{}, name string) (string, error) {
|
||||
myEntry := entryField.Interface().(Entry)
|
||||
return myEntry.Get(), nil
|
||||
}
|
||||
|
||||
/*
|
||||
Check if the Netdev is empty, so has no values set
|
||||
*/
|
||||
func (dev *NetDevs) Empty() bool {
|
||||
if dev == nil {
|
||||
return true
|
||||
}
|
||||
varType := reflect.TypeOf(*dev)
|
||||
varVal := reflect.ValueOf(*dev)
|
||||
if varVal.IsZero() {
|
||||
return true
|
||||
}
|
||||
for i := 0; i < varType.NumField(); i++ {
|
||||
if varType.Field(i).Type.Kind() == reflect.String && !varVal.Field(i).IsZero() {
|
||||
val := varVal.Field(i).Interface().(string)
|
||||
if val != "" {
|
||||
return false
|
||||
}
|
||||
} else if varType.Field(i).Type == reflect.TypeOf(map[string]string{}) {
|
||||
if len(varVal.Field(i).Interface().(map[string]string)) != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
32
internal/pkg/node/methods_test.go
Normal file
32
internal/pkg/node/methods_test.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package node
|
||||
|
||||
import "testing"
|
||||
|
||||
func Test_Empty(t *testing.T) {
|
||||
var netdev NetDevs
|
||||
var netdevPtr *NetDevs
|
||||
|
||||
t.Run("test for empty", func(t *testing.T) {
|
||||
if netdev.Empty() != true {
|
||||
t.Errorf("netdev must be empty")
|
||||
}
|
||||
})
|
||||
t.Run("test for non empty", func(t *testing.T) {
|
||||
netdev.Device = "foo"
|
||||
if netdev.Empty() == true {
|
||||
t.Errorf("netdev must be non empty")
|
||||
}
|
||||
})
|
||||
t.Run("test for nil pointer", func(t *testing.T) {
|
||||
if netdevPtr.Empty() != true {
|
||||
t.Errorf("netdev must be empty")
|
||||
}
|
||||
})
|
||||
t.Run("test for pointer assigned", func(t *testing.T) {
|
||||
netdev.Ipaddr = "10.10.10.1"
|
||||
netdevPtr = &netdev
|
||||
if netdevPtr.Empty() == true {
|
||||
t.Errorf("netdev must be empty")
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -127,7 +127,10 @@ func (config *NodeYaml) Persist() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Can't persist for unit tests
|
||||
if !config.persist {
|
||||
return err
|
||||
}
|
||||
file, err := os.OpenFile(ConfigFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
wwlog.Error("%s", err)
|
||||
|
||||
@@ -5,11 +5,12 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
)
|
||||
|
||||
func OverlaySourceTopDir() string {
|
||||
return buildconfig.WWOVERLAYDIR()
|
||||
conf := warewulfconf.New()
|
||||
return conf.Paths.WWOverlaydir
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -30,5 +31,6 @@ func OverlaySourceDir(overlayName string) string {
|
||||
Returns the overlay name of the image for a given node
|
||||
*/
|
||||
func OverlayImage(nodeName string, overlayName []string) string {
|
||||
return path.Join(buildconfig.WWPROVISIONDIR(), "overlays/", nodeName, strings.Join(overlayName, "-")+".img")
|
||||
conf := warewulfconf.New()
|
||||
return path.Join(conf.Paths.WWProvisiondir, "overlays/", nodeName, strings.Join(overlayName, "-")+".img")
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ type TemplateStruct struct {
|
||||
Nfs warewulfconf.NfsConf
|
||||
Warewulf warewulfconf.WarewulfConf
|
||||
Tftp warewulfconf.TftpConf
|
||||
Paths warewulfconf.BuildConfig
|
||||
AllNodes []node.NodeInfo
|
||||
node.NodeConf
|
||||
// backward compatiblity
|
||||
@@ -43,11 +44,7 @@ Initialize an TemplateStruct with the given node.NodeInfo
|
||||
*/
|
||||
func InitStruct(nodeInfo node.NodeInfo) TemplateStruct {
|
||||
var tstruct TemplateStruct
|
||||
controller, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
wwlog.Error("%s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
controller := warewulfconf.New()
|
||||
nodeDB, err := node.New()
|
||||
if err != nil {
|
||||
wwlog.Error("%s", err)
|
||||
|
||||
@@ -6,20 +6,20 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/container"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
/*
|
||||
Reads a file file from the host fs. If the file has nor '/' prefix
|
||||
the path is relative to SYSCONFDIR.
|
||||
Templates in the file are no evaluated.
|
||||
the path is relative to Paths.SysconfdirTemplates in the file are no evaluated.
|
||||
*/
|
||||
func templateFileInclude(inc string) string {
|
||||
conf := warewulfconf.New()
|
||||
if !strings.HasPrefix(inc, "/") {
|
||||
inc = path.Join(buildconfig.SYSCONFDIR(), "warewulf", inc)
|
||||
inc = path.Join(conf.Paths.Sysconfdir, "warewulf", inc)
|
||||
}
|
||||
wwlog.Debug("Including file into template: %s", inc)
|
||||
content, err := os.ReadFile(inc)
|
||||
@@ -35,8 +35,9 @@ is the file to read, the second the abort string
|
||||
Templates in the file are no evaluated.
|
||||
*/
|
||||
func templateFileBlock(inc string, abortStr string) (string, error) {
|
||||
conf := warewulfconf.New()
|
||||
if !strings.HasPrefix(inc, "/") {
|
||||
inc = path.Join(buildconfig.SYSCONFDIR(), "warewulf", inc)
|
||||
inc = path.Join(conf.Paths.Sysconfdir, "warewulf", inc)
|
||||
}
|
||||
wwlog.Debug("Including file block into template: %s", inc)
|
||||
readFile, err := os.Open(inc)
|
||||
|
||||
@@ -4,14 +4,15 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||
)
|
||||
|
||||
/*
|
||||
Return the version of wwctl
|
||||
*/
|
||||
func GetVersion() string {
|
||||
return fmt.Sprintf("%s-%s", buildconfig.VERSION(), buildconfig.RELEASE())
|
||||
conf := warewulfconf.New()
|
||||
return fmt.Sprintf("%s-%s", conf.Paths.Version, conf.Paths.Release)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
18
internal/pkg/warewulfconf/buildconfig.go.in
Normal file
18
internal/pkg/warewulfconf/buildconfig.go.in
Normal file
@@ -0,0 +1,18 @@
|
||||
package warewulfconf
|
||||
|
||||
type BuildConfig struct {
|
||||
Bindir string `default:"@BINDIR@"`
|
||||
Sysconfdir string `default:"@SYSCONFDIR@"`
|
||||
Datadir string `default:"@DATADIR@"`
|
||||
Localstatedir string `default:"@LOCALSTATEDIR@"`
|
||||
Srvdir string `default:"@SRVDIR@"`
|
||||
Tftpdir string `default:"@TFTPDIR@"`
|
||||
Firewallddir string `default:"@FIREWALLDDIR@"`
|
||||
Systemddir string `default:"@SYSTEMDDIR@"`
|
||||
WWOverlaydir string `default:"@WWOVERLAYDIR@"`
|
||||
WWChrootdir string `default:"@WWCHROOTDIR@"`
|
||||
WWProvisiondir string `default:"@WWPROVISIONDIR@"`
|
||||
Version string `default:"@VERSION@"`
|
||||
Release string `default:"@RELEASE@"`
|
||||
WWClientdir string `default:"@WWCLIENTDIR@"`
|
||||
}
|
||||
@@ -1,17 +1,14 @@
|
||||
package warewulfconf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/brotherpowers/ipsubnet"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/creasty/defaults"
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
@@ -19,97 +16,141 @@ var cachedConf ControllerConf
|
||||
|
||||
var ConfigFile string
|
||||
|
||||
func init() {
|
||||
if ConfigFile == "" {
|
||||
ConfigFile = path.Join(buildconfig.SYSCONFDIR(), "warewulf/warewulf.conf")
|
||||
/*
|
||||
Creates a new empty ControllerConf object, returns a cached
|
||||
one if called in a nother context.
|
||||
*/
|
||||
func New() (conf ControllerConf) {
|
||||
// NOTE: This function can be called before any log level is set
|
||||
// so using wwlog.Verbose or wwlog.Debug won't work
|
||||
if !cachedConf.current {
|
||||
conf.Warewulf = new(WarewulfConf)
|
||||
conf.Dhcp = new(DhcpConf)
|
||||
conf.Tftp = new(TftpConf)
|
||||
conf.Nfs = new(NfsConf)
|
||||
conf.Paths = new(BuildConfig)
|
||||
_ = defaults.Set(&conf)
|
||||
cachedConf = conf
|
||||
cachedConf.readConf = false
|
||||
cachedConf.current = true
|
||||
} else {
|
||||
// If cached struct isn't empty, use it as the return value
|
||||
conf = cachedConf
|
||||
}
|
||||
return conf
|
||||
}
|
||||
|
||||
func New() (ControllerConf, error) {
|
||||
var ret ControllerConf
|
||||
var warewulfconf WarewulfConf
|
||||
var dhpdconf DhcpConf
|
||||
var tftpconf TftpConf
|
||||
var nfsConf NfsConf
|
||||
ret.Warewulf = &warewulfconf
|
||||
ret.Dhcp = &dhpdconf
|
||||
ret.Tftp = &tftpconf
|
||||
ret.Nfs = &nfsConf
|
||||
err := defaults.Set(&ret)
|
||||
/*
|
||||
Populate the configuration with the values from the configuration file.
|
||||
*/
|
||||
func (conf *ControllerConf) ReadConf(confFileName string) (err error) {
|
||||
wwlog.Debug("Reading warewulf.conf from: %s", confFileName)
|
||||
fileHandle, err := os.ReadFile(confFileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return conf.Read(fileHandle)
|
||||
}
|
||||
|
||||
/*
|
||||
Populate the configuration with the values from the given yaml information
|
||||
*/
|
||||
func (conf *ControllerConf) Read(data []byte) (err error) {
|
||||
// ipxe binaries are merged not overwritten, store defaults separate
|
||||
defIpxe := make(map[string]string)
|
||||
for k, v := range ret.Tftp.IpxeBinaries {
|
||||
for k, v := range conf.Tftp.IpxeBinaries {
|
||||
defIpxe[k] = v
|
||||
delete(ret.Tftp.IpxeBinaries, k)
|
||||
delete(conf.Tftp.IpxeBinaries, k)
|
||||
}
|
||||
err = yaml.Unmarshal(data, &conf)
|
||||
if err != nil {
|
||||
wwlog.Error("Could initialize default variables")
|
||||
return ret, err
|
||||
return
|
||||
}
|
||||
// Check if cached config is old before re-reading config file
|
||||
if !cachedConf.current {
|
||||
wwlog.Debug("Opening Warewulf configuration file: %s", ConfigFile)
|
||||
data, err := os.ReadFile(ConfigFile)
|
||||
if err != nil {
|
||||
wwlog.Warn("Error reading Warewulf configuration file")
|
||||
}
|
||||
|
||||
wwlog.Debug("Unmarshaling the Warewulf configuration")
|
||||
err = yaml.Unmarshal(data, &ret)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
if len(ret.Tftp.IpxeBinaries) == 0 {
|
||||
ret.Tftp.IpxeBinaries = defIpxe
|
||||
}
|
||||
if ret.Ipaddr == "" || ret.Netmask == "" {
|
||||
conn, error := net.Dial("udp", "8.8.8.8:80")
|
||||
if error != nil {
|
||||
return ret, err
|
||||
}
|
||||
defer conn.Close()
|
||||
localIp := conn.LocalAddr().(*net.UDPAddr)
|
||||
if ret.Ipaddr == "" {
|
||||
ret.Ipaddr = localIp.IP.String()
|
||||
wwlog.Warn("IP address is not configured in warewulfd.conf, using %s", ret.Ipaddr)
|
||||
}
|
||||
if ret.Netmask == "" {
|
||||
mask := localIp.IP.DefaultMask()
|
||||
ret.Netmask = fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3])
|
||||
wwlog.Warn("Netmask address is not configured in warewulfd.conf, using %s", ret.Netmask)
|
||||
}
|
||||
}
|
||||
|
||||
if ret.Network == "" {
|
||||
mask := net.IPMask(net.ParseIP(ret.Netmask).To4())
|
||||
size, _ := mask.Size()
|
||||
|
||||
sub := ipsubnet.SubnetCalculator(ret.Ipaddr, size)
|
||||
|
||||
ret.Network = sub.GetNetworkPortion()
|
||||
}
|
||||
// check validity of ipv6 net
|
||||
if ret.Ipaddr6 != "" {
|
||||
_, ipv6net, err := net.ParseCIDR(ret.Ipaddr6)
|
||||
if err != nil {
|
||||
wwlog.Error("Invalid ipv6 address specified, mut be CIDR notation: %s", ret.Ipaddr6)
|
||||
return ret, errors.New("invalid ipv6 network")
|
||||
}
|
||||
if msize, _ := ipv6net.Mask.Size(); msize > 64 {
|
||||
wwlog.Error("ipv6 mask size must be smaller than 64")
|
||||
return ret, errors.New("invalid ipv6 network size")
|
||||
}
|
||||
}
|
||||
|
||||
wwlog.Debug("Returning warewulf config object")
|
||||
cachedConf = ret
|
||||
cachedConf.current = true
|
||||
|
||||
} else {
|
||||
wwlog.Debug("Returning cached warewulf config object")
|
||||
// If cached struct isn't empty, use it as the return value
|
||||
ret = cachedConf
|
||||
err = conf.SetDynamicDefaults()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
if len(conf.Tftp.IpxeBinaries) == 0 {
|
||||
conf.Tftp.IpxeBinaries = defIpxe
|
||||
}
|
||||
cachedConf = *conf
|
||||
cachedConf.current = true
|
||||
cachedConf.readConf = true
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Set the runtime defaults like IP address of running system to the config
|
||||
*/
|
||||
func (conf *ControllerConf) SetDynamicDefaults() (err error) {
|
||||
if conf.Ipaddr == "" || conf.Netmask == "" || conf.Network == "" {
|
||||
var mask net.IPMask
|
||||
var network *net.IPNet
|
||||
var ipaddr net.IP
|
||||
|
||||
if conf.Ipaddr == "" {
|
||||
wwlog.Verbose("Configuration has no valid network, going to dynamic values")
|
||||
conn, _ := net.Dial("udp", "8.8.8.8:80")
|
||||
defer conn.Close()
|
||||
ipaddr = conn.LocalAddr().(*net.UDPAddr).IP
|
||||
mask = ipaddr.DefaultMask()
|
||||
sz, _ := mask.Size()
|
||||
conf.Ipaddr = ipaddr.String() + fmt.Sprintf("/%d", sz)
|
||||
}
|
||||
_, network, err = net.ParseCIDR(conf.Ipaddr)
|
||||
if err == nil {
|
||||
mask = network.Mask
|
||||
} else {
|
||||
return errors.Wrap(err, "Couldn't parse IP address")
|
||||
}
|
||||
if conf.Netmask == "" {
|
||||
conf.Netmask = fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3])
|
||||
wwlog.Verbose("Netmask address is not configured in warewulf.conf, using %s", conf.Netmask)
|
||||
}
|
||||
if conf.Network == "" {
|
||||
conf.Network = network.IP.String()
|
||||
wwlog.Verbose("Network is not configured in warewulf.conf, using %s", conf.Network)
|
||||
}
|
||||
}
|
||||
if conf.Dhcp.RangeStart == "" && conf.Dhcp.RangeEnd == "" {
|
||||
start := net.ParseIP(conf.Network).To4()
|
||||
start[3] += 1
|
||||
if start.Equal(net.ParseIP(conf.Ipaddr)) {
|
||||
start[3] += 1
|
||||
}
|
||||
conf.Dhcp.RangeStart = start.String()
|
||||
wwlog.Verbose("dhpd start is not configured in warewulf.conf, using %s", conf.Dhcp.RangeStart)
|
||||
sz, _ := net.IPMask(net.ParseIP(conf.Netmask).To4()).Size()
|
||||
range_end := (1 << (32 - sz)) / 8
|
||||
if range_end > 127 {
|
||||
range_end = 127
|
||||
}
|
||||
end := net.ParseIP(conf.Network).To4()
|
||||
end[3] += byte(range_end)
|
||||
conf.Dhcp.RangeEnd = end.String()
|
||||
wwlog.Verbose("dhpd end is not configured in warewulf.conf, using %s", conf.Dhcp.RangeEnd)
|
||||
|
||||
}
|
||||
// check validity of ipv6 net
|
||||
if conf.Ipaddr6 != "" {
|
||||
_, ipv6net, err := net.ParseCIDR(conf.Ipaddr6)
|
||||
if err != nil {
|
||||
wwlog.Error("Invalid ipv6 address specified, mut be CIDR notation: %s", conf.Ipaddr6)
|
||||
return errors.New("invalid ipv6 network")
|
||||
}
|
||||
if msize, _ := ipv6net.Mask.Size(); msize > 64 {
|
||||
wwlog.Error("ipv6 mask size must be smaller than 64")
|
||||
return errors.New("invalid ipv6 network size")
|
||||
}
|
||||
}
|
||||
cachedConf = *conf
|
||||
cachedConf.current = true
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Return if configuration was read from disk
|
||||
*/
|
||||
func (conf *ControllerConf) Initialized() bool {
|
||||
return conf.readConf
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ package warewulfconf
|
||||
|
||||
import (
|
||||
"github.com/creasty/defaults"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
type ControllerConf struct {
|
||||
@@ -19,8 +17,10 @@ type ControllerConf struct {
|
||||
Dhcp *DhcpConf `yaml:"dhcp"`
|
||||
Tftp *TftpConf `yaml:"tftp"`
|
||||
Nfs *NfsConf `yaml:"nfs"`
|
||||
MountsContainer []*MountEntry `yaml:"container mounts"`
|
||||
MountsContainer []*MountEntry `yaml:"container mounts" default:"[{\"source\": \"/etc/resolv.conf\", \"dest\": \"/etc/resolv.conf\"}]"`
|
||||
Paths *BuildConfig `yaml:"paths"`
|
||||
current bool
|
||||
readConf bool
|
||||
}
|
||||
|
||||
type WarewulfConf struct {
|
||||
@@ -79,19 +79,9 @@ func (s *NfsConf) Unmarshal(unmarshal func(interface{}) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
if !util.IsFile(ConfigFile) {
|
||||
wwlog.Error("Configuration file not found: %s", ConfigFile)
|
||||
// fail silently as this also called by bash_completion
|
||||
}
|
||||
_, err := New()
|
||||
if err != nil {
|
||||
wwlog.Error("Could not read Warewulf configuration file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Waste processor cycles to make code more readable
|
||||
|
||||
func DataStore() string {
|
||||
_ = New()
|
||||
return cachedConf.Warewulf.DataStore
|
||||
}
|
||||
|
||||
@@ -23,6 +23,23 @@ const (
|
||||
|
||||
var loginit bool
|
||||
|
||||
// allow to run without daemon for tests
|
||||
var nodaemon bool
|
||||
|
||||
func init() {
|
||||
nodaemon = false
|
||||
}
|
||||
|
||||
// run without daemon
|
||||
func SetNoDaemon() {
|
||||
nodaemon = true
|
||||
}
|
||||
|
||||
// run with daemon
|
||||
func SetDaemon() {
|
||||
nodaemon = false
|
||||
}
|
||||
|
||||
func DaemonFormatter(logLevel int, rec *wwlog.LogRecord) string {
|
||||
return "[" + rec.Time.Format(time.UnixDate) + "] " + wwlog.DefaultFormatter(logLevel, rec)
|
||||
}
|
||||
@@ -44,10 +61,7 @@ func DaemonInitLogging() error {
|
||||
wwlog.SetLogLevel(wwlog.SERV)
|
||||
}
|
||||
|
||||
conf, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not read Warewulf configuration file")
|
||||
}
|
||||
conf := warewulfconf.New()
|
||||
|
||||
if conf.Warewulf.Syslog {
|
||||
|
||||
@@ -69,6 +83,10 @@ func DaemonInitLogging() error {
|
||||
}
|
||||
|
||||
func DaemonStart() error {
|
||||
if nodaemon {
|
||||
return nil
|
||||
}
|
||||
|
||||
if os.Getenv("WAREWULFD_BACKGROUND") == "1" {
|
||||
err := RunServer()
|
||||
if err != nil {
|
||||
@@ -119,6 +137,10 @@ func DaemonStart() error {
|
||||
}
|
||||
|
||||
func DaemonStatus() error {
|
||||
if nodaemon {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !util.IsFile(WAREWULFD_PIDFILE) {
|
||||
return errors.New("Warewulf server is not running")
|
||||
}
|
||||
@@ -145,6 +167,9 @@ func DaemonStatus() error {
|
||||
}
|
||||
|
||||
func DaemonReload() error {
|
||||
if nodaemon {
|
||||
return nil
|
||||
}
|
||||
if !util.IsFile(WAREWULFD_PIDFILE) {
|
||||
return errors.New("Warewulf server is not running")
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"strconv"
|
||||
"text/template"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
|
||||
"github.com/hpcng/warewulf/internal/pkg/container"
|
||||
"github.com/hpcng/warewulf/internal/pkg/kernel"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
@@ -31,12 +30,7 @@ type iPxeTemplate struct {
|
||||
}
|
||||
|
||||
func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
conf, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
wwlog.Error("Could not open Warewulf configuration: %s", err)
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
conf := warewulfconf.New()
|
||||
|
||||
rinfo, err := parseReq(req)
|
||||
if err != nil {
|
||||
@@ -45,7 +39,7 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
wwlog.Recv("hwaddr: %s, ipaddr: %s, stage: %s", rinfo.hwaddr, req.RemoteAddr, rinfo.stage )
|
||||
wwlog.Recv("hwaddr: %s, ipaddr: %s, stage: %s", rinfo.hwaddr, req.RemoteAddr, rinfo.stage)
|
||||
|
||||
if rinfo.stage == "runtime" && conf.Warewulf.Secure {
|
||||
if rinfo.remoteport >= 1024 {
|
||||
@@ -56,11 +50,11 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
|
||||
status_stages := map[string]string{
|
||||
"ipxe": "IPXE",
|
||||
"kernel": "KERNEL",
|
||||
"kmods": "KMODS_OVERLAY",
|
||||
"system": "SYSTEM_OVERLAY",
|
||||
"runtime": "RUNTIME_OVERLAY" }
|
||||
"ipxe": "IPXE",
|
||||
"kernel": "KERNEL",
|
||||
"kmods": "KMODS_OVERLAY",
|
||||
"system": "SYSTEM_OVERLAY",
|
||||
"runtime": "RUNTIME_OVERLAY"}
|
||||
|
||||
status_stage := status_stages[rinfo.stage]
|
||||
var stage_overlays []string
|
||||
@@ -85,26 +79,26 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
if !node.Id.Defined() {
|
||||
wwlog.Error("%s (unknown/unconfigured node)", rinfo.hwaddr)
|
||||
if rinfo.stage == "ipxe" {
|
||||
stage_file = path.Join(buildconfig.SYSCONFDIR(), "/warewulf/ipxe/unconfigured.ipxe")
|
||||
stage_file = path.Join(conf.Paths.Sysconfdir, "/warewulf/ipxe/unconfigured.ipxe")
|
||||
tmpl_data = iPxeTemplate{
|
||||
Hwaddr : rinfo.hwaddr }
|
||||
Hwaddr: rinfo.hwaddr}
|
||||
}
|
||||
|
||||
}else if rinfo.stage == "ipxe" {
|
||||
stage_file = path.Join(buildconfig.SYSCONFDIR(), "warewulf/ipxe/"+node.Ipxe.Get()+".ipxe")
|
||||
} else if rinfo.stage == "ipxe" {
|
||||
stage_file = path.Join(conf.Paths.Sysconfdir, "warewulf/ipxe/"+node.Ipxe.Get()+".ipxe")
|
||||
tmpl_data = iPxeTemplate{
|
||||
Id : node.Id.Get(),
|
||||
Cluster : node.ClusterName.Get(),
|
||||
Fqdn : node.Id.Get(),
|
||||
Ipaddr : conf.Ipaddr,
|
||||
Port : strconv.Itoa(conf.Warewulf.Port),
|
||||
Hostname : node.Id.Get(),
|
||||
Hwaddr : rinfo.hwaddr,
|
||||
ContainerName : node.ContainerName.Get(),
|
||||
KernelArgs : node.Kernel.Args.Get(),
|
||||
KernelOverride : node.Kernel.Override.Get() }
|
||||
Id: node.Id.Get(),
|
||||
Cluster: node.ClusterName.Get(),
|
||||
Fqdn: node.Id.Get(),
|
||||
Ipaddr: conf.Ipaddr,
|
||||
Port: strconv.Itoa(conf.Warewulf.Port),
|
||||
Hostname: node.Id.Get(),
|
||||
Hwaddr: rinfo.hwaddr,
|
||||
ContainerName: node.ContainerName.Get(),
|
||||
KernelArgs: node.Kernel.Args.Get(),
|
||||
KernelOverride: node.Kernel.Override.Get()}
|
||||
|
||||
}else if rinfo.stage == "kernel" {
|
||||
} else if rinfo.stage == "kernel" {
|
||||
if node.Kernel.Override.Defined() {
|
||||
stage_file = kernel.KernelImage(node.Kernel.Override.Get())
|
||||
} else if node.ContainerName.Defined() {
|
||||
@@ -117,28 +111,28 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
wwlog.Warn("No kernel version set for node %s", node.Id.Get())
|
||||
}
|
||||
|
||||
}else if rinfo.stage == "kmods" {
|
||||
} else if rinfo.stage == "kmods" {
|
||||
if node.Kernel.Override.Defined() {
|
||||
stage_file = kernel.KmodsImage(node.Kernel.Override.Get())
|
||||
}else{
|
||||
} else {
|
||||
wwlog.Warn("No kernel override modules set for node %s", node.Id.Get())
|
||||
}
|
||||
|
||||
}else if rinfo.stage == "container" {
|
||||
} else if rinfo.stage == "container" {
|
||||
if node.ContainerName.Defined() {
|
||||
stage_file = container.ImageFile(node.ContainerName.Get())
|
||||
} else {
|
||||
wwlog.Warn("No container set for node %s", node.Id.Get())
|
||||
}
|
||||
|
||||
}else if rinfo.stage == "system" {
|
||||
} else if rinfo.stage == "system" {
|
||||
if len(node.SystemOverlay.GetSlice()) != 0 {
|
||||
stage_overlays = node.SystemOverlay.GetSlice()
|
||||
} else {
|
||||
wwlog.Warn("No system overlay set for node %s", node.Id.Get())
|
||||
}
|
||||
|
||||
}else if rinfo.stage == "runtime" {
|
||||
} else if rinfo.stage == "runtime" {
|
||||
if rinfo.overlay != "" {
|
||||
stage_overlays = []string{rinfo.overlay}
|
||||
} else if len(node.RuntimeOverlay.GetSlice()) != 0 {
|
||||
@@ -153,7 +147,7 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
stage_file, err = getOverlayFile(
|
||||
node.Id.Get(),
|
||||
stage_overlays,
|
||||
conf.Warewulf.AutobuildOverlays )
|
||||
conf.Warewulf.AutobuildOverlays)
|
||||
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
@@ -162,7 +156,7 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
wwlog.Serv("stage_file '%s'", stage_file )
|
||||
wwlog.Serv("stage_file '%s'", stage_file)
|
||||
|
||||
if util.IsFile(stage_file) {
|
||||
|
||||
@@ -200,7 +194,7 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
|
||||
wwlog.Send("%15s: %s", node.Id.Get(), stage_file)
|
||||
|
||||
}else{
|
||||
} else {
|
||||
if rinfo.compress == "gz" {
|
||||
stage_file += ".gz"
|
||||
|
||||
@@ -210,7 +204,7 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
}else if rinfo.compress != "" {
|
||||
} else if rinfo.compress != "" {
|
||||
wwlog.Error("unsupported %s compressed version of file %s",
|
||||
rinfo.compress, stage_file)
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
@@ -225,14 +219,14 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
|
||||
updateStatus(node.Id.Get(), status_stage, path.Base(stage_file), rinfo.ipaddr)
|
||||
|
||||
}else if stage_file == "" {
|
||||
} else if stage_file == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
wwlog.Error("No resource selected")
|
||||
updateStatus(node.Id.Get(), status_stage, "BAD_REQUEST", rinfo.ipaddr)
|
||||
|
||||
}else{
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
wwlog.Error("Not found: %s", stage_file )
|
||||
wwlog.Error("Not found: %s", stage_file)
|
||||
updateStatus(node.Id.Get(), status_stage, "NOT_FOUND", rinfo.ipaddr)
|
||||
}
|
||||
|
||||
|
||||
@@ -58,10 +58,7 @@ func RunServer() error {
|
||||
http.HandleFunc("/overlay-runtime/", ProvisionSend)
|
||||
http.HandleFunc("/status", StatusSend)
|
||||
|
||||
conf, err := warewulfconf.New()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get Warewulf configuration")
|
||||
}
|
||||
conf := warewulfconf.New()
|
||||
|
||||
daemonPort := conf.Warewulf.Port
|
||||
wwlog.Serv("Starting HTTPD REST service on port %d", daemonPort)
|
||||
|
||||
310
userdocs/contributing/debugging.rst
Normal file
310
userdocs/contributing/debugging.rst
Normal file
@@ -0,0 +1,310 @@
|
||||
=========
|
||||
Debugging
|
||||
=========
|
||||
|
||||
Whether developing a new feature or fixing a bug, using the automated
|
||||
test suite together with a debugger is a potent combination. This
|
||||
guide here can't substitute for full documentation on a given
|
||||
debugger; but it might help you get started debugging Warewulf.
|
||||
|
||||
Validating the code with vet
|
||||
============================
|
||||
|
||||
The Warewulf ``Makefile`` includes a ``vet`` target which runs ``go
|
||||
vet`` on the full codebase.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ make vet
|
||||
|
||||
|
||||
Running the full test suite
|
||||
===========================
|
||||
|
||||
The Warewulf ``Makefile`` includes a ``test-it`` target which runs the
|
||||
full test suite.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ make test-it
|
||||
|
||||
|
||||
Using delve
|
||||
===========
|
||||
|
||||
If you have a failing test but you're having trouble tracking down
|
||||
why, try using a debugger to step through the test. These instructions
|
||||
use delve.
|
||||
|
||||
|
||||
Installing delve
|
||||
----------------
|
||||
|
||||
You can install delve as a regular user directly with Go.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ go install github.com/go-delve/delve/cmd/dlv@latest
|
||||
|
||||
The ``dlv`` binary will be installed by default at
|
||||
``$HOME/go/bin/dlv``. You can, of course, add ``$HOME/go/bin`` to your
|
||||
path if you prefer.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ PATH=$HOME/go/bin:$PATH
|
||||
|
||||
|
||||
Running delve against a specific test
|
||||
-------------------------------------
|
||||
|
||||
You can use delve to specifically run the test suite and, even more
|
||||
specifically, a single failing test. In this example delve is
|
||||
instructed to run the tests for Warewulf's ``node`` package, and
|
||||
specifically the ``Test_GetAllNodeInfoDefaults`` test.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ dlv test github.com/hpcng/warewulf/internal/pkg/node -- -test.v -test.run Test_GetAllNodeInfoDefaults
|
||||
Type 'help' for list of commands.
|
||||
(dlv) break node.Test_GetAllNodeInfoDefaults
|
||||
Breakpoint 1 set at 0x26c0d0 for github.com/hpcng/warewulf/internal/pkg/node.Test_GetAllNodeInfoDefaults() ./internal/pkg/node/nodeyaml_test.go:51
|
||||
|
||||
Setting a breakpoint at ``node.Test_GetAllNodeInfoDefaults`` pauses
|
||||
execution once the test starts, and allows us to ``continue`` through
|
||||
all the setup prior to that point.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
(dlv) continue
|
||||
=== RUN Test_GetAllNodeInfoDefaults
|
||||
> github.com/hpcng/warewulf/internal/pkg/node.Test_GetAllNodeInfoDefaults() ./internal/pkg/node/nodeyaml_test.go:51 (hits goroutine(35):1 total:1) (PC: 0x26c0d0)
|
||||
46: assert.Contains(t, nodeYaml.Nodes, "test_node")
|
||||
47: assert.Equal(t, "A single node", nodeYaml.Nodes["test_node"].Comment)
|
||||
48: }
|
||||
49:
|
||||
50:
|
||||
=> 51: func Test_GetAllNodeInfoDefaults(t *testing.T) {
|
||||
52: file, writeErr := writeTestConfigFile(`
|
||||
53: nodes:
|
||||
54: test_node: {}`)
|
||||
55: if file != nil {
|
||||
56: defer os.Remove(file.Name())
|
||||
|
||||
Helpful commands from here include
|
||||
|
||||
``next``
|
||||
|
||||
Execute the current line (marked by ``=>``) and proceed to the next
|
||||
line.
|
||||
|
||||
``step``
|
||||
|
||||
Execute the current line (marked by ``=>``) and proceed to the next
|
||||
line, potentially moving into a function call.
|
||||
|
||||
``list``
|
||||
|
||||
Display a contextual Go code listing, marking the next instruction.
|
||||
|
||||
``locals``
|
||||
|
||||
Display all local variables in the current scope.
|
||||
|
||||
``print``
|
||||
|
||||
Display (in detail) the value of a single variable from the current
|
||||
scope.
|
||||
|
||||
Read about other commands available within delve using the ``help``
|
||||
command.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ~/go/bin/dlv test github.com/hpcng/warewulf/internal/pkg/node -- -test.v -test.run Test_GetAllNodeInfoDefaults
|
||||
Type 'help' for list of commands.
|
||||
|
||||
(dlv) break node.Test_GetAllNodeInfoDefaults
|
||||
Breakpoint 1 set at 0x26c0d0 for github.com/hpcng/warewulf/internal/pkg/node.Test_GetAllNodeInfoDefaults() ./internal/pkg/node/nodeyaml_test.go:51
|
||||
|
||||
(dlv) break nodeinfo.go:417
|
||||
Breakpoint 2 set at 0x267f18 for github.com/hpcng/warewulf/internal/pkg/node.NewNodeInfo() ./internal/pkg/node/nodeinfo.go:417
|
||||
|
||||
(dlv) continue
|
||||
=== RUN Test_GetAllNodeInfoDefaults
|
||||
> github.com/hpcng/warewulf/internal/pkg/node.Test_GetAllNodeInfoDefaults() ./internal/pkg/node/nodeyaml_test.go:51 (hits goroutine(19):1 total:1) (PC: 0x26c0d0)
|
||||
46: assert.Contains(t, nodeYaml.Nodes, "test_node")
|
||||
47: assert.Equal(t, "A single node", nodeYaml.Nodes["test_node"].Comment)
|
||||
48: }
|
||||
49:
|
||||
50:
|
||||
=> 51: func Test_GetAllNodeInfoDefaults(t *testing.T) {
|
||||
52: file, writeErr := writeTestConfigFile(`
|
||||
53: nodes:
|
||||
54: test_node: {}`)
|
||||
55: if file != nil {
|
||||
56: defer os.Remove(file.Name())
|
||||
|
||||
(dlv) continue
|
||||
WARN : Error reading UNDEF/warewulf/defaults.conf: open UNDEF/warewulf/defaults.conf: no such file or directory
|
||||
> github.com/hpcng/warewulf/internal/pkg/node.NewNodeInfo() ./internal/pkg/node/nodeinfo.go:417 (hits goroutine(19):1 total:1) (PC: 0x267f18)
|
||||
412: defaultNodeConf.NetDevs = nil
|
||||
413: nodeInfo.SetDefFrom(defaultNodeConf)
|
||||
414: }
|
||||
415:
|
||||
416: // Load normal attributes
|
||||
=> 417: if nodeConf != nil {
|
||||
418: // If no profiles are included, automatically include the
|
||||
419: // default profile.
|
||||
420: if len(nodeConf.Profiles) == 0 {
|
||||
421: nodeInfo.Profiles.SetSlice([]string{"default"})
|
||||
422: } else {
|
||||
|
||||
(dlv) next
|
||||
> github.com/hpcng/warewulf/internal/pkg/node.NewNodeInfo() ./internal/pkg/node/nodeinfo.go:420 (PC: 0x267f24)
|
||||
415:
|
||||
416: // Load normal attributes
|
||||
417: if nodeConf != nil {
|
||||
418: // If no profiles are included, automatically include the
|
||||
419: // default profile.
|
||||
=> 420: if len(nodeConf.Profiles) == 0 {
|
||||
421: nodeInfo.Profiles.SetSlice([]string{"default"})
|
||||
422: } else {
|
||||
423: nodeInfo.Profiles.SetSlice(nodeConf.Profiles)
|
||||
424: }
|
||||
425:
|
||||
|
||||
(dlv) next
|
||||
> github.com/hpcng/warewulf/internal/pkg/node.NewNodeInfo() ./internal/pkg/node/nodeinfo.go:421 (PC: 0x267f3c)
|
||||
416: // Load normal attributes
|
||||
417: if nodeConf != nil {
|
||||
418: // If no profiles are included, automatically include the
|
||||
419: // default profile.
|
||||
420: if len(nodeConf.Profiles) == 0 {
|
||||
=> 421: nodeInfo.Profiles.SetSlice([]string{"default"})
|
||||
422: } else {
|
||||
423: nodeInfo.Profiles.SetSlice(nodeConf.Profiles)
|
||||
424: }
|
||||
425:
|
||||
426: nodeInfo.SetFrom(nodeConf)
|
||||
|
||||
(dlv) next
|
||||
> github.com/hpcng/warewulf/internal/pkg/node.NewNodeInfo() ./internal/pkg/node/nodeinfo.go:426 (PC: 0x267fec)
|
||||
421: nodeInfo.Profiles.SetSlice([]string{"default"})
|
||||
422: } else {
|
||||
423: nodeInfo.Profiles.SetSlice(nodeConf.Profiles)
|
||||
424: }
|
||||
425:
|
||||
=> 426: nodeInfo.SetFrom(nodeConf)
|
||||
427: }
|
||||
428:
|
||||
429: // Load default attributes for each NetDev
|
||||
430: if defaultNetDevConf != nil {
|
||||
431: for _, netdev := range nodeInfo.NetDevs {
|
||||
|
||||
(dlv) next
|
||||
> github.com/hpcng/warewulf/internal/pkg/node.NewNodeInfo() ./internal/pkg/node/nodeinfo.go:430 (PC: 0x268000)
|
||||
425:
|
||||
426: nodeInfo.SetFrom(nodeConf)
|
||||
427: }
|
||||
428:
|
||||
429: // Load default attributes for each NetDev
|
||||
=> 430: if defaultNetDevConf != nil {
|
||||
431: for _, netdev := range nodeInfo.NetDevs {
|
||||
432: netdev.SetDefFrom(defaultNetDevConf)
|
||||
433: }
|
||||
434: }
|
||||
435:
|
||||
|
||||
(dlv) print nodeInfo
|
||||
github.com/hpcng/warewulf/internal/pkg/node.NodeInfo {
|
||||
Id: github.com/hpcng/warewulf/internal/pkg/node.Entry {
|
||||
value: []string len: 1, cap: 1, [
|
||||
"test_node",
|
||||
],
|
||||
altvalue: []string len: 0, cap: 0, nil,
|
||||
from: "",
|
||||
def: []string len: 0, cap: 0, nil,},
|
||||
Comment: github.com/hpcng/warewulf/internal/pkg/node.Entry {
|
||||
value: []string len: 0, cap: 0, nil,
|
||||
altvalue: []string len: 0, cap: 0, nil,
|
||||
from: "",
|
||||
def: []string len: 0, cap: 0, nil,},
|
||||
ClusterName: github.com/hpcng/warewulf/internal/pkg/node.Entry {
|
||||
value: []string len: 0, cap: 0, nil,
|
||||
altvalue: []string len: 0, cap: 0, nil,
|
||||
from: "",
|
||||
def: []string len: 0, cap: 0, nil,},
|
||||
ContainerName: github.com/hpcng/warewulf/internal/pkg/node.Entry {
|
||||
value: []string len: 0, cap: 0, nil,
|
||||
altvalue: []string len: 0, cap: 0, nil,
|
||||
from: "",
|
||||
def: []string len: 0, cap: 0, nil,},
|
||||
Ipxe: github.com/hpcng/warewulf/internal/pkg/node.Entry {
|
||||
value: []string len: 0, cap: 0, nil,
|
||||
altvalue: []string len: 0, cap: 0, nil,
|
||||
from: "",
|
||||
def: []string len: 1, cap: 1, ["default"],},
|
||||
RuntimeOverlay: github.com/hpcng/warewulf/internal/pkg/node.Entry {
|
||||
value: []string len: 0, cap: 0, nil,
|
||||
altvalue: []string len: 0, cap: 0, nil,
|
||||
from: "",
|
||||
def: []string len: 1, cap: 1, ["generic"],},
|
||||
SystemOverlay: github.com/hpcng/warewulf/internal/pkg/node.Entry {
|
||||
value: []string len: 0, cap: 0, nil,
|
||||
altvalue: []string len: 0, cap: 0, nil,
|
||||
from: "",
|
||||
def: []string len: 1, cap: 1, ["wwinit"],},
|
||||
Root: github.com/hpcng/warewulf/internal/pkg/node.Entry {
|
||||
value: []string len: 0, cap: 0, nil,
|
||||
altvalue: []string len: 0, cap: 0, nil,
|
||||
from: "",
|
||||
def: []string len: 1, cap: 1, [
|
||||
"initramfs",
|
||||
],},
|
||||
Discoverable: github.com/hpcng/warewulf/internal/pkg/node.Entry {
|
||||
value: []string len: 0, cap: 0, nil,
|
||||
altvalue: []string len: 0, cap: 0, nil,
|
||||
from: "",
|
||||
def: []string len: 0, cap: 0, nil,},
|
||||
Init: github.com/hpcng/warewulf/internal/pkg/node.Entry {
|
||||
value: []string len: 0, cap: 0, nil,
|
||||
altvalue: []string len: 0, cap: 0, nil,
|
||||
from: "",
|
||||
def: []string len: 1, cap: 1, [
|
||||
"/sbin/init",
|
||||
],},
|
||||
AssetKey: github.com/hpcng/warewulf/internal/pkg/node.Entry {
|
||||
value: []string len: 0, cap: 0, nil,
|
||||
altvalue: []string len: 0, cap: 0, nil,
|
||||
from: "",
|
||||
def: []string len: 0, cap: 0, nil,},
|
||||
Kernel: *github.com/hpcng/warewulf/internal/pkg/node.KernelEntry {
|
||||
Override: (*"github.com/hpcng/warewulf/internal/pkg/node.Entry")(0x4000158370),
|
||||
Args: (*"github.com/hpcng/warewulf/internal/pkg/node.Entry")(0x40001583c8),},
|
||||
Ipmi: *github.com/hpcng/warewulf/internal/pkg/node.IpmiEntry {
|
||||
Ipaddr: (*"github.com/hpcng/warewulf/internal/pkg/node.Entry")(0x40001b6600),
|
||||
Netmask: (*"github.com/hpcng/warewulf/internal/pkg/node.Entry")(0x40001b6658),
|
||||
Port: (*"github.com/hpcng/warewulf/internal/pkg/node.Entry")(0x40001b66b0),
|
||||
Gateway: (*"github.com/hpcng/warewulf/internal/pkg/node.Entry")(0x40001b6708),
|
||||
UserName: (*"github.com/hpcng/warewulf/internal/pkg/node.Entry")(0x40001b6760),
|
||||
Password: (*"github.com/hpcng/warewulf/internal/pkg/node.Entry")(0x40001b67b8),
|
||||
Interface: (*"github.com/hpcng/warewulf/internal/pkg/node.Entry")(0x40001b6810),
|
||||
Write: (*"github.com/hpcng/warewulf/internal/pkg/node.Entry")(0x40001b6868),
|
||||
Tags: map[string]*github.com/hpcng/warewulf/internal/pkg/node.Entry [],},
|
||||
Profiles: github.com/hpcng/warewulf/internal/pkg/node.Entry {
|
||||
value: []string len: 1, cap: 1, ["default"],
|
||||
altvalue: []string len: 0, cap: 0, nil,
|
||||
from: "",
|
||||
def: []string len: 1, cap: 1, ["default"],},
|
||||
PrimaryNetDev: github.com/hpcng/warewulf/internal/pkg/node.Entry {
|
||||
value: []string len: 0, cap: 0, nil,
|
||||
altvalue: []string len: 0, cap: 0, nil,
|
||||
from: "",
|
||||
def: []string len: 0, cap: 0, nil,},
|
||||
NetDevs: map[string]*github.com/hpcng/warewulf/internal/pkg/node.NetDevEntry [],
|
||||
Tags: map[string]*github.com/hpcng/warewulf/internal/pkg/node.Entry [],}
|
||||
@@ -38,12 +38,18 @@ Welcome to the Warewulf User Guide!
|
||||
:caption: Contributing
|
||||
|
||||
Contributing <contributing/contributing>
|
||||
Debugging <contributing/debugging>
|
||||
Documentation <contributing/documentation>
|
||||
Development Environment (KVM) <contributing/development-environment-kvm>
|
||||
Development Environment (VirtualBox) <contributing/development-environment-vbox>
|
||||
Glossary <contents/glossary>
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Reference
|
||||
:glob:
|
||||
|
||||
reference/*
|
||||
|
||||
|
||||
|
||||
Glossary <reference/glossary>
|
||||
|
||||
@@ -9,7 +9,7 @@ Install Warewulf and dependencies
|
||||
|
||||
sudo dnf groupinstall "Development Tools"
|
||||
sudo dnf install epel-release
|
||||
sudo dnf install golang tftp-server dhcp-server nfs-utils
|
||||
sudo dnf install golang tftp-server dhcp-server nfs-utils gpgpme-devel libassuan-devel
|
||||
|
||||
git clone https://github.com/hpcng/warewulf.git
|
||||
cd warewulf
|
||||
|
||||
@@ -118,7 +118,7 @@ getent group %{wwgroup} >/dev/null || groupadd -r %{wwgroup}
|
||||
%dir %{_sysconfdir}/warewulf
|
||||
%config(noreplace) %{_sysconfdir}/warewulf/*
|
||||
%config(noreplace) %attr(0640,-,-) %{_sysconfdir}/warewulf/nodes.conf
|
||||
%{_sysconfdir}/bash_completion.d/warewulf
|
||||
%{_sysconfdir}/bash_completion.d/wwctl
|
||||
|
||||
%dir %{_sharedstatedir}/warewulf
|
||||
%{_sharedstatedir}/warewulf/chroots
|
||||
|
||||
Reference in New Issue
Block a user