Merge pull request #157 from gmkurtzer/overlay_autoupdate
Update or build overlays on demand
This commit is contained in:
@@ -35,6 +35,7 @@ if exists user-class and option user-class = "iPXE" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
subnet {{$.Network}} netmask {{$.Netmask}} {
|
subnet {{$.Network}} netmask {{$.Netmask}} {
|
||||||
|
max-lease-time 120;
|
||||||
range {{$.RangeStart}} {{$.RangeEnd}};
|
range {{$.RangeStart}} {{$.RangeEnd}};
|
||||||
next-server {{$.Ipaddr}};
|
next-server {{$.Ipaddr}};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
ipaddr: 192.168.1.1
|
ipaddr: 192.168.200.1
|
||||||
netmask: 255.255.255.0
|
netmask: 255.255.255.0
|
||||||
warewulf:
|
warewulf:
|
||||||
port: 9873
|
port: 9873
|
||||||
secure: true
|
secure: true
|
||||||
|
autobuild overlays: true
|
||||||
update interval: 60
|
update interval: 60
|
||||||
|
syslog: false
|
||||||
dhcp:
|
dhcp:
|
||||||
enabled: true
|
enabled: true
|
||||||
range start: 192.168.1.150
|
range start: 192.168.200.50
|
||||||
range end: 192.168.1.200
|
range end: 192.168.200.99
|
||||||
template: default
|
template: default
|
||||||
systemd name: dhcpd
|
systemd name: dhcpd
|
||||||
tftp:
|
tftp:
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/config"
|
"github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -55,37 +53,5 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !NoOverlayUpdate {
|
|
||||||
n, err := node.New()
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes, err := n.FindAllNodes()
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var updateNodes []node.NodeInfo
|
|
||||||
|
|
||||||
for _, node := range nodes {
|
|
||||||
if overlayKind == "system" && node.SystemOverlay.Get() == overlayName {
|
|
||||||
updateNodes = append(updateNodes, node)
|
|
||||||
} else if overlayKind == "runtime" && node.RuntimeOverlay.Get() == overlayName {
|
|
||||||
updateNodes = append(updateNodes, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if overlayKind == "system" {
|
|
||||||
wwlog.Printf(wwlog.INFO, "Updating System Overlays...\n")
|
|
||||||
return overlay.BuildSystemOverlay(updateNodes)
|
|
||||||
} else if overlayKind == "runtime" {
|
|
||||||
wwlog.Printf(wwlog.INFO, "Updating Runtime Overlays...\n")
|
|
||||||
return overlay.BuildRuntimeOverlay(updateNodes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,9 @@ var (
|
|||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
Args: cobra.ExactArgs(4),
|
Args: cobra.ExactArgs(4),
|
||||||
}
|
}
|
||||||
NoOverlayUpdate bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
baseCmd.PersistentFlags().BoolVarP(&NoOverlayUpdate, "noupdate", "n", false, "Don't update overlays")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootCommand returns the root cobra.Command for the application.
|
// GetRootCommand returns the root cobra.Command for the application.
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/config"
|
"github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
|
|
||||||
@@ -69,37 +67,5 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !NoOverlayUpdate {
|
|
||||||
n, err := node.New()
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes, err := n.FindAllNodes()
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var updateNodes []node.NodeInfo
|
|
||||||
|
|
||||||
for _, node := range nodes {
|
|
||||||
if overlayKind == "system" && node.SystemOverlay.Get() == overlayName {
|
|
||||||
updateNodes = append(updateNodes, node)
|
|
||||||
} else if overlayKind == "runtime" && node.RuntimeOverlay.Get() == overlayName {
|
|
||||||
updateNodes = append(updateNodes, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if overlayKind == "system" {
|
|
||||||
wwlog.Printf(wwlog.INFO, "Updating System Overlays...\n")
|
|
||||||
return overlay.BuildSystemOverlay(updateNodes)
|
|
||||||
} else if overlayKind == "runtime" {
|
|
||||||
wwlog.Printf(wwlog.INFO, "Updating Runtime Overlays...\n")
|
|
||||||
return overlay.BuildRuntimeOverlay(updateNodes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,9 @@ var (
|
|||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
Args: cobra.RangeArgs(4, 5),
|
Args: cobra.RangeArgs(4, 5),
|
||||||
}
|
}
|
||||||
NoOverlayUpdate bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
baseCmd.PersistentFlags().BoolVarP(&NoOverlayUpdate, "noupdate", "n", false, "Don't update overlays")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootCommand returns the root cobra.Command for the application.
|
// GetRootCommand returns the root cobra.Command for the application.
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package create
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -32,39 +31,6 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
|||||||
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
wwlog.Printf(wwlog.ERROR, "%s\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
wwlog.Printf(wwlog.INFO, "Created new runtime overlay: %s\n", overlayName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !NoOverlayUpdate {
|
|
||||||
n, err := node.New()
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes, err := n.FindAllNodes()
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.ERROR, "Could not get nodeList: %s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var updateNodes []node.NodeInfo
|
|
||||||
|
|
||||||
for _, node := range nodes {
|
|
||||||
if overlayKind == "system" && node.SystemOverlay.Get() == overlayName {
|
|
||||||
updateNodes = append(updateNodes, node)
|
|
||||||
} else if overlayKind == "runtime" && node.RuntimeOverlay.Get() == overlayName {
|
|
||||||
updateNodes = append(updateNodes, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if overlayKind == "system" {
|
|
||||||
wwlog.Printf(wwlog.INFO, "Updating System Overlays...\n")
|
|
||||||
return overlay.BuildSystemOverlay(updateNodes)
|
|
||||||
} else if overlayKind == "runtime" {
|
|
||||||
wwlog.Printf(wwlog.INFO, "Updating Runtime Overlays...\n")
|
|
||||||
return overlay.BuildRuntimeOverlay(updateNodes)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -12,11 +12,9 @@ var (
|
|||||||
RunE: CobraRunE,
|
RunE: CobraRunE,
|
||||||
Args: cobra.ExactArgs(2),
|
Args: cobra.ExactArgs(2),
|
||||||
}
|
}
|
||||||
NoOverlayUpdate bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
baseCmd.PersistentFlags().BoolVarP(&NoOverlayUpdate, "noupdate", "n", false, "Don't update overlays")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootCommand returns the root cobra.Command for the application.
|
// GetRootCommand returns the root cobra.Command for the application.
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/config"
|
"github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -88,8 +87,6 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
|||||||
return errors.Wrap(err, "failed to persist node updates")
|
return errors.Wrap(err, "failed to persist node updates")
|
||||||
}
|
}
|
||||||
|
|
||||||
overlayName = "default"
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
removePath := path.Join(overlayPath, fileName)
|
removePath := path.Join(overlayPath, fileName)
|
||||||
|
|
||||||
@@ -128,39 +125,6 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
|||||||
i = path.Dir(i)
|
i = path.Dir(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Printf("Deleted from overlay: %s:%s:%s\n", overlayKind, overlayName, overlayPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !NoOverlayUpdate {
|
|
||||||
n, err := node.New()
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes, err := n.FindAllNodes()
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var updateNodes []node.NodeInfo
|
|
||||||
|
|
||||||
for _, node := range nodes {
|
|
||||||
if overlayKind == "system" && node.SystemOverlay.Get() == overlayName {
|
|
||||||
updateNodes = append(updateNodes, node)
|
|
||||||
} else if overlayKind == "runtime" && node.RuntimeOverlay.Get() == overlayName {
|
|
||||||
updateNodes = append(updateNodes, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if overlayKind == "system" {
|
|
||||||
wwlog.Printf(wwlog.INFO, "Updating System Overlays...\n")
|
|
||||||
return overlay.BuildSystemOverlay(updateNodes)
|
|
||||||
} else if overlayKind == "runtime" {
|
|
||||||
wwlog.Printf(wwlog.INFO, "Updating Runtime Overlays...\n")
|
|
||||||
return overlay.BuildRuntimeOverlay(updateNodes)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -16,13 +16,11 @@ var (
|
|||||||
}
|
}
|
||||||
Force bool
|
Force bool
|
||||||
Parents bool
|
Parents bool
|
||||||
NoOverlayUpdate bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
baseCmd.PersistentFlags().BoolVarP(&Force, "force", "f", false, "Force deletion of a non-empty overlay")
|
baseCmd.PersistentFlags().BoolVarP(&Force, "force", "f", false, "Force deletion of a non-empty overlay")
|
||||||
baseCmd.PersistentFlags().BoolVarP(&Parents, "parents", "p", false, "Remove empty parent directories")
|
baseCmd.PersistentFlags().BoolVarP(&Parents, "parents", "p", false, "Remove empty parent directories")
|
||||||
baseCmd.PersistentFlags().BoolVarP(&NoOverlayUpdate, "noupdate", "n", false, "Don't update overlays")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootCommand returns the root cobra.Command for the application.
|
// GetRootCommand returns the root cobra.Command for the application.
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/config"
|
"github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -82,59 +80,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
|||||||
fmt.Fprintf(w, "\n")
|
fmt.Fprintf(w, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
shasum1, err := util.ShaSumFile(overlayFile)
|
err := util.ExecInteractive(editor, overlayFile)
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.WARN, "Could not open overlay file for checksum: %s\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = util.ExecInteractive(editor, overlayFile)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
wwlog.Printf(wwlog.ERROR, "Editor process existed with non-zero\n")
|
wwlog.Printf(wwlog.ERROR, "Editor process existed with non-zero\n")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
wwlog.Printf(wwlog.INFO, "Updated: %s:%s:%s\n", overlayKind, overlayName, fileName)
|
|
||||||
|
|
||||||
shasum2, err := util.ShaSumFile(overlayFile)
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.WARN, "Could not open overlay file for checksum: %s\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if shasum1 == shasum2 {
|
|
||||||
wwlog.Printf(wwlog.VERBOSE, "Not updating overlays, no file change\n")
|
|
||||||
NoOverlayUpdate = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if !NoOverlayUpdate {
|
|
||||||
n, err := node.New()
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes, err := n.FindAllNodes()
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var updateNodes []node.NodeInfo
|
|
||||||
|
|
||||||
for _, node := range nodes {
|
|
||||||
if overlayKind == "system" && node.SystemOverlay.Get() == overlayName {
|
|
||||||
updateNodes = append(updateNodes, node)
|
|
||||||
} else if overlayKind == "runtime" && node.RuntimeOverlay.Get() == overlayName {
|
|
||||||
updateNodes = append(updateNodes, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if overlayKind == "system" {
|
|
||||||
wwlog.Printf(wwlog.INFO, "Updating System Overlays...\n")
|
|
||||||
return overlay.BuildSystemOverlay(updateNodes)
|
|
||||||
} else if overlayKind == "runtime" {
|
|
||||||
wwlog.Printf(wwlog.INFO, "Updating Runtime Overlays...\n")
|
|
||||||
return overlay.BuildRuntimeOverlay(updateNodes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ var (
|
|||||||
ListFiles bool
|
ListFiles bool
|
||||||
CreateDirs bool
|
CreateDirs bool
|
||||||
PermMode int32
|
PermMode int32
|
||||||
NoOverlayUpdate bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
baseCmd.PersistentFlags().BoolVarP(&ListFiles, "files", "f", false, "List files contained within a given overlay")
|
baseCmd.PersistentFlags().BoolVarP(&ListFiles, "files", "f", false, "List files contained within a given overlay")
|
||||||
baseCmd.PersistentFlags().BoolVarP(&CreateDirs, "parents", "p", false, "Create any necessary parent directories")
|
baseCmd.PersistentFlags().BoolVarP(&CreateDirs, "parents", "p", false, "Create any necessary parent directories")
|
||||||
baseCmd.PersistentFlags().Int32VarP(&PermMode, "mode", "m", 0755, "Permission mode for directory")
|
baseCmd.PersistentFlags().Int32VarP(&PermMode, "mode", "m", 0755, "Permission mode for directory")
|
||||||
baseCmd.PersistentFlags().BoolVarP(&NoOverlayUpdate, "noupdate", "n", false, "Don't update overlays")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootCommand returns the root cobra.Command for the application.
|
// GetRootCommand returns the root cobra.Command for the application.
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
package mkdir
|
package mkdir
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/config"
|
"github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -46,39 +43,5 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Created directory within overlay: %s:%s:%s\n", overlayKind, overlayName, overlayDir)
|
|
||||||
|
|
||||||
if !NoOverlayUpdate {
|
|
||||||
n, err := node.New()
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes, err := n.FindAllNodes()
|
|
||||||
if err != nil {
|
|
||||||
wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var updateNodes []node.NodeInfo
|
|
||||||
|
|
||||||
for _, node := range nodes {
|
|
||||||
if overlayKind == "system" && node.SystemOverlay.Get() == overlayName {
|
|
||||||
updateNodes = append(updateNodes, node)
|
|
||||||
} else if overlayKind == "runtime" && node.RuntimeOverlay.Get() == overlayName {
|
|
||||||
updateNodes = append(updateNodes, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if overlayKind == "system" {
|
|
||||||
wwlog.Printf(wwlog.INFO, "Updating System Overlays...\n")
|
|
||||||
return overlay.BuildSystemOverlay(updateNodes)
|
|
||||||
} else if overlayKind == "runtime" {
|
|
||||||
wwlog.Printf(wwlog.INFO, "Updating Runtime Overlays...\n")
|
|
||||||
return overlay.BuildRuntimeOverlay(updateNodes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,10 @@ var (
|
|||||||
Args: cobra.MinimumNArgs(3),
|
Args: cobra.MinimumNArgs(3),
|
||||||
}
|
}
|
||||||
PermMode int32
|
PermMode int32
|
||||||
NoOverlayUpdate bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
baseCmd.PersistentFlags().Int32VarP(&PermMode, "mode", "m", 0755, "Permission mode for directory")
|
baseCmd.PersistentFlags().Int32VarP(&PermMode, "mode", "m", 0755, "Permission mode for directory")
|
||||||
baseCmd.PersistentFlags().BoolVarP(&NoOverlayUpdate, "noupdate", "n", false, "Don't update overlays")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootCommand returns the root cobra.Command for the application.
|
// GetRootCommand returns the root cobra.Command for the application.
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
package start
|
package start
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
|
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
if SetForeground {
|
if SetForeground {
|
||||||
|
conf, err := warewulfconf.New()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Could not read Warewulf configuration file")
|
||||||
|
}
|
||||||
|
conf.Warewulf.Syslog = false
|
||||||
return errors.Wrap(warewulfd.RunServer(), "failed to start Warewulf server")
|
return errors.Wrap(warewulfd.RunServer(), "failed to start Warewulf server")
|
||||||
} else {
|
} else {
|
||||||
return errors.Wrap(warewulfd.DaemonStart(), "failed to start Warewulf server")
|
return errors.Wrap(warewulfd.DaemonStart(), "failed to start Warewulf server")
|
||||||
|
|||||||
@@ -126,12 +126,12 @@ func buildOverlay(nodeList []node.NodeInfo, overlayType string) error {
|
|||||||
var OverlayFile string
|
var OverlayFile string
|
||||||
|
|
||||||
if overlayType == "runtime" {
|
if overlayType == "runtime" {
|
||||||
wwlog.Printf(wwlog.VERBOSE, "Building runtime overlay for: %s\n", n.Id.Get())
|
wwlog.Printf(wwlog.DEBUG, "Building runtime overlay for: %s\n", n.Id.Get())
|
||||||
|
|
||||||
OverlayDir = config.RuntimeOverlaySource(n.RuntimeOverlay.Get())
|
OverlayDir = config.RuntimeOverlaySource(n.RuntimeOverlay.Get())
|
||||||
OverlayFile = config.RuntimeOverlayImage(n.Id.Get())
|
OverlayFile = config.RuntimeOverlayImage(n.Id.Get())
|
||||||
} else if overlayType == "system" {
|
} else if overlayType == "system" {
|
||||||
wwlog.Printf(wwlog.VERBOSE, "Building system overlay for: %s\n", n.Id.Get())
|
wwlog.Printf(wwlog.DEBUG, "Building system overlay for: %s\n", n.Id.Get())
|
||||||
|
|
||||||
OverlayDir = config.SystemOverlaySource(n.SystemOverlay.Get())
|
OverlayDir = config.SystemOverlaySource(n.SystemOverlay.Get())
|
||||||
OverlayFile = config.SystemOverlayImage(n.Id.Get())
|
OverlayFile = config.SystemOverlayImage(n.Id.Get())
|
||||||
@@ -256,7 +256,7 @@ func buildOverlay(nodeList []node.NodeInfo, overlayType string) error {
|
|||||||
}
|
}
|
||||||
defer w.Close()
|
defer w.Close()
|
||||||
|
|
||||||
wwlog.Printf(wwlog.VERBOSE, "Writing overlay template: OVERLAY:/%s\n", destFile)
|
wwlog.Printf(wwlog.DEBUG, "Writing overlay template: OVERLAY:/%s\n", destFile)
|
||||||
err = tmpl.Execute(w, t)
|
err = tmpl.Execute(w, t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
wwlog.Printf(wwlog.ERROR, "tmpl.Execute %s\n", err)
|
wwlog.Printf(wwlog.ERROR, "tmpl.Execute %s\n", err)
|
||||||
@@ -291,14 +291,14 @@ func buildOverlay(nodeList []node.NodeInfo, overlayType string) error {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
wwlog.Printf(wwlog.VERBOSE, "Finished generating overlay directory for: %s\n", n.Id.Get())
|
wwlog.Printf(wwlog.DEBUG, "Finished generating overlay directory for: %s\n", n.Id.Get())
|
||||||
|
|
||||||
compressor, err := exec.LookPath("pigz")
|
compressor, err := exec.LookPath("pigz")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
wwlog.Printf(wwlog.VERBOSE, "Could not locate PIGZ, using GZIP\n")
|
wwlog.Printf(wwlog.DEBUG, "Could not locate PIGZ, using GZIP\n")
|
||||||
compressor = "gzip"
|
compressor = "gzip"
|
||||||
} else {
|
} else {
|
||||||
wwlog.Printf(wwlog.VERBOSE, "Using PIGZ to compress the overlay: %s\n", compressor)
|
wwlog.Printf(wwlog.DEBUG, "Using PIGZ to compress the overlay: %s\n", compressor)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := fmt.Sprintf("cd \"%s\"; find . | cpio --quiet -o -H newc | %s -c > \"%s\"", tmpDir, compressor, OverlayFile)
|
cmd := fmt.Sprintf("cd \"%s\"; find . | cpio --quiet -o -H newc | %s -c > \"%s\"", tmpDir, compressor, OverlayFile)
|
||||||
@@ -309,7 +309,7 @@ func buildOverlay(nodeList []node.NodeInfo, overlayType string) error {
|
|||||||
wwlog.Printf(wwlog.ERROR, "Could not generate runtime image overlay: %s\n", err)
|
wwlog.Printf(wwlog.ERROR, "Could not generate runtime image overlay: %s\n", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
wwlog.Printf(wwlog.INFO, "%-35s: Done\n", n.Id.Get())
|
wwlog.Printf(wwlog.VERBOSE, "%-35s: Done\n", n.Id.Get())
|
||||||
|
|
||||||
wwlog.Printf(wwlog.DEBUG, "Removing temporary directory: %s\n", tmpDir)
|
wwlog.Printf(wwlog.DEBUG, "Removing temporary directory: %s\n", tmpDir)
|
||||||
os.RemoveAll(tmpDir)
|
os.RemoveAll(tmpDir)
|
||||||
|
|||||||
@@ -10,9 +10,12 @@ import (
|
|||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var singleton ControllerConf
|
||||||
|
|
||||||
func New() (ControllerConf, error) {
|
func New() (ControllerConf, error) {
|
||||||
var ret ControllerConf
|
var ret ControllerConf
|
||||||
|
|
||||||
|
if (ControllerConf{}) == singleton {
|
||||||
wwlog.Printf(wwlog.DEBUG, "Opening Warewulf configuration file: %s\n", ConfigFile)
|
wwlog.Printf(wwlog.DEBUG, "Opening Warewulf configuration file: %s\n", ConfigFile)
|
||||||
data, err := ioutil.ReadFile(ConfigFile)
|
data, err := ioutil.ReadFile(ConfigFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -46,7 +49,14 @@ func New() (ControllerConf, error) {
|
|||||||
ret.Warewulf.Port = 9873
|
ret.Warewulf.Port = 9873
|
||||||
}
|
}
|
||||||
|
|
||||||
wwlog.Printf(wwlog.DEBUG, "Returning node object\n")
|
wwlog.Printf(wwlog.DEBUG, "Returning warewulf config object\n")
|
||||||
|
singleton = ret
|
||||||
|
|
||||||
|
} else {
|
||||||
|
wwlog.Printf(wwlog.DEBUG, "Returning cached warewulf config object\n")
|
||||||
|
|
||||||
|
ret = singleton
|
||||||
|
}
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ type WarewulfConf struct {
|
|||||||
Port int `yaml:"port"`
|
Port int `yaml:"port"`
|
||||||
Secure bool `yaml:"secure"`
|
Secure bool `yaml:"secure"`
|
||||||
UpdateInterval int `yaml:"update interval"`
|
UpdateInterval int `yaml:"update interval"`
|
||||||
|
AutobuildOverlays bool `yaml:"autobuild overlays"`
|
||||||
|
Syslog bool `yaml:"syslog"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DhcpConf struct {
|
type DhcpConf struct {
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import (
|
|||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (self *ControllerConf) Persist() error {
|
func (controller *ControllerConf) Persist() error {
|
||||||
|
|
||||||
out, err := yaml.Marshal(self)
|
out, err := yaml.Marshal(controller)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import (
|
|||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/config"
|
"github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,7 +22,7 @@ func RuntimeOverlaySend(w http.ResponseWriter, req *http.Request) {
|
|||||||
|
|
||||||
nodes, err := node.New()
|
nodes, err := node.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
daemonLogf("%s | ERROR: Could not read node configuration file: %s\n", err)
|
daemonLogf("ERROR: Could not read node configuration file: %s\n", err)
|
||||||
w.WriteHeader(503)
|
w.WriteHeader(503)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -28,13 +30,13 @@ func RuntimeOverlaySend(w http.ResponseWriter, req *http.Request) {
|
|||||||
remote := strings.Split(req.RemoteAddr, ":")
|
remote := strings.Split(req.RemoteAddr, ":")
|
||||||
port, err := strconv.Atoi(remote[1])
|
port, err := strconv.Atoi(remote[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
daemonLogf("%s | ERROR: Could not convert port to integer: %s\n", remote[1])
|
daemonLogf("ERROR: Could not convert port to integer: %s\n", remote[1])
|
||||||
w.WriteHeader(503)
|
w.WriteHeader(503)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
daemonLogf("%s | ERROR: Could not load configuration file: %s\n", err)
|
daemonLogf("ERROR: Could not load configuration file: %s\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,30 +48,37 @@ func RuntimeOverlaySend(w http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node, err := nodes.FindByIpaddr(remote[0])
|
n, err := nodes.FindByIpaddr(remote[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
daemonLogf("WARNING: Could not find node by IP address: %s\n", remote[0])
|
daemonLogf("WARNING: Could not find node by IP address: %s\n", remote[0])
|
||||||
w.WriteHeader(404)
|
w.WriteHeader(404)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !node.Id.Defined() {
|
if !n.Id.Defined() {
|
||||||
daemonLogf("REQ: %15s: %s (unknown/unconfigured node)\n", node.Id.Get(), req.URL.Path)
|
daemonLogf("REQ: %15s: %s (unknown/unconfigured node)\n", n.Id.Get(), req.URL.Path)
|
||||||
w.WriteHeader(404)
|
w.WriteHeader(404)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
daemonLogf("REQ: %15s: %s\n", node.Id.Get(), req.URL.Path)
|
daemonLogf("REQ: %15s: %s\n", n.Id.Get(), req.URL.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.RuntimeOverlay.Defined() {
|
if n.RuntimeOverlay.Defined() {
|
||||||
fileName := config.RuntimeOverlayImage(node.Id.Get())
|
fileName := config.RuntimeOverlayImage(n.Id.Get())
|
||||||
|
|
||||||
err := sendFile(w, fileName, node.Id.Get())
|
if conf.Warewulf.AutobuildOverlays {
|
||||||
|
if !util.IsFile(fileName) || util.PathIsNewer(fileName, node.ConfigFile) || util.PathIsNewer(fileName, config.RuntimeOverlaySource(n.RuntimeOverlay.Get())) {
|
||||||
|
daemonLogf("BUILD: %15s: Runtime Overlay\n", n.Id.Get())
|
||||||
|
_ = overlay.BuildRuntimeOverlay([]node.NodeInfo{n})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := sendFile(w, fileName, n.Id.Get())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
daemonLogf("ERROR: %s\n", err)
|
daemonLogf("ERROR: %s\n", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
w.WriteHeader(503)
|
w.WriteHeader(503)
|
||||||
daemonLogf("WARNING: No 'runtime system-overlay' set for node %s\n", node.Id.Get())
|
daemonLogf("WARNING: No 'runtime system-overlay' set for node %s\n", n.Id.Get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,25 +4,43 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/config"
|
"github.com/hpcng/warewulf/internal/pkg/config"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SystemOverlaySend(w http.ResponseWriter, req *http.Request) {
|
func SystemOverlaySend(w http.ResponseWriter, req *http.Request) {
|
||||||
node, err := getSanity(req)
|
conf, err := warewulfconf.New()
|
||||||
|
if err != nil {
|
||||||
|
daemonLogf("ERROR: Could not read Warewulf configuration file: %s\n", err)
|
||||||
|
w.WriteHeader(503)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := getSanity(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(404)
|
w.WriteHeader(404)
|
||||||
daemonLogf("ERROR: %s\n", err)
|
daemonLogf("ERROR: %s\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.SystemOverlay.Defined() {
|
if n.SystemOverlay.Defined() {
|
||||||
fileName := config.SystemOverlayImage(node.Id.Get())
|
fileName := config.SystemOverlayImage(n.Id.Get())
|
||||||
|
|
||||||
err := sendFile(w, fileName, node.Id.Get())
|
if conf.Warewulf.AutobuildOverlays {
|
||||||
|
if !util.IsFile(fileName) || util.PathIsNewer(fileName, node.ConfigFile) || util.PathIsNewer(fileName, config.SystemOverlaySource(n.SystemOverlay.Get())) {
|
||||||
|
daemonLogf("BUILD: %15s: System Overlay\n", n.Id.Get())
|
||||||
|
_ = overlay.BuildSystemOverlay([]node.NodeInfo{n})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := sendFile(w, fileName, n.Id.Get())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
daemonLogf("ERROR: %s\n", err)
|
daemonLogf("ERROR: %s\n", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
w.WriteHeader(503)
|
w.WriteHeader(503)
|
||||||
daemonLogf("WARNING: No 'system system-overlay' set for node %s\n", node.Id.Get())
|
daemonLogf("WARNING: No 'system system-overlay' set for node %s\n", n.Id.Get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package warewulfd
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
|
"log/syslog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -10,12 +12,40 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||||
|
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var logwriter *syslog.Writer
|
||||||
|
var loginit bool
|
||||||
|
|
||||||
func daemonLogf(message string, a ...interface{}) {
|
func daemonLogf(message string, a ...interface{}) {
|
||||||
|
conf, err := warewulfconf.New()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ERROR: Could not read Warewulf configuration file: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if conf.Warewulf.Syslog {
|
||||||
|
if !loginit {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
logwriter, err = syslog.New(syslog.LOG_NOTICE, "warewulfd")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.SetOutput(logwriter)
|
||||||
|
loginit = true
|
||||||
|
}
|
||||||
|
|
||||||
|
log.SetFlags(0)
|
||||||
|
log.SetPrefix("")
|
||||||
|
log.Printf(message, a...)
|
||||||
|
|
||||||
|
} else {
|
||||||
prefix := fmt.Sprintf("[%s] ", time.Now().Format(time.UnixDate))
|
prefix := fmt.Sprintf("[%s] ", time.Now().Format(time.UnixDate))
|
||||||
fmt.Printf(prefix+message, a...)
|
fmt.Printf(prefix+message, a...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSanity(req *http.Request) (node.NodeInfo, error) {
|
func getSanity(req *http.Request) (node.NodeInfo, error) {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -39,7 +39,7 @@ func RunServer() error {
|
|||||||
http.HandleFunc("/kmods/", KmodsSend)
|
http.HandleFunc("/kmods/", KmodsSend)
|
||||||
http.HandleFunc("/container/", ContainerSend)
|
http.HandleFunc("/container/", ContainerSend)
|
||||||
http.HandleFunc("/overlay-system/", SystemOverlaySend)
|
http.HandleFunc("/overlay-system/", SystemOverlaySend)
|
||||||
http.HandleFunc("/overlay-runtime", RuntimeOverlaySend)
|
http.HandleFunc("/overlay-runtime/", RuntimeOverlaySend)
|
||||||
|
|
||||||
conf, err := warewulfconf.New()
|
conf, err := warewulfconf.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -49,7 +49,7 @@ func RunServer() error {
|
|||||||
daemonPort := conf.Warewulf.Port
|
daemonPort := conf.Warewulf.Port
|
||||||
daemonLogf("Starting HTTPD REST service on port %d\n", daemonPort)
|
daemonLogf("Starting HTTPD REST service on port %d\n", daemonPort)
|
||||||
|
|
||||||
err = http.ListenAndServe(":" + strconv.Itoa(daemonPort), nil)
|
err = http.ListenAndServe(":"+strconv.Itoa(daemonPort), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Could not start listening service")
|
return errors.Wrap(err, "Could not start listening service")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user