Initial cut of wwapi.

We need an API for Warewulf in order to automate around it. The initial version of the API will look a lot like wwctl. wwctl will call the API so that we do not need to maintain separate code paths. In this preview wwctl calls the API via direct function call, but we can change that to a gprc or REST call to a Warewulf server in the future.

This commit contains:
wwapid WareWulf API Daemon. A grpc server with mTLS auth.
wwapic WareWulf API Client. A grpc client with mTLS auth. It's just a sample that reads the version from the server.
wwapird WareWulf API Rest Daemon. A http REST reverse proxy to wwapid.
There are also sample insecure and secure curls to test with.

Implemented Functionality:
wwctl node add
wwctl node delete
wwctl node list
wwctl node set
wwctl node status
wwctl container build
wwctl container delete
wwctl container import
wwctl container list
wwctl container show

Some notes on the files:

    Logic that was in wwctl has moved to warewulf/internal/pkg/api. wwctl just calls the API. wwctl functionality is unchanged.
    Everything under the /google directory is copied google proto code to stand up wwapird. It's a bit strange to copy in the code, but that is currently how it's done.
    Everything in warewulf/internal/pkg/api/routes/wwapiv1 is generated code.

There are some loose ends here, such as no service installers. I just ran off the command line for development.
The Makefile could use improvement. I'm building by make clean setup proto all build wwapid wwapic wwapird ; echo $?
I copied the configs from warewulf/etc to /usr/local/etc/warewulf manually.
This commit is contained in:
MatthewHink
2022-05-13 15:12:32 -04:00
parent d976e7fc31
commit d8cd6049ac
57 changed files with 8842 additions and 1157 deletions

View File

@@ -0,0 +1,41 @@
package apiconfig
import (
"gopkg.in/yaml.v2"
"io/ioutil"
"log"
)
// ClientApiConfig contains configuration parameters for an API server.
type ClientApiConfig struct {
// Server is the hostname or IP address of the server to connect to.
Server string `yaml:"prefix"`
// Port is the where the API server listens.
Port uint32 `yaml:"port"`
}
// ClientConfig is the full client configuration.
type ClientConfig struct {
ApiConfig ClientApiConfig `yaml:"api"`
TlsConfig TlsConfig `yaml:"tls"`
}
// NewClient loads the client config from the given configFilePath.
func NewClient(configFilePath string) (config ClientConfig, err error) {
log.Printf("Loading api client configuration from: %v\n", configFilePath)
var fileBytes []byte
fileBytes, err = ioutil.ReadFile(configFilePath)
if err != nil {
return
}
err = yaml.Unmarshal(fileBytes, &config)
if err != nil {
return
}
log.Printf("api client config: %#v\n", config)
return
}

View File

@@ -0,0 +1,37 @@
package apiconfig
import (
"gopkg.in/yaml.v2"
"io/ioutil"
"log"
)
// ClientServerConfig is the full client server configuration.
// wwapird is a client of wwapid.
// wwapird serves REST. (WareWulf API Rest Daemon)
type ClientServerConfig struct {
ClientApiConfig ClientApiConfig `yaml:"clientapi"`
ServerApiConfig ServerApiConfig `yaml:"serverapi"`
ClientTlsConfig TlsConfig `yaml:"clienttls"`
ServerTlsConfig TlsConfig `yaml:"servertls"`
}
// NewClientServer loads the client config from the given configFilePath.
func NewClientServer(configFilePath string) (config ClientServerConfig, err error) {
log.Printf("Loading api client server configuration from: %v\n", configFilePath)
var fileBytes []byte
fileBytes, err = ioutil.ReadFile(configFilePath)
if err != nil {
return
}
err = yaml.Unmarshal(fileBytes, &config)
if err != nil {
return
}
log.Printf("api client server config: %#v\n", config)
return
}

View File

@@ -0,0 +1,379 @@
package container
import (
"fmt"
"os"
"path"
"strconv"
"strings"
"github.com/containers/image/v5/types"
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
"github.com/hpcng/warewulf/internal/pkg/container"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/pkg/errors"
)
// TODO: SynchUser is not NYI in the API: See https://github.com/hpcng/warewulf/blob/main/internal/app/wwctl/container/syncuser/main.go
func ContainerBuild(cbp *wwapiv1.ContainerBuildParameter) (err error) {
if cbp == nil {
return fmt.Errorf("ContainerBuildParameter is nil")
}
var containers []string
if cbp.All {
containers, err = container.ListSources()
} else {
containers = cbp.ContainerNames
}
if len(containers) == 0 {
return
}
for _, c := range containers {
if !container.ValidSource(c) {
err = fmt.Errorf("VNFS name does not exist: %s", c)
wwlog.Printf(wwlog.ERROR, "%s\n", err)
return
}
err = container.Build(c, cbp.Force)
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not build container %s: %s\n", c, err)
return
}
}
if cbp.Default {
if len(containers) != 1 {
wwlog.Printf(wwlog.ERROR, "Can only set default for one container\n")
} else {
var nodeDB node.NodeYaml
nodeDB, err = node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
return
}
//TODO: Don't loop through profiles, instead have a nodeDB function that goes directly to the map
profiles, _ := nodeDB.FindAllProfiles()
for _, profile := range profiles {
wwlog.Printf(wwlog.DEBUG, "Looking for profile default: %s\n", profile.Id.Get())
if profile.Id.Get() == "default" {
wwlog.Printf(wwlog.DEBUG, "Found profile default, setting container name to: %s\n", containers[0])
profile.ContainerName.Set(containers[0])
err := nodeDB.ProfileUpdate(profile)
if err != nil {
return errors.Wrap(err, "failed to update node profile")
}
}
}
// TODO: Need a wrapper and flock around this. Sometimes we restart warewulfd and sometimes we don't.
err = nodeDB.Persist()
if err != nil {
return errors.Wrap(err, "failed to persist nodedb")
}
fmt.Printf("Set default profile to container: %s\n", containers[0])
}
}
return
}
func ContainerDelete(cdp *wwapiv1.ContainerDeleteParameter) (err error) {
if cdp == nil {
return fmt.Errorf("ContainerDeleteParameter is nil")
}
nodeDB, err := node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not open nodeDB: %s\n", err)
return
}
nodes, err := nodeDB.FindAllNodes()
if err != nil {
return
}
ARG_LOOP:
for i := 0; i < len(cdp.ContainerNames); i++ {
//_, arg := range args {
containerName := cdp.ContainerNames[i]
for _, n := range nodes {
if n.ContainerName.Get() == containerName {
wwlog.Printf(wwlog.ERROR, "Container is configured for nodes, skipping: %s\n", containerName)
continue ARG_LOOP
}
}
if !container.ValidSource(containerName) {
wwlog.Printf(wwlog.ERROR, "Container name is not a valid source: %s\n", containerName)
continue
}
err := container.DeleteSource(containerName)
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not remove source: %s\n", containerName)
} else {
fmt.Printf("Container has been deleted: %s\n", containerName)
}
}
return
}
func ContainerImport(cip *wwapiv1.ContainerImportParameter) (containerName string, err error) {
if cip == nil {
err = fmt.Errorf("NodeAddParameter is nil")
return
}
if cip.Name == "" {
name := path.Base(cip.Source)
fmt.Printf("Setting VNFS name: %s\n", name)
cip.Name = name
}
if !container.ValidName(cip.Name) {
err = fmt.Errorf("VNFS name contains illegal characters: %s", cip.Name)
wwlog.Printf(wwlog.ERROR, "%s\n", err)
return
}
containerName = cip.Name
fullPath := container.SourceDir(cip.Name)
if util.IsDir(fullPath) {
if cip.Force {
fmt.Printf("Overwriting existing VNFS\n")
err = os.RemoveAll(fullPath)
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
return
}
} else if cip.Update {
fmt.Printf("Updating existing VNFS\n")
} else {
err = fmt.Errorf("VNFS Name exists, specify --force, --update, or choose a different name: %s", cip.Name)
wwlog.Printf(wwlog.ERROR, "%s\n", err)
return
}
} else if strings.HasPrefix(cip.Source, "docker://") || strings.HasPrefix(cip.Source, "docker-daemon://") {
var sCtx *types.SystemContext
sCtx, err = getSystemContext()
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
// return was missing here. Was that deliberate?
}
err = container.ImportDocker(cip.Source, cip.Name, sCtx)
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not import image: %s\n", err)
_ = container.DeleteSource(cip.Name)
return
}
} else if util.IsDir(cip.Source) {
err = container.ImportDirectory(cip.Source, cip.Name)
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not import image: %s\n", err)
_ = container.DeleteSource(cip.Name)
return
}
} else {
err = fmt.Errorf("Invalid dir or uri: %s", cip.Source)
wwlog.Printf(wwlog.ERROR, "%s\n", err)
return
}
fmt.Printf("Updating the container's /etc/resolv.conf\n")
err = util.CopyFile("/etc/resolv.conf", path.Join(container.RootFsDir(cip.Name), "/etc/resolv.conf"))
if err != nil {
wwlog.Printf(wwlog.WARN, "Could not copy /etc/resolv.conf into container: %s\n", err)
}
fmt.Printf("Building container: %s\n", cip.Name)
err = container.Build(cip.Name, true)
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not build container %s: %s\n", cip.Name, err)
return
}
if cip.Default {
var nodeDB node.NodeYaml
nodeDB, err = node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
return
}
//TODO: Don't loop through profiles, instead have a nodeDB function that goes directly to the map
profiles, _ := nodeDB.FindAllProfiles()
for _, profile := range profiles {
wwlog.Printf(wwlog.DEBUG, "Looking for profile default: %s\n", profile.Id.Get())
if profile.Id.Get() == "default" {
wwlog.Printf(wwlog.DEBUG, "Found profile default, setting container name to: %s\n", cip.Name)
profile.ContainerName.Set(cip.Name)
err = nodeDB.ProfileUpdate(profile)
if err != nil {
err = errors.Wrap(err, "failed to update profile")
return
}
}
}
// TODO: We need this in a function with a flock around it.
// Also need to understand if the daemon restart is only to
// reload the config or if there is something more.
err = nodeDB.Persist()
if err != nil {
err = errors.Wrap(err, "failed to persist nodedb")
return
}
fmt.Printf("Set default profile to container: %s\n", cip.Name)
err = warewulfd.DaemonReload()
if err != nil {
err = errors.Wrap(err, "failed to reload warewulf daemon")
return
}
}
return
}
func ContainerList() (containerInfo []*wwapiv1.ContainerInfo, err error) {
var sources []string
sources, err = container.ListSources()
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
return
}
nodeDB, err := node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
return
}
nodes, err := nodeDB.FindAllNodes()
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
return
}
nodemap := make(map[string]int)
for _, n := range nodes {
nodemap[n.ContainerName.Get()]++
}
for _, source := range sources {
if nodemap[source] == 0 {
nodemap[source] = 0
}
wwlog.Printf(wwlog.DEBUG, "Finding kernel version for: %s\n", source)
kernelVersion := container.KernelVersion(source)
containerInfo = append(containerInfo, &wwapiv1.ContainerInfo{
Name: source,
NodeCount: uint32(nodemap[source]),
KernelVersion: kernelVersion,
})
}
return
}
func ContainerShow(csp *wwapiv1.ContainerShowParameter) (response *wwapiv1.ContainerShowResponse, err error) {
containerName := csp.ContainerName
if !container.ValidName(containerName) {
err = fmt.Errorf("%s is not a valid container", containerName)
return
}
rootFsDir := container.RootFsDir(containerName)
nodeDB, err := node.New()
if err != nil {
return
}
nodes, err := nodeDB.FindAllNodes()
if err != nil {
return
}
var nodeList []string
for _, n := range nodes {
if n.ContainerName.Get() == containerName {
nodeList = append(nodeList, n.Id.Get())
}
}
response = &wwapiv1.ContainerShowResponse{
Name: containerName,
Rootfs: rootFsDir,
Nodes: nodeList,
}
return
}
// Private helpers
func setOCICredentials(sCtx *types.SystemContext) error {
username, userSet := os.LookupEnv("WAREWULF_OCI_USERNAME")
password, passSet := os.LookupEnv("WAREWULF_OCI_PASSWORD")
if userSet || passSet {
if userSet && passSet {
sCtx.DockerAuthConfig = &types.DockerAuthConfig{
Username: username,
Password: password,
}
} else {
return fmt.Errorf("oci username and password env vars must be specified together")
}
}
return nil
}
func setNoHTTPSOpts(sCtx *types.SystemContext) error {
val, ok := os.LookupEnv("WAREWULF_OCI_NOHTTPS")
if !ok {
return nil
}
noHTTPS, err := strconv.ParseBool(val)
if err != nil {
return fmt.Errorf("while parsing insecure http option: %v", err)
}
// only set this if we want to disable, otherwise leave as undefined
if noHTTPS {
sCtx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(true)
}
sCtx.OCIInsecureSkipTLSVerify = noHTTPS
return nil
}
func getSystemContext() (sCtx *types.SystemContext, err error) {
sCtx = &types.SystemContext{}
if err := setOCICredentials(sCtx); err != nil {
return nil, err
}
if err := setNoHTTPSOpts(sCtx); err != nil {
return nil, err
}
return sCtx, nil
}

View File

@@ -0,0 +1,43 @@
package apiconfig
import (
"gopkg.in/yaml.v2"
"io/ioutil"
"log"
)
// ServerApiConfig contains configuration parameters for an API server.
type ServerApiConfig struct {
// Version contains the full version of the API server, eg: 1.0.0.
Version string `yaml:"version"`
// Prefix contains the version url prefix for the API server, eg: v1.
Prefix string `yaml:"prefix"`
// Port is the where the API server listens.
Port uint32 `yaml:"port"`
}
// ServerConfig is the full server configuration.
type ServerConfig struct {
ApiConfig ServerApiConfig `yaml:"api"`
TlsConfig TlsConfig `yaml:"tls"`
}
// NewServer loads the server config from the given configFilePath.
func NewServer(configFilePath string) (config ServerConfig, err error) {
log.Printf("Loading api server configuration from: %v\n", configFilePath)
var fileBytes []byte
fileBytes, err = ioutil.ReadFile(configFilePath)
if err != nil {
return
}
err = yaml.Unmarshal(fileBytes, &config)
if err != nil {
return
}
log.Printf("api server config: %#v\n", config)
return
}

View File

@@ -0,0 +1,20 @@
package apiconfig
// TlsConfig contains TLS configuration parameters for a client or server.
type TlsConfig struct {
// Enabled is true when secure.
Enabled bool `yaml:"enabled"`
// Cert is the path to the client or server certificate file.
Cert string `yaml:"cert,omitempty"`
// Key is the path to the client or server key file.
Key string `yaml:"key,omitempty"`
// CaCert is the path the CA certificate file.
CaCert string `yaml:"cacert,omitempty"`
// ConcatCert is for wwapird. http.ListenAndServeTLS wants the following
// cert file, so in our case this file contains `cat ${Cert} ${CaCert}`
//
// If the certificate is signed by a certificate authority, the certFile
// should be the concatenation of the server's certificate, any
// intermediates, and the CA's certificate
ConcatCert string `yaml:"concatcert,omitempty"`
}

View File

@@ -0,0 +1,395 @@
package container
import (
"fmt"
"os"
"path"
"strconv"
"strings"
"github.com/containers/image/v5/types"
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
"github.com/hpcng/warewulf/internal/pkg/container"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/pkg/errors"
)
func ContainerBuild(cbp *wwapiv1.ContainerBuildParameter) (err error) {
if cbp == nil {
return fmt.Errorf("ContainerBuildParameter is nil")
}
var containers []string
if cbp.All {
containers, err = container.ListSources()
} else {
containers = cbp.ContainerNames
}
if len(containers) == 0 {
return
}
for _, c := range containers {
if !container.ValidSource(c) {
err = fmt.Errorf("VNFS name does not exist: %s", c)
wwlog.Printf(wwlog.ERROR, "%s\n", err)
return
}
err = container.Build(c, cbp.Force)
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not build container %s: %s\n", c, err)
return
}
}
if cbp.Default {
if len(containers) != 1 {
wwlog.Printf(wwlog.ERROR, "Can only set default for one container\n")
} else {
var nodeDB node.NodeYaml
nodeDB, err = node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
return
}
//TODO: Don't loop through profiles, instead have a nodeDB function that goes directly to the map
profiles, _ := nodeDB.FindAllProfiles()
for _, profile := range profiles {
wwlog.Printf(wwlog.DEBUG, "Looking for profile default: %s\n", profile.Id.Get())
if profile.Id.Get() == "default" {
wwlog.Printf(wwlog.DEBUG, "Found profile default, setting container name to: %s\n", containers[0])
profile.ContainerName.Set(containers[0])
err := nodeDB.ProfileUpdate(profile)
if err != nil {
return errors.Wrap(err, "failed to update node profile")
}
}
}
// TODO: Need a wrapper and flock around this. Sometimes we restart warewulfd and sometimes we don't.
err = nodeDB.Persist()
if err != nil {
return errors.Wrap(err, "failed to persist nodedb")
}
fmt.Printf("Set default profile to container: %s\n", containers[0])
}
}
return
}
func ContainerDelete(cdp *wwapiv1.ContainerDeleteParameter) (err error) {
if cdp == nil {
return fmt.Errorf("ContainerDeleteParameter is nil")
}
nodeDB, err := node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not open nodeDB: %s\n", err)
return
}
nodes, err := nodeDB.FindAllNodes()
if err != nil {
return
}
ARG_LOOP:
for i := 0; i < len(cdp.ContainerNames); i++ {
//_, arg := range args {
containerName := cdp.ContainerNames[i]
for _, n := range nodes {
if n.ContainerName.Get() == containerName {
wwlog.Printf(wwlog.ERROR, "Container is configured for nodes, skipping: %s\n", containerName)
continue ARG_LOOP
}
}
if !container.ValidSource(containerName) {
wwlog.Printf(wwlog.ERROR, "Container name is not a valid source: %s\n", containerName)
continue
}
err := container.DeleteSource(containerName)
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not remove source: %s\n", containerName)
} else {
fmt.Printf("Container has been deleted: %s\n", containerName)
}
}
return
}
func ContainerImport(cip *wwapiv1.ContainerImportParameter) (containerName string, err error) {
if cip == nil {
err = fmt.Errorf("NodeAddParameter is nil")
return
}
if cip.Name == "" {
name := path.Base(cip.Source)
wwlog.Info("Setting VNFS name: %s", name)
cip.Name = name
}
if !container.ValidName(cip.Name) {
err = fmt.Errorf("VNFS name contains illegal characters: %s", cip.Name)
wwlog.Error(err.Error())
return
}
containerName = cip.Name
fullPath := container.SourceDir(cip.Name)
if util.IsDir(fullPath) {
if cip.Force {
wwlog.Info("Overwriting existing VNFS")
err = os.RemoveAll(fullPath)
if err != nil {
wwlog.ErrorExc(err, "")
return
}
} else if cip.Update {
wwlog.Info("Updating existing VNFS")
} else {
err = fmt.Errorf("VNFS Name exists, specify --force, --update, or choose a different name: %s", cip.Name)
wwlog.Error(err.Error())
return
}
} else if strings.HasPrefix(cip.Source, "docker://") || strings.HasPrefix(cip.Source, "docker-daemon://") {
var sCtx *types.SystemContext
sCtx, err = getSystemContext()
if err != nil {
wwlog.ErrorExc(err, "")
// TODO: mhink - return was missing here. Was that deliberate?
}
err = container.ImportDocker(cip.Source, cip.Name, sCtx)
if err != nil {
err = fmt.Errorf("could not import image: %s", err.Error())
wwlog.Error(err.Error())
_ = container.DeleteSource(cip.Name)
return
}
} else if util.IsDir(cip.Source) {
err = container.ImportDirectory(cip.Source, cip.Name)
if err != nil {
err = fmt.Errorf("could not import image: %s", err.Error())
wwlog.Error(err.Error())
_ = container.DeleteSource(cip.Name)
return
}
} else {
err = fmt.Errorf("invalid dir or uri: %s", cip.Source)
wwlog.Error(err.Error())
return
}
wwlog.Info("Updating the container's /etc/resolv.conf")
err = util.CopyFile("/etc/resolv.conf", path.Join(container.RootFsDir(cip.Name), "/etc/resolv.conf"))
if err != nil {
wwlog.Printf(wwlog.WARN, "Could not copy /etc/resolv.conf into container: %s\n", err)
}
err = container.SyncUids(cip.Name, !cip.SyncUser)
if err != nil && !cip.SyncUser {
err = fmt.Errorf("error in user sync, fix error and run 'syncuser' manually: %s", err)
wwlog.Error(err.Error())
return
}
wwlog.Info("Building container: %s", cip.Name)
err = container.Build(cip.Name, true)
if err != nil {
err = fmt.Errorf("could not build container %s: %s", cip.Name, err.Error())
wwlog.Error(err.Error())
return
}
if cip.Default {
var nodeDB node.NodeYaml
nodeDB, err = node.New()
if err != nil {
err = fmt.Errorf("could not open node configuration: %s", err.Error())
wwlog.Error(err.Error())
return
}
//TODO: Don't loop through profiles, instead have a nodeDB function that goes directly to the map
profiles, _ := nodeDB.FindAllProfiles()
for _, profile := range profiles {
wwlog.Printf(wwlog.DEBUG, "Looking for profile default: %s", profile.Id.Get())
if profile.Id.Get() == "default" {
wwlog.Printf(wwlog.DEBUG, "Found profile default, setting container name to: %s", cip.Name)
profile.ContainerName.Set(cip.Name)
err = nodeDB.ProfileUpdate(profile)
if err != nil {
err = errors.Wrap(err, "failed to update profile")
return
}
}
}
// TODO: We need this in a function with a flock around it.
// Also need to understand if the daemon restart is only to
// reload the config or if there is something more.
err = nodeDB.Persist()
if err != nil {
err = errors.Wrap(err, "failed to persist nodedb")
return
}
wwlog.Info("Set default profile to container: %s", cip.Name)
err = warewulfd.DaemonReload()
if err != nil {
err = errors.Wrap(err, "failed to reload warewulf daemon")
return
}
}
return
}
func ContainerList() (containerInfo []*wwapiv1.ContainerInfo, err error) {
var sources []string
sources, err = container.ListSources()
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
return
}
nodeDB, err := node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
return
}
nodes, err := nodeDB.FindAllNodes()
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
return
}
nodemap := make(map[string]int)
for _, n := range nodes {
nodemap[n.ContainerName.Get()]++
}
for _, source := range sources {
if nodemap[source] == 0 {
nodemap[source] = 0
}
wwlog.Printf(wwlog.DEBUG, "Finding kernel version for: %s\n", source)
kernelVersion := container.KernelVersion(source)
containerInfo = append(containerInfo, &wwapiv1.ContainerInfo{
Name: source,
NodeCount: uint32(nodemap[source]),
KernelVersion: kernelVersion,
})
}
return
}
func ContainerShow(csp *wwapiv1.ContainerShowParameter) (response *wwapiv1.ContainerShowResponse, err error) {
containerName := csp.ContainerName
if !container.ValidName(containerName) {
err = fmt.Errorf("%s is not a valid container", containerName)
return
}
rootFsDir := container.RootFsDir(containerName)
kernelVersion := container.KernelVersion(containerName)
if kernelVersion != "" {
kernelVersion = "not found"
fmt.Printf("Kernelversion: %s\n", kernelVersion)
}
nodeDB, err := node.New()
if err != nil {
return
}
nodes, err := nodeDB.FindAllNodes()
if err != nil {
return
}
var nodeList []string
for _, n := range nodes {
if n.ContainerName.Get() == containerName {
nodeList = append(nodeList, n.Id.Get())
}
}
response = &wwapiv1.ContainerShowResponse{
Name: containerName,
Rootfs: rootFsDir,
Nodes: nodeList,
KernelVersion: kernelVersion,
}
return
}
// Private helpers
func setOCICredentials(sCtx *types.SystemContext) error {
username, userSet := os.LookupEnv("WAREWULF_OCI_USERNAME")
password, passSet := os.LookupEnv("WAREWULF_OCI_PASSWORD")
if userSet || passSet {
if userSet && passSet {
sCtx.DockerAuthConfig = &types.DockerAuthConfig{
Username: username,
Password: password,
}
} else {
return fmt.Errorf("oci username and password env vars must be specified together")
}
}
return nil
}
func setNoHTTPSOpts(sCtx *types.SystemContext) error {
val, ok := os.LookupEnv("WAREWULF_OCI_NOHTTPS")
if !ok {
return nil
}
noHTTPS, err := strconv.ParseBool(val)
if err != nil {
return fmt.Errorf("while parsing insecure http option: %v", err)
}
// only set this if we want to disable, otherwise leave as undefined
if noHTTPS {
sCtx.DockerInsecureSkipTLSVerify = types.NewOptionalBool(true)
}
sCtx.OCIInsecureSkipTLSVerify = noHTTPS
return nil
}
func getSystemContext() (sCtx *types.SystemContext, err error) {
sCtx = &types.SystemContext{}
if err := setOCICredentials(sCtx); err != nil {
return nil, err
}
if err := setNoHTTPSOpts(sCtx); err != nil {
return nil, err
}
return sCtx, nil
}

View File

@@ -0,0 +1,988 @@
package node
import (
"encoding/json"
"fmt"
"net"
"net/http"
"os"
"strconv"
"strings"
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/hpcng/warewulf/pkg/hostlist"
"github.com/pkg/errors"
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
)
// NodeAdd adds nodes for management by Warewulf.
func NodeAdd(nap *wwapiv1.NodeAddParameter) (err error) {
if nap == nil {
return fmt.Errorf("NodeAddParameter is nil")
}
var count uint
nodeDB, err := node.New()
if err != nil {
return errors.Wrap(err, "failed to open node database")
}
node_args := hostlist.Expand(nap.NodeNames)
for _, a := range node_args {
var n node.NodeInfo
n, err = nodeDB.AddNode(a)
if err != nil {
return errors.Wrap(err, "failed to add node")
}
wwlog.Printf(wwlog.INFO, "Added node: %s\n", a)
if nap.Cluster != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting cluster name to: %s\n", n.Id.Get(), nap.Cluster)
n.ClusterName.Set(nap.Cluster)
err = nodeDB.NodeUpdate(n)
if err != nil {
return errors.Wrap(err, "failed to update node")
}
}
if nap.Netdev != "" {
err = checkNetNameRequired(nap.Netname)
if err != nil {
return
}
if _, ok := n.NetDevs[nap.Netname]; !ok {
var netdev node.NetDevEntry
n.NetDevs[nap.Netname] = &netdev
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting Device to: %s\n", n.Id.Get(), nap.Netname, nap.Netdev)
n.NetDevs[nap.Netname].Device.Set(nap.Netdev)
n.NetDevs[nap.Netname].OnBoot.SetB(true)
}
if nap.Ipaddr != "" {
err = checkNetNameRequired(nap.Netname)
if err != nil {
return
}
NewIpaddr := util.IncrementIPv4(nap.Ipaddr, count)
if _, ok := n.NetDevs[nap.Netname]; !ok {
var netdev node.NetDevEntry
n.NetDevs[nap.Netname] = &netdev
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting Ipaddr to: %s\n", n.Id.Get(), nap.Netname, NewIpaddr)
n.NetDevs[nap.Netname].Ipaddr.Set(NewIpaddr)
n.NetDevs[nap.Netname].OnBoot.SetB(true)
}
if nap.Netmask != "" {
err = checkNetNameRequired(nap.Netname)
if err != nil {
return
}
if _, ok := n.NetDevs[nap.Netname]; !ok {
return errors.New("network device does not exist: " + nap.Netname)
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting netmask to: %s\n", n.Id.Get(), nap.Netname, nap.Netmask)
n.NetDevs[nap.Netname].Netmask.Set(nap.Netmask)
}
if nap.Gateway != "" {
err = checkNetNameRequired(nap.Netname)
if err != nil {
return
}
if _, ok := n.NetDevs[nap.Netname]; !ok {
return errors.New("network device does not exist: " + nap.Netname)
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting gateway to: %s\n", n.Id.Get(), nap.Netname, nap.Gateway)
n.NetDevs[nap.Netname].Gateway.Set(nap.Gateway)
}
if nap.Hwaddr != "" {
if nap.Netname == "" {
return errors.New("you must include the '--netname' option")
}
if _, ok := n.NetDevs[nap.Netname]; !ok {
return errors.New("network device does not exist: " + nap.Netname)
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting HW address to: %s\n", n.Id.Get(), nap.Netname, nap.Hwaddr)
n.NetDevs[nap.Netname].Hwaddr.Set(nap.Hwaddr)
n.NetDevs[nap.Netname].OnBoot.SetB(true)
}
if nap.Type != "" {
if nap.Netname == "" {
return errors.New("you must include the '--netname' option")
}
if _, ok := n.NetDevs[nap.Netname]; !ok {
return errors.New("network device does not exist: " + nap.Netname)
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting Type to: %s\n", n.Id.Get(), nap.Netname, nap.Type)
n.NetDevs[nap.Netname].Type.Set(nap.Type)
}
if nap.Ipaddr6 != "" {
if nap.Netname == "" {
return errors.New("you must include the '--netname' option")
}
if _, ok := n.NetDevs[nap.Netname]; !ok {
return errors.New("network device does not exist: " + nap.Netname)
}
// just check if address is a valid ipv6 CIDR address
if _, _, err := net.ParseCIDR(nap.Ipaddr6); err != nil {
return errors.Errorf("%s is not a valid ipv6 address in CIDR notation", nap.Ipaddr6)
}
}
if nap.Discoverable {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting node to discoverable\n", n.Id.Get())
n.Discoverable.SetB(true)
}
err = nodeDB.NodeUpdate(n)
if err != nil {
return errors.Wrap(err, "failed to update nodedb")
}
count++
} // end for
err = nodeDB.Persist()
if err != nil {
return errors.Wrap(err, "failed to persist new node")
}
err = warewulfd.DaemonReload()
if err != nil {
return errors.Wrap(err, "failed to reload warewulf daemon")
}
return
}
// NodeDelete adds nodes for management by Warewulf.
func NodeDelete(ndp *wwapiv1.NodeDeleteParameter) (err error) {
var nodeList []node.NodeInfo
nodeList, err = NodeDeleteParameterCheck(ndp, false)
if err != nil {
return
}
nodeDB, err := node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Failed to open node database: %s\n", err)
return
}
for _, n := range nodeList {
err := nodeDB.DelNode(n.Id.Get())
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
} else {
//count++
fmt.Printf("Deleting node: %s\n", n.Id.Print())
}
}
err = nodeDB.Persist()
if err != nil {
return errors.Wrap(err, "failed to persist nodedb")
}
err = warewulfd.DaemonReload()
if err != nil {
return errors.Wrap(err, "failed to reload warewulf daemon")
}
return
}
// NodeDeleteParameterCheck does error checking on NodeDeleteParameter.
// Output to the console if console is true.
// Returns the nodes to delete.
func NodeDeleteParameterCheck(ndp *wwapiv1.NodeDeleteParameter, console bool) (nodeList []node.NodeInfo, err error) {
if ndp == nil {
err = fmt.Errorf("NodeDeleteParameter is nil")
return
}
nodeDB, err := node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Failed to open node database: %s\n", err)
return
}
nodes, err := nodeDB.FindAllNodes()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err)
return
}
node_args := hostlist.Expand(ndp.NodeNames)
for _, r := range node_args {
var match bool
for _, n := range nodes {
if n.Id.Get() == r {
nodeList = append(nodeList, n)
match = true
}
}
if !match {
fmt.Fprintf(os.Stderr, "ERROR: No match for node: %s\n", r)
}
}
if len(nodeList) == 0 {
fmt.Printf("No nodes found\n")
}
return
}
// NodeList lists all to none of the nodes managed by Warewulf.
func NodeList(nodeNames []string) (nodeInfo []*wwapiv1.NodeInfo, err error) {
// nil is okay for nodeNames
nodeDB, err := node.New()
if err != nil {
return
}
nodes, err := nodeDB.FindAllNodes()
if err != nil {
return
}
nodeNames = hostlist.Expand(nodeNames)
// Translate to the protobuf structure so wwapiv1 can use this across the wire.
// This is the same logic as was in wwctl.
for _, node := range node.FilterByName(nodes, nodeNames) {
var ni wwapiv1.NodeInfo
ni.Id = &wwapiv1.NodeField{
Source: node.Id.Source(),
Value: node.Id.Get(),
Print: node.Id.Print(),
}
ni.Comment = &wwapiv1.NodeField{
Source: node.Comment.Source(),
Value: node.Comment.Get(),
Print: node.Comment.Print(),
}
ni.Cluster = &wwapiv1.NodeField{
Source: node.ClusterName.Source(),
Value: node.ClusterName.Get(),
Print: node.ClusterName.Print(),
}
ni.Profiles = node.Profiles
ni.Discoverable = &wwapiv1.NodeField{
Source: node.Discoverable.Source(),
Value: strconv.FormatBool(node.Discoverable.GetB()),
Print: node.Discoverable.PrintB(),
}
ni.Container = &wwapiv1.NodeField{
Source: node.ContainerName.Source(),
Value: node.ContainerName.Get(),
Print: node.ContainerName.Print(),
}
ni.KernelOverride = &wwapiv1.NodeField{
Source: node.Kernel.Override.Source(),
Value: node.Kernel.Override.Get(),
Print: node.Kernel.Override.Print(),
}
ni.KernelArgs = &wwapiv1.NodeField{
Source: node.Kernel.Args.Source(),
Value: node.Kernel.Args.Get(),
Print: node.Kernel.Args.Print(),
}
ni.SystemOverlay = &wwapiv1.NodeField{
Source: node.SystemOverlay.Source(),
Value: node.SystemOverlay.Get(),
Print: node.SystemOverlay.Print(),
}
ni.RuntimeOverlay = &wwapiv1.NodeField{
Source: node.RuntimeOverlay.Source(),
Value: node.RuntimeOverlay.Get(),
Print: node.RuntimeOverlay.Print(),
}
ni.Ipxe = &wwapiv1.NodeField{
Source: node.Ipxe.Source(),
Value: node.Ipxe.Get(),
Print: node.Ipxe.Print(),
}
ni.Init = &wwapiv1.NodeField{
Source: node.Init.Source(),
Value: node.Init.Get(),
Print: node.Init.Print(),
}
ni.Root = &wwapiv1.NodeField{
Source: node.Root.Source(),
Value: node.Root.Get(),
Print: node.Root.Print(),
}
ni.AssetKey = &wwapiv1.NodeField{
Source: node.AssetKey.Source(),
Value: node.AssetKey.Get(),
Print: node.AssetKey.Print(),
}
ni.IpmiIpaddr = &wwapiv1.NodeField{
Source: node.Ipmi.Ipaddr.Source(),
Value: node.Ipmi.Ipaddr.Get(),
Print: node.Ipmi.Ipaddr.Print(),
}
ni.IpmiNetmask = &wwapiv1.NodeField{
Source: node.Ipmi.Netmask.Source(),
Value: node.Ipmi.Netmask.Get(),
Print: node.Ipmi.Netmask.Print(),
}
ni.IpmiPort = &wwapiv1.NodeField{
Source: node.Ipmi.Port.Source(),
Value: node.Ipmi.Port.Get(),
Print: node.Ipmi.Port.Print(),
}
ni.IpmiGateway = &wwapiv1.NodeField{
Source: node.Ipmi.Gateway.Source(),
Value: node.Ipmi.Gateway.Get(),
Print: node.Ipmi.Gateway.Print(),
}
ni.IpmiUserName = &wwapiv1.NodeField{
Source: node.Ipmi.UserName.Source(),
Value: node.Ipmi.UserName.Get(),
Print: node.Ipmi.UserName.Print(),
}
ni.IpmiPassword = &wwapiv1.NodeField{
Source: node.Ipmi.Password.Source(),
Value: node.Ipmi.Password.Get(),
Print: node.Ipmi.Password.Print(), // TODO: Password was removed from pprinted output, at least in some places.
}
ni.IpmiInterface = &wwapiv1.NodeField{
Source: node.Ipmi.Interface.Source(),
Value: node.Ipmi.Interface.Get(),
Print: node.Ipmi.Interface.Print(),
}
for keyname, keyvalue := range node.Tags {
ni.Tags[keyname].Source = keyvalue.Source()
ni.Tags[keyname].Value = keyvalue.Get()
ni.Tags[keyname].Print = keyvalue.Print()
}
ni.NetDevs = map[string]*wwapiv1.NetDev{}
for name, netdev := range node.NetDevs {
ni.NetDevs[name] = &wwapiv1.NetDev{
Device: &wwapiv1.NodeField{
Source: netdev.Device.Source(),
Value: netdev.Device.Get(),
Print: netdev.Device.Print(),
},
Hwaddr: &wwapiv1.NodeField{
Source: netdev.Hwaddr.Source(),
Value: netdev.Hwaddr.Get(),
Print: netdev.Hwaddr.Print(),
},
Ipaddr: &wwapiv1.NodeField{
Source: netdev.Ipaddr.Source(),
Value: netdev.Ipaddr.Get(),
Print: netdev.Ipaddr.Print(),
},
Netmask: &wwapiv1.NodeField{
Source: netdev.Netmask.Source(),
Value: netdev.Netmask.Get(),
Print: netdev.Netmask.Print(),
},
Gateway: &wwapiv1.NodeField{
Source: netdev.Gateway.Source(),
Value: netdev.Gateway.Get(),
Print: netdev.Gateway.Print(),
},
Type: &wwapiv1.NodeField{
Source: netdev.Type.Source(),
Value: netdev.Type.Get(),
Print: netdev.Type.Print(),
},
Onboot: &wwapiv1.NodeField{
Source: netdev.OnBoot.Source(),
Value: strconv.FormatBool(netdev.OnBoot.GetB()),
Print: netdev.OnBoot.PrintB(),
},
Primary: &wwapiv1.NodeField{
Source: netdev.Primary.Source(),
Value: strconv.FormatBool(netdev.Primary.GetB()),
Print: netdev.Primary.PrintB(),
},
}
}
nodeInfo = append(nodeInfo, &ni)
}
return
}
// NodeSet is the wwapiv1 implmentation for updating node fields.
func NodeSet(set *wwapiv1.NodeSetParameter) (err error) {
if set == nil {
return fmt.Errorf("NodeAddParameter is nil")
}
var nodeDB node.NodeYaml
nodeDB, _, err = NodeSetParameterCheck(set, false)
if err != nil {
return
}
return nodeDbSave(&nodeDB)
}
// NodeSetParameterCheck does error checking on NodeSetParameter.
// Output to the console if console is true.
// TODO: Determine if the console switch does wwlog or not.
// - console may end up being textOutput?
func NodeSetParameterCheck(set *wwapiv1.NodeSetParameter, console bool) (nodeDB node.NodeYaml, nodeCount uint, err error) {
if set == nil {
err = fmt.Errorf("Node set parameter is nil")
if console {
fmt.Printf("%v\n", err)
return
}
}
if set.NodeNames == nil {
err = fmt.Errorf("Node set parameter: NodeNames is nil")
if console {
fmt.Printf("%v\n", err)
return
}
}
nodeDB, err = node.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err)
return
}
nodes, err := nodeDB.FindAllNodes()
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err)
return
}
// Note: This does not do expansion on the nodes.
if set.AllNodes || (len(set.NodeNames) == 0 && len(nodes) > 0) {
if console {
fmt.Printf("\n*** WARNING: This command will modify all nodes! ***\n\n")
}
} else {
nodes = node.FilterByName(nodes, set.NodeNames)
}
if len(nodes) == 0 {
if console {
fmt.Printf("No nodes found\n")
}
return
}
for _, n := range nodes {
wwlog.Printf(wwlog.VERBOSE, "Evaluating node: %s\n", n.Id.Get())
if set.Comment != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting comment to: %s\n", n.Id.Get(), set.Comment)
n.Comment.Set(set.Comment)
}
if set.Container != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting container name to: %s\n", n.Id.Get(), set.Container)
n.ContainerName.Set(set.Container)
}
if set.Init != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting init command to: %s\n", n.Id.Get(), set.Init)
n.Init.Set(set.Init)
}
if set.Root != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting root to: %s\n", n.Id.Get(), set.Root)
n.Root.Set(set.Root)
}
if set.AssetKey != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting asset key to: %s\n", n.Id.Get(), set.AssetKey)
n.AssetKey.Set(set.AssetKey)
}
if set.KernelOverride != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting kernel override to: %s\n", n.Id.Get(), set.KernelOverride)
n.Kernel.Override.Set(set.KernelOverride)
}
if set.KernelArgs != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting kernel args to: %s\n", n.Id.Get(), set.KernelArgs)
n.Kernel.Args.Set(set.KernelArgs)
}
if set.Cluster != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting cluster name to: %s\n", n.Id.Get(), set.Cluster)
n.ClusterName.Set(set.Cluster)
}
if set.Ipxe != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting iPXE template to: %s\n", n.Id.Get(), set.Ipxe)
n.Ipxe.Set(set.Ipxe)
}
if len(set.RuntimeOverlay) != 0 {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting runtime overlay to: %s\n", n.Id.Get(), set.RuntimeOverlay)
n.RuntimeOverlay.SetSlice(set.RuntimeOverlay)
}
if len(set.SystemOverlay) != 0 {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting system overlay to: %s\n", n.Id.Get(), set.SystemOverlay)
n.SystemOverlay.SetSlice(set.SystemOverlay)
}
if set.IpmiIpaddr != "" {
newIpaddr := util.IncrementIPv4(set.IpmiIpaddr, nodeCount)
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI IP address to: %s\n", n.Id.Get(), newIpaddr)
n.Ipmi.Ipaddr.Set(newIpaddr)
}
if set.IpmiNetmask != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI netmask to: %s\n", n.Id.Get(), set.IpmiNetmask)
n.Ipmi.Netmask.Set(set.IpmiNetmask)
}
if set.IpmiPort != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI port to: %s\n", n.Id.Get(), set.IpmiPort)
n.Ipmi.Port.Set(set.IpmiPort)
}
if set.IpmiGateway != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI gateway to: %s\n", n.Id.Get(), set.IpmiGateway)
n.Ipmi.Gateway.Set(set.IpmiGateway)
}
if set.IpmiUsername != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI IP username to: %s\n", n.Id.Get(), set.IpmiUsername)
n.Ipmi.UserName.Set(set.IpmiUsername)
}
if set.IpmiPassword != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI IP password to: %s\n", n.Id.Get(), set.IpmiPassword)
n.Ipmi.Password.Set(set.IpmiPassword)
}
if set.IpmiInterface != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting IPMI IP interface to: %s\n", n.Id.Get(), set.IpmiInterface)
n.Ipmi.Interface.Set(set.IpmiInterface)
}
if set.IpmiWrite == "yes" || set.Onboot == "y" || set.Onboot == "1" || set.Onboot == "true" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting Ipmiwrite to %s\n", n.Id.Get(), set.IpmiWrite)
n.Ipmi.Write.SetB(true)
} else {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting Ipmiwrite to %s\n", n.Id.Get(), set.IpmiWrite)
n.Ipmi.Write.SetB(false)
}
if set.Discoverable {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting node to discoverable\n", n.Id.Get())
n.Discoverable.SetB(true)
}
if set.Undiscoverable {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting node to undiscoverable\n", n.Id.Get())
n.Discoverable.SetB(false)
}
if set.Profile != "" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting profiles to: %s\n", n.Id.Get(), set.Profile)
n.Profiles = []string{set.Profile}
}
if len(set.ProfileAdd) > 0 {
for _, p := range set.ProfileAdd {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, adding profile '%s'\n", n.Id.Get(), p)
n.Profiles = util.SliceAddUniqueElement(n.Profiles, p)
}
}
if len(set.ProfileDelete) > 0 {
for _, p := range set.ProfileDelete {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, deleting profile '%s'\n", n.Id.Get(), p)
n.Profiles = util.SliceRemoveElement(n.Profiles, p)
}
}
if set.Netname != "" {
if _, ok := n.NetDevs[set.Netname]; !ok {
var nd node.NetDevEntry
nd.Tags = make(map[string]*node.Entry)
n.NetDevs[set.Netname] = &nd
if set.Netdev == "" {
n.NetDevs[set.Netname].Device.Set(set.Netname)
}
}
var def bool = true
// NOTE: This is overriding parameters passed in by the caller.
set.Onboot = "yes"
for _, n := range n.NetDevs {
if n.Primary.GetB() {
def = false
}
}
if def {
set.NetDefault = "yes"
}
}
if set.Netdev != "" {
err = checkNetNameRequired(set.Netname)
if err != nil {
return
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting net Device to: %s\n", n.Id.Get(), set.Netname, set.Netdev)
n.NetDevs[set.Netname].Device.Set(set.Netdev)
}
if set.Ipaddr != "" {
err = checkNetNameRequired(set.Netname)
if err != nil {
return
}
newIpaddr := util.IncrementIPv4(set.Ipaddr, nodeCount)
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting Ipaddr to: %s\n", n.Id.Get(), set.Netname, newIpaddr)
n.NetDevs[set.Netname].Ipaddr.Set(newIpaddr)
}
if set.Netmask != "" {
err = checkNetNameRequired(set.Netname)
if err != nil {
return
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting netmask to: %s\n", n.Id.Get(), set.Netname, set.Netmask)
n.NetDevs[set.Netname].Netmask.Set(set.Netmask)
}
if set.Gateway != "" {
err = checkNetNameRequired(set.Netname)
if err != nil {
return
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting gateway to: %s\n", n.Id.Get(), set.Netname, set.Gateway)
n.NetDevs[set.Netname].Gateway.Set(set.Gateway)
}
if set.Hwaddr != "" {
err = checkNetNameRequired(set.Netname)
if err != nil {
return
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting HW address to: %s\n", n.Id.Get(), set.Netname, set.Hwaddr)
n.NetDevs[set.Netname].Hwaddr.Set(strings.ToLower(set.Hwaddr))
}
if set.Type != "" {
err = checkNetNameRequired(set.Netname)
if err != nil {
return
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting Type %s\n", n.Id.Get(), set.Netname, set.Type)
n.NetDevs[set.Netname].Type.Set(set.Type)
}
if set.Onboot != "" {
err = checkNetNameRequired(set.Netname)
if err != nil {
return
}
if set.Onboot == "yes" || set.Onboot == "y" || set.Onboot == "1" || set.Onboot == "true" {
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting ONBOOT\n", n.Id.Get(), set.Netname)
n.NetDevs[set.Netname].OnBoot.SetB(true)
} else {
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Unsetting ONBOOT\n", n.Id.Get(), set.Netname)
n.NetDevs[set.Netname].OnBoot.SetB(false)
}
}
if set.NetDefault != "" {
if set.Netname == "" {
err = fmt.Errorf("You must include the '--netname' option")
wwlog.Printf(wwlog.ERROR, fmt.Sprintf("%v\n", err.Error()))
return
}
if set.NetDefault == "yes" || set.NetDefault == "y" || set.NetDefault == "1" || set.NetDefault == "true" {
// Set all other devices to non-default
for _, n := range n.NetDevs {
n.Primary.SetB(false)
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting PRIMARY\n", n.Id.Get(), set.Netname)
n.NetDevs[set.Netname].Primary.SetB(true)
} else {
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Unsetting PRIMARY\n", n.Id.Get(), set.Netname)
n.NetDevs[set.Netname].Primary.SetB(false)
}
}
if set.NetdevDelete {
err = checkNetNameRequired(set.Netname)
if err != nil {
return
}
if _, ok := n.NetDevs[set.Netname]; !ok {
err = fmt.Errorf("Network device name doesn't exist: %s", set.Netname)
wwlog.Printf(wwlog.ERROR, fmt.Sprintf("%v\n", err.Error()))
return
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Deleting network device: %s\n", n.Id.Get(), set.Netname)
delete(n.NetDevs, set.Netname)
}
if len(set.Tags) > 0 {
for _, t := range set.Tags {
keyval := strings.SplitN(t, "=", 2)
key := keyval[0]
val := keyval[1]
if _, ok := n.Tags[key]; !ok {
var nd node.Entry
n.Tags[key] = &nd
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting Tag '%s'='%s'\n", n.Id.Get(), key, val)
n.Tags[key].Set(val)
}
}
if len(set.TagsDelete) > 0 {
for _, t := range set.TagsDelete {
keyval := strings.SplitN(t, "=", 1)
key := keyval[0]
if _, ok := n.Tags[key]; !ok {
wwlog.Printf(wwlog.WARN, "Key does not exist: %s\n", key)
os.Exit(1)
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Deleting tag: %s\n", n.Id.Get(), key)
delete(n.Tags, key)
}
}
if len(set.NetTags) > 0 {
for _, t := range set.NetTags {
keyval := strings.SplitN(t, "=", 2)
key := keyval[0]
val := keyval[1]
if _, ok := n.NetDevs[set.Netname].Tags[key]; !ok {
var nd node.Entry
n.NetDevs[set.Netname].Tags[key] = &nd
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting NETTAG '%s'='%s'\n", n.Id.Get(), set.Netname, key, val)
n.NetDevs[set.Netname].Tags[key].Set(val)
}
}
if len(set.NetDeleteTags) > 0 {
for _, t := range set.NetDeleteTags {
keyval := strings.SplitN(t, "=", 1)
key := keyval[0]
if _, ok := n.NetDevs[set.Netname].Tags[key]; !ok {
wwlog.Printf(wwlog.WARN, "Node: %s:%s Key %s does not exist\n", n.Id.Get(), set.Netname, key)
os.Exit(1)
}
wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Deleting Tag %s\n", n.Id.Get(), set.Netname, key)
delete(n.NetDevs[set.Netname].Tags, key)
}
}
err := nodeDB.NodeUpdate(n)
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
os.Exit(1)
}
nodeCount++
}
return
}
// NodeStatus returns the imaging state for nodes.
// This requires warewulfd.
func NodeStatus(nodeNames []string) (nodeStatusResponse *wwapiv1.NodeStatusResponse, err error) {
// Local structs for translating json from warewulfd.
type nodeStatusInternal struct {
NodeName string `json:"node name"`
Stage string `json:"stage"`
Sent string `json:"sent"`
Ipaddr string `json:"ipaddr"`
Lastseen int64 `json:"last seen"`
}
// all status is a map with one key (nodes)
// and maps of [nodeName]NodeStatus underneath.
type allStatus struct {
Nodes map[string]*nodeStatusInternal `json:"nodes"`
}
controller, err := warewulfconf.New()
if err != nil {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
return
}
if controller.Ipaddr == "" {
err = fmt.Errorf("The Warewulf Server IP Address is not properly configured")
wwlog.Printf(wwlog.ERROR, fmt.Sprintf("%v\n", err.Error()))
return
}
statusURL := fmt.Sprintf("http://%s:%d/status", controller.Ipaddr, controller.Warewulf.Port)
wwlog.Printf(wwlog.VERBOSE, "Connecting to: %s\n", statusURL)
resp, err := http.Get(statusURL)
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not connect to Warewulf server: %s\n", err)
return
}
defer resp.Body.Close()
decoder := json.NewDecoder(resp.Body)
var wwNodeStatus allStatus
err = decoder.Decode(&wwNodeStatus)
if err != nil {
wwlog.Printf(wwlog.ERROR, "Could not decode JSON: %s\n", err)
return
}
// Translate struct and filter.
nodeStatusResponse = &wwapiv1.NodeStatusResponse{}
if len(nodeNames) == 0 {
for _, v := range wwNodeStatus.Nodes {
nodeStatusResponse.NodeStatus = append(nodeStatusResponse.NodeStatus,
&wwapiv1.NodeStatus{
NodeName: v.NodeName,
Stage: v.Stage,
Sent: v.Sent,
Ipaddr: v.Ipaddr,
Lastseen: v.Lastseen,
})
}
} else {
nodeList := hostlist.Expand(nodeNames)
for _, v := range wwNodeStatus.Nodes {
for j := 0; j < len(nodeList); j++ {
if v.NodeName == nodeList[j] {
nodeStatusResponse.NodeStatus = append(nodeStatusResponse.NodeStatus,
&wwapiv1.NodeStatus{
NodeName: v.NodeName,
Stage: v.Stage,
Sent: v.Sent,
Ipaddr: v.Ipaddr,
Lastseen: v.Lastseen,
})
break
}
}
}
}
return
}
// checkNetNameRequired is a helper for determining if netname is set.
// Certain settings require it.
func checkNetNameRequired(netname string) (err error) {
if netname == "" {
err = fmt.Errorf("You must include the '--netname' option")
wwlog.Printf(wwlog.ERROR, fmt.Sprintf("%v\n", err.Error()))
}
return
}
// nodeDbSave persists the nodeDB to disk and restarts warewulfd.
// TODO: We will likely need locking around anything changing nodeDB
// or restarting warewulfd. Determine if the reason for restart is
// just to reinitialize warewulfd with the new nodeDB or if there is
// something more to it.
func nodeDbSave(nodeDB *node.NodeYaml) (err error) {
err = nodeDB.Persist()
if err != nil {
return errors.Wrap(err, "failed to persist nodedb")
}
err = warewulfd.DaemonReload()
if err != nil {
return errors.Wrap(err, "failed to reload warewulf daemon")
}
return
}

View File

@@ -0,0 +1,317 @@
// Routes for the wwapi (WareWulf API).
// TODO: Try protoc-gen-doc for generating documentation.
syntax = "proto3";
option go_package = "internal/pkg/api/routes/wwapiv1;wwapiv1";
package wwapi.v1;
import "google/protobuf/empty.proto";
import "google/api/annotations.proto";
// Container
// ContainerBuildParameter contains input for building zero or more containers.
message ContainerBuildParameter {
repeated string containerNames = 1;
bool force = 2;
bool all = 3;
bool default = 4;
}
// ContainerDeleteParameter contains input for removing containers from Warewulf
// management.
message ContainerDeleteParameter {
repeated string containerNames = 1;
}
// ContainerImportParameter has all input for importing a container.
message ContainerImportParameter{
string source = 1; // container source uri
string name = 2; // container name
bool force = 3;
bool update = 4;
bool build = 5;
bool default = 6;
bool syncUser = 7;
}
// ContainerInfo has data on each container. This is emitted in the
// ContainerListResponse.
message ContainerInfo {
string name = 1;
uint32 nodeCount = 2;
string kernelVersion = 3;
}
// ContainerListResponse has all information that ContainerList provides.
message ContainerListResponse {
repeated ContainerInfo containers = 1;
}
// ContainerShowParameter is the input for ContainerShow.
message ContainerShowParameter {
string containerName = 1;
}
// ContainerShowResponse has all information emitted on ContainerShow.
message ContainerShowResponse {
string Name = 1;
string Rootfs = 2;
repeated string Nodes = 3;
string KernelVersion = 4;
}
// ContainerSyncUserParameter is the input for ContainerSyncUser.
message ContainerSyncUserParameter {
string containerName = 1;
}
// Nodes
// NodeNames is an array of node ids.
message NodeNames {
repeated string nodeNames = 1;
}
// NodeField contains data output on NodeList.
message NodeField {
string source = 1;
string value = 2; // TODO: Variable name okay?
string print = 3; // Empty values printed as -- in wwctl.
}
// NetDev is network devices (NICs) on a node.
message NetDev {
NodeField type = 1;
NodeField onboot = 2;
NodeField device = 3;
NodeField hwaddr = 4;
NodeField ipaddr = 5;
NodeField netmask = 6;
NodeField gateway = 7;
NodeField primary = 8;
map<string, NodeField> Tags = 9;
}
// NodeInfo contains details about a node managed by Warewulf/
message NodeInfo {
NodeField id = 1;
NodeField comment = 2;
NodeField cluster = 3;
NodeField discoverable = 4;
NodeField container = 5;
NodeField kernelOverride = 6;
NodeField kernelArgs = 7;
NodeField systemOverlay = 8;
NodeField runtimeOverlay = 9;
NodeField ipxe = 10;
NodeField init = 11;
NodeField root = 12;
NodeField assetKey = 13;
NodeField ipmiIpaddr = 14;
NodeField ipmiNetmask = 15;
NodeField ipmiPort = 16;
NodeField ipmiGateway = 17;
NodeField ipmiUserName = 18;
NodeField ipmiInterface = 19;
NodeField ipmiPassword = 20;
repeated string profiles = 21;
repeated string groupProfiles = 22;
map<string, NetDev> NetDevs = 23;
map<string, NodeField> Tags = 24;
map<string, NodeField> Keys = 25; // TODO: We may not need this. Tags may be it. Ask Greg.
}
// NodeListResponse is the output of NodeList.
message NodeListResponse {
repeated NodeInfo nodes = 1;
}
// NodeAddParameter contains all input for adding a node to be managed by
// Warewulf.
message NodeAddParameter {
string cluster = 1;
bool discoverable = 2;
string gateway = 3;
string hwaddr = 4;
string ipaddr = 5;
string netdev = 6;
string netmask = 7;
string netname = 8;
string type = 9;
repeated string nodeNames = 10;
string ipaddr6 = 11;
}
// NodeDeleteParameter contains input for removing nodes from Warewulf
// management.
message NodeDeleteParameter {
bool force = 1;
repeated string nodeNames = 2;
}
// NodeSetParameter contains all fields for updating aspects of nodes managed
// by Warewulf.
message NodeSetParameter {
string comment = 1;
string container = 2;
string kernelOverride = 3;
string kernelArgs = 4;
string netname = 5;
string netdev = 6;
string ipaddr = 7;
string netmask = 8;
string gateway = 9;
string hwaddr = 10;
string type = 11;
string onboot = 12;
string netDefault = 13;
bool netdevDelete = 14;
string cluster = 15;
string ipxe = 16;
string initOverlay = 17;
repeated string runtimeOverlay = 18;
repeated string systemOverlay = 19;
string ipmiIpaddr = 20;
string ipmiNetmask = 21;
string ipmiPort = 22;
string ipmiGateway = 23;
string ipmiUsername = 24;
string ipmiPassword = 25;
string ipmiInterface = 26;
bool allNodes = 27;
string profile = 28;
repeated string profileAdd = 29;
repeated string profileDelete = 30;
bool force = 31;
string init = 32;
bool discoverable = 33;
bool undiscoverable = 34;
string root = 35;
repeated string tags = 36;
repeated string tagsDelete = 37;
string assetKey = 38;
repeated string nodeNames = 39;
string ipmiWrite = 40;
repeated string NetTags = 41;
repeated string NetDeleteTags = 42;
}
// NodeStatus contains information about the imaging status per node.
message NodeStatus {
string nodeName = 1; // Name (Id) of the node.
string stage = 2; // Stage of imaging.
string sent = 3; // Last overlay sent.
string ipaddr = 4; // Node IP address.
int64 lastseen = 5; // Time in seconds since the node was last seen.
}
// NodeStatusResponse contains NodeStatus for zero or more nodes.
message NodeStatusResponse {
repeated NodeStatus nodeStatus = 1;
}
// Version
// VersionReponse contains versions of the software.
message VersionResponse {
string apiPrefix = 1;
string apiVersion = 2;
string warewulfVersion = 3;
}
// WWApi defines the wwapid service web interface.
service WWApi {
// Containers
// ContainerBuild builds zero or more containers.
rpc ContainerBuild(ContainerBuildParameter) returns (ContainerListResponse) {
option (google.api.http) = {
post: "/v1/containerbuild"
body: "*"
};
}
// ContainerDelete removes one or more container from Warewulf management.
rpc ContainerDelete(ContainerDeleteParameter) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/container"
};
}
// ContainerImport imports a container to Warewulf.
rpc ContainerImport(ContainerImportParameter) returns (ContainerListResponse) {
option(google.api.http) = {
post: "/v1/container"
body: "*"
};
}
// ContainerList lists ContainerInfo for each container.
rpc ContainerList(google.protobuf.Empty) returns (ContainerListResponse) {
option (google.api.http) = {
get: "/v1/container"
};
}
// ContainerShow lists ContainerShow for each container.
rpc ContainerShow(ContainerShowParameter) returns (ContainerShowResponse) {
option (google.api.http) = {
get: "/v1/containershow"
};
}
// Nodes
// NodeAdd adds one or more nodes for management by Warewulf and returns
// the added nodes. Node fields may be shimmed in per profiles.
rpc NodeAdd(NodeAddParameter) returns (NodeListResponse) {
option (google.api.http) = {
post: "/v1/node"
body: "*"
};
}
// NodeDelete removes one or more nodes from Warewulf management.
rpc NodeDelete(NodeDeleteParameter) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/node"
};
}
// NodeList lists some or all nodes managed by Warewulf.
rpc NodeList(NodeNames) returns (NodeListResponse) {
option (google.api.http) = {
get: "/v1/node"
};
}
// NodeSet updates node fields for one or more nodes.
rpc NodeSet(NodeSetParameter) returns (NodeListResponse) {
option (google.api.http) = {
post: "/v1/nodeset" // TODO: This should be a patch. Had trouble getting patch to work at all.
body: "*"
};
}
// NodeStatus returns the imaging state for nodes.
// This requires warewulfd.
rpc NodeStatus(NodeNames) returns (NodeStatusResponse) {
option (google.api.http) = {
get: "/v1/nodestatus"
};
}
// Version returns the wwapi version, the api prefix, and the Warewulf
// version. This is also useful for testing if the service is up.
rpc Version(google.protobuf.Empty) returns (VersionResponse) {
option (google.api.http) = {
get: "/version"
};
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,978 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: routes.proto
/*
Package wwapiv1 is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package wwapiv1
import (
"context"
"io"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/emptypb"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = metadata.Join
func request_WWApi_ContainerBuild_0(ctx context.Context, marshaler runtime.Marshaler, client WWApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContainerBuildParameter
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ContainerBuild(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WWApi_ContainerBuild_0(ctx context.Context, marshaler runtime.Marshaler, server WWApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContainerBuildParameter
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ContainerBuild(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_WWApi_ContainerDelete_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_WWApi_ContainerDelete_0(ctx context.Context, marshaler runtime.Marshaler, client WWApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContainerDeleteParameter
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WWApi_ContainerDelete_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ContainerDelete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WWApi_ContainerDelete_0(ctx context.Context, marshaler runtime.Marshaler, server WWApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContainerDeleteParameter
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WWApi_ContainerDelete_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ContainerDelete(ctx, &protoReq)
return msg, metadata, err
}
func request_WWApi_ContainerImport_0(ctx context.Context, marshaler runtime.Marshaler, client WWApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContainerImportParameter
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ContainerImport(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WWApi_ContainerImport_0(ctx context.Context, marshaler runtime.Marshaler, server WWApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContainerImportParameter
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ContainerImport(ctx, &protoReq)
return msg, metadata, err
}
func request_WWApi_ContainerList_0(ctx context.Context, marshaler runtime.Marshaler, client WWApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq emptypb.Empty
var metadata runtime.ServerMetadata
msg, err := client.ContainerList(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WWApi_ContainerList_0(ctx context.Context, marshaler runtime.Marshaler, server WWApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq emptypb.Empty
var metadata runtime.ServerMetadata
msg, err := server.ContainerList(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_WWApi_ContainerShow_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_WWApi_ContainerShow_0(ctx context.Context, marshaler runtime.Marshaler, client WWApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContainerShowParameter
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WWApi_ContainerShow_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ContainerShow(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WWApi_ContainerShow_0(ctx context.Context, marshaler runtime.Marshaler, server WWApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ContainerShowParameter
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WWApi_ContainerShow_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ContainerShow(ctx, &protoReq)
return msg, metadata, err
}
func request_WWApi_NodeAdd_0(ctx context.Context, marshaler runtime.Marshaler, client WWApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq NodeAddParameter
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.NodeAdd(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WWApi_NodeAdd_0(ctx context.Context, marshaler runtime.Marshaler, server WWApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq NodeAddParameter
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.NodeAdd(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_WWApi_NodeDelete_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_WWApi_NodeDelete_0(ctx context.Context, marshaler runtime.Marshaler, client WWApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq NodeDeleteParameter
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WWApi_NodeDelete_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.NodeDelete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WWApi_NodeDelete_0(ctx context.Context, marshaler runtime.Marshaler, server WWApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq NodeDeleteParameter
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WWApi_NodeDelete_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.NodeDelete(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_WWApi_NodeList_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_WWApi_NodeList_0(ctx context.Context, marshaler runtime.Marshaler, client WWApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq NodeNames
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WWApi_NodeList_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.NodeList(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WWApi_NodeList_0(ctx context.Context, marshaler runtime.Marshaler, server WWApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq NodeNames
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WWApi_NodeList_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.NodeList(ctx, &protoReq)
return msg, metadata, err
}
func request_WWApi_NodeSet_0(ctx context.Context, marshaler runtime.Marshaler, client WWApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq NodeSetParameter
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.NodeSet(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WWApi_NodeSet_0(ctx context.Context, marshaler runtime.Marshaler, server WWApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq NodeSetParameter
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.NodeSet(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_WWApi_NodeStatus_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_WWApi_NodeStatus_0(ctx context.Context, marshaler runtime.Marshaler, client WWApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq NodeNames
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WWApi_NodeStatus_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.NodeStatus(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WWApi_NodeStatus_0(ctx context.Context, marshaler runtime.Marshaler, server WWApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq NodeNames
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WWApi_NodeStatus_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.NodeStatus(ctx, &protoReq)
return msg, metadata, err
}
func request_WWApi_Version_0(ctx context.Context, marshaler runtime.Marshaler, client WWApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq emptypb.Empty
var metadata runtime.ServerMetadata
msg, err := client.Version(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WWApi_Version_0(ctx context.Context, marshaler runtime.Marshaler, server WWApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq emptypb.Empty
var metadata runtime.ServerMetadata
msg, err := server.Version(ctx, &protoReq)
return msg, metadata, err
}
// RegisterWWApiHandlerServer registers the http handlers for service WWApi to "mux".
// UnaryRPC :call WWApiServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterWWApiHandlerFromEndpoint instead.
func RegisterWWApiHandlerServer(ctx context.Context, mux *runtime.ServeMux, server WWApiServer) error {
mux.Handle("POST", pattern_WWApi_ContainerBuild_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/wwapi.v1.WWApi/ContainerBuild", runtime.WithHTTPPathPattern("/v1/containerbuild"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WWApi_ContainerBuild_0(ctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_ContainerBuild_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_WWApi_ContainerDelete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/wwapi.v1.WWApi/ContainerDelete", runtime.WithHTTPPathPattern("/v1/container"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WWApi_ContainerDelete_0(ctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_ContainerDelete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_WWApi_ContainerImport_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/wwapi.v1.WWApi/ContainerImport", runtime.WithHTTPPathPattern("/v1/container"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WWApi_ContainerImport_0(ctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_ContainerImport_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_WWApi_ContainerList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/wwapi.v1.WWApi/ContainerList", runtime.WithHTTPPathPattern("/v1/container"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WWApi_ContainerList_0(ctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_ContainerList_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_WWApi_ContainerShow_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/wwapi.v1.WWApi/ContainerShow", runtime.WithHTTPPathPattern("/v1/containershow"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WWApi_ContainerShow_0(ctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_ContainerShow_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_WWApi_NodeAdd_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/wwapi.v1.WWApi/NodeAdd", runtime.WithHTTPPathPattern("/v1/node"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WWApi_NodeAdd_0(ctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_NodeAdd_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_WWApi_NodeDelete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/wwapi.v1.WWApi/NodeDelete", runtime.WithHTTPPathPattern("/v1/node"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WWApi_NodeDelete_0(ctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_NodeDelete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_WWApi_NodeList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/wwapi.v1.WWApi/NodeList", runtime.WithHTTPPathPattern("/v1/node"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WWApi_NodeList_0(ctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_NodeList_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_WWApi_NodeSet_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/wwapi.v1.WWApi/NodeSet", runtime.WithHTTPPathPattern("/v1/nodeset"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WWApi_NodeSet_0(ctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_NodeSet_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_WWApi_NodeStatus_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/wwapi.v1.WWApi/NodeStatus", runtime.WithHTTPPathPattern("/v1/nodestatus"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WWApi_NodeStatus_0(ctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_NodeStatus_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_WWApi_Version_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/wwapi.v1.WWApi/Version", runtime.WithHTTPPathPattern("/version"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WWApi_Version_0(ctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_Version_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterWWApiHandlerFromEndpoint is same as RegisterWWApiHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterWWApiHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterWWApiHandler(ctx, mux, conn)
}
// RegisterWWApiHandler registers the http handlers for service WWApi to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterWWApiHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterWWApiHandlerClient(ctx, mux, NewWWApiClient(conn))
}
// RegisterWWApiHandlerClient registers the http handlers for service WWApi
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "WWApiClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "WWApiClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "WWApiClient" to call the correct interceptors.
func RegisterWWApiHandlerClient(ctx context.Context, mux *runtime.ServeMux, client WWApiClient) error {
mux.Handle("POST", pattern_WWApi_ContainerBuild_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/wwapi.v1.WWApi/ContainerBuild", runtime.WithHTTPPathPattern("/v1/containerbuild"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WWApi_ContainerBuild_0(ctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_ContainerBuild_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_WWApi_ContainerDelete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/wwapi.v1.WWApi/ContainerDelete", runtime.WithHTTPPathPattern("/v1/container"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WWApi_ContainerDelete_0(ctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_ContainerDelete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_WWApi_ContainerImport_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/wwapi.v1.WWApi/ContainerImport", runtime.WithHTTPPathPattern("/v1/container"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WWApi_ContainerImport_0(ctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_ContainerImport_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_WWApi_ContainerList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/wwapi.v1.WWApi/ContainerList", runtime.WithHTTPPathPattern("/v1/container"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WWApi_ContainerList_0(ctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_ContainerList_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_WWApi_ContainerShow_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/wwapi.v1.WWApi/ContainerShow", runtime.WithHTTPPathPattern("/v1/containershow"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WWApi_ContainerShow_0(ctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_ContainerShow_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_WWApi_NodeAdd_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/wwapi.v1.WWApi/NodeAdd", runtime.WithHTTPPathPattern("/v1/node"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WWApi_NodeAdd_0(ctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_NodeAdd_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_WWApi_NodeDelete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/wwapi.v1.WWApi/NodeDelete", runtime.WithHTTPPathPattern("/v1/node"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WWApi_NodeDelete_0(ctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_NodeDelete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_WWApi_NodeList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/wwapi.v1.WWApi/NodeList", runtime.WithHTTPPathPattern("/v1/node"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WWApi_NodeList_0(ctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_NodeList_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_WWApi_NodeSet_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/wwapi.v1.WWApi/NodeSet", runtime.WithHTTPPathPattern("/v1/nodeset"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WWApi_NodeSet_0(ctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_NodeSet_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_WWApi_NodeStatus_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/wwapi.v1.WWApi/NodeStatus", runtime.WithHTTPPathPattern("/v1/nodestatus"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WWApi_NodeStatus_0(ctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_NodeStatus_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_WWApi_Version_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/wwapi.v1.WWApi/Version", runtime.WithHTTPPathPattern("/version"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WWApi_Version_0(ctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_WWApi_Version_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_WWApi_ContainerBuild_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "containerbuild"}, ""))
pattern_WWApi_ContainerDelete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "container"}, ""))
pattern_WWApi_ContainerImport_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "container"}, ""))
pattern_WWApi_ContainerList_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "container"}, ""))
pattern_WWApi_ContainerShow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "containershow"}, ""))
pattern_WWApi_NodeAdd_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "node"}, ""))
pattern_WWApi_NodeDelete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "node"}, ""))
pattern_WWApi_NodeList_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "node"}, ""))
pattern_WWApi_NodeSet_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "nodeset"}, ""))
pattern_WWApi_NodeStatus_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "nodestatus"}, ""))
pattern_WWApi_Version_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"version"}, ""))
)
var (
forward_WWApi_ContainerBuild_0 = runtime.ForwardResponseMessage
forward_WWApi_ContainerDelete_0 = runtime.ForwardResponseMessage
forward_WWApi_ContainerImport_0 = runtime.ForwardResponseMessage
forward_WWApi_ContainerList_0 = runtime.ForwardResponseMessage
forward_WWApi_ContainerShow_0 = runtime.ForwardResponseMessage
forward_WWApi_NodeAdd_0 = runtime.ForwardResponseMessage
forward_WWApi_NodeDelete_0 = runtime.ForwardResponseMessage
forward_WWApi_NodeList_0 = runtime.ForwardResponseMessage
forward_WWApi_NodeSet_0 = runtime.ForwardResponseMessage
forward_WWApi_NodeStatus_0 = runtime.ForwardResponseMessage
forward_WWApi_Version_0 = runtime.ForwardResponseMessage
)

View File

@@ -0,0 +1,494 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.21.1
// source: routes.proto
package wwapiv1
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// WWApiClient is the client API for WWApi service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type WWApiClient interface {
// ContainerBuild builds zero or more containers.
ContainerBuild(ctx context.Context, in *ContainerBuildParameter, opts ...grpc.CallOption) (*ContainerListResponse, error)
// ContainerDelete removes one or more container from Warewulf management.
ContainerDelete(ctx context.Context, in *ContainerDeleteParameter, opts ...grpc.CallOption) (*emptypb.Empty, error)
// ContainerImport imports a container to Warewulf.
ContainerImport(ctx context.Context, in *ContainerImportParameter, opts ...grpc.CallOption) (*ContainerListResponse, error)
// ContainerList lists ContainerInfo for each container.
ContainerList(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ContainerListResponse, error)
// ContainerShow lists ContainerShow for each container.
ContainerShow(ctx context.Context, in *ContainerShowParameter, opts ...grpc.CallOption) (*ContainerShowResponse, error)
// NodeAdd adds one or more nodes for management by Warewulf and returns
// the added nodes. Node fields may be shimmed in per profiles.
NodeAdd(ctx context.Context, in *NodeAddParameter, opts ...grpc.CallOption) (*NodeListResponse, error)
// NodeDelete removes one or more nodes from Warewulf management.
NodeDelete(ctx context.Context, in *NodeDeleteParameter, opts ...grpc.CallOption) (*emptypb.Empty, error)
// NodeList lists some or all nodes managed by Warewulf.
NodeList(ctx context.Context, in *NodeNames, opts ...grpc.CallOption) (*NodeListResponse, error)
// NodeSet updates node fields for one or more nodes.
NodeSet(ctx context.Context, in *NodeSetParameter, opts ...grpc.CallOption) (*NodeListResponse, error)
// NodeStatus returns the imaging state for nodes.
// This requires warewulfd.
NodeStatus(ctx context.Context, in *NodeNames, opts ...grpc.CallOption) (*NodeStatusResponse, error)
// Version returns the wwapi version, the api prefix, and the Warewulf
// version. This is also useful for testing if the service is up.
Version(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*VersionResponse, error)
}
type wWApiClient struct {
cc grpc.ClientConnInterface
}
func NewWWApiClient(cc grpc.ClientConnInterface) WWApiClient {
return &wWApiClient{cc}
}
func (c *wWApiClient) ContainerBuild(ctx context.Context, in *ContainerBuildParameter, opts ...grpc.CallOption) (*ContainerListResponse, error) {
out := new(ContainerListResponse)
err := c.cc.Invoke(ctx, "/wwapi.v1.WWApi/ContainerBuild", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *wWApiClient) ContainerDelete(ctx context.Context, in *ContainerDeleteParameter, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/wwapi.v1.WWApi/ContainerDelete", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *wWApiClient) ContainerImport(ctx context.Context, in *ContainerImportParameter, opts ...grpc.CallOption) (*ContainerListResponse, error) {
out := new(ContainerListResponse)
err := c.cc.Invoke(ctx, "/wwapi.v1.WWApi/ContainerImport", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *wWApiClient) ContainerList(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ContainerListResponse, error) {
out := new(ContainerListResponse)
err := c.cc.Invoke(ctx, "/wwapi.v1.WWApi/ContainerList", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *wWApiClient) ContainerShow(ctx context.Context, in *ContainerShowParameter, opts ...grpc.CallOption) (*ContainerShowResponse, error) {
out := new(ContainerShowResponse)
err := c.cc.Invoke(ctx, "/wwapi.v1.WWApi/ContainerShow", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *wWApiClient) NodeAdd(ctx context.Context, in *NodeAddParameter, opts ...grpc.CallOption) (*NodeListResponse, error) {
out := new(NodeListResponse)
err := c.cc.Invoke(ctx, "/wwapi.v1.WWApi/NodeAdd", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *wWApiClient) NodeDelete(ctx context.Context, in *NodeDeleteParameter, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/wwapi.v1.WWApi/NodeDelete", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *wWApiClient) NodeList(ctx context.Context, in *NodeNames, opts ...grpc.CallOption) (*NodeListResponse, error) {
out := new(NodeListResponse)
err := c.cc.Invoke(ctx, "/wwapi.v1.WWApi/NodeList", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *wWApiClient) NodeSet(ctx context.Context, in *NodeSetParameter, opts ...grpc.CallOption) (*NodeListResponse, error) {
out := new(NodeListResponse)
err := c.cc.Invoke(ctx, "/wwapi.v1.WWApi/NodeSet", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *wWApiClient) NodeStatus(ctx context.Context, in *NodeNames, opts ...grpc.CallOption) (*NodeStatusResponse, error) {
out := new(NodeStatusResponse)
err := c.cc.Invoke(ctx, "/wwapi.v1.WWApi/NodeStatus", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *wWApiClient) Version(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*VersionResponse, error) {
out := new(VersionResponse)
err := c.cc.Invoke(ctx, "/wwapi.v1.WWApi/Version", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// WWApiServer is the server API for WWApi service.
// All implementations must embed UnimplementedWWApiServer
// for forward compatibility
type WWApiServer interface {
// ContainerBuild builds zero or more containers.
ContainerBuild(context.Context, *ContainerBuildParameter) (*ContainerListResponse, error)
// ContainerDelete removes one or more container from Warewulf management.
ContainerDelete(context.Context, *ContainerDeleteParameter) (*emptypb.Empty, error)
// ContainerImport imports a container to Warewulf.
ContainerImport(context.Context, *ContainerImportParameter) (*ContainerListResponse, error)
// ContainerList lists ContainerInfo for each container.
ContainerList(context.Context, *emptypb.Empty) (*ContainerListResponse, error)
// ContainerShow lists ContainerShow for each container.
ContainerShow(context.Context, *ContainerShowParameter) (*ContainerShowResponse, error)
// NodeAdd adds one or more nodes for management by Warewulf and returns
// the added nodes. Node fields may be shimmed in per profiles.
NodeAdd(context.Context, *NodeAddParameter) (*NodeListResponse, error)
// NodeDelete removes one or more nodes from Warewulf management.
NodeDelete(context.Context, *NodeDeleteParameter) (*emptypb.Empty, error)
// NodeList lists some or all nodes managed by Warewulf.
NodeList(context.Context, *NodeNames) (*NodeListResponse, error)
// NodeSet updates node fields for one or more nodes.
NodeSet(context.Context, *NodeSetParameter) (*NodeListResponse, error)
// NodeStatus returns the imaging state for nodes.
// This requires warewulfd.
NodeStatus(context.Context, *NodeNames) (*NodeStatusResponse, error)
// Version returns the wwapi version, the api prefix, and the Warewulf
// version. This is also useful for testing if the service is up.
Version(context.Context, *emptypb.Empty) (*VersionResponse, error)
mustEmbedUnimplementedWWApiServer()
}
// UnimplementedWWApiServer must be embedded to have forward compatible implementations.
type UnimplementedWWApiServer struct {
}
func (UnimplementedWWApiServer) ContainerBuild(context.Context, *ContainerBuildParameter) (*ContainerListResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ContainerBuild not implemented")
}
func (UnimplementedWWApiServer) ContainerDelete(context.Context, *ContainerDeleteParameter) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method ContainerDelete not implemented")
}
func (UnimplementedWWApiServer) ContainerImport(context.Context, *ContainerImportParameter) (*ContainerListResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ContainerImport not implemented")
}
func (UnimplementedWWApiServer) ContainerList(context.Context, *emptypb.Empty) (*ContainerListResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ContainerList not implemented")
}
func (UnimplementedWWApiServer) ContainerShow(context.Context, *ContainerShowParameter) (*ContainerShowResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ContainerShow not implemented")
}
func (UnimplementedWWApiServer) NodeAdd(context.Context, *NodeAddParameter) (*NodeListResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method NodeAdd not implemented")
}
func (UnimplementedWWApiServer) NodeDelete(context.Context, *NodeDeleteParameter) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method NodeDelete not implemented")
}
func (UnimplementedWWApiServer) NodeList(context.Context, *NodeNames) (*NodeListResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method NodeList not implemented")
}
func (UnimplementedWWApiServer) NodeSet(context.Context, *NodeSetParameter) (*NodeListResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method NodeSet not implemented")
}
func (UnimplementedWWApiServer) NodeStatus(context.Context, *NodeNames) (*NodeStatusResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method NodeStatus not implemented")
}
func (UnimplementedWWApiServer) Version(context.Context, *emptypb.Empty) (*VersionResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Version not implemented")
}
func (UnimplementedWWApiServer) mustEmbedUnimplementedWWApiServer() {}
// UnsafeWWApiServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to WWApiServer will
// result in compilation errors.
type UnsafeWWApiServer interface {
mustEmbedUnimplementedWWApiServer()
}
func RegisterWWApiServer(s grpc.ServiceRegistrar, srv WWApiServer) {
s.RegisterService(&WWApi_ServiceDesc, srv)
}
func _WWApi_ContainerBuild_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ContainerBuildParameter)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WWApiServer).ContainerBuild(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/wwapi.v1.WWApi/ContainerBuild",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WWApiServer).ContainerBuild(ctx, req.(*ContainerBuildParameter))
}
return interceptor(ctx, in, info, handler)
}
func _WWApi_ContainerDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ContainerDeleteParameter)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WWApiServer).ContainerDelete(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/wwapi.v1.WWApi/ContainerDelete",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WWApiServer).ContainerDelete(ctx, req.(*ContainerDeleteParameter))
}
return interceptor(ctx, in, info, handler)
}
func _WWApi_ContainerImport_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ContainerImportParameter)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WWApiServer).ContainerImport(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/wwapi.v1.WWApi/ContainerImport",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WWApiServer).ContainerImport(ctx, req.(*ContainerImportParameter))
}
return interceptor(ctx, in, info, handler)
}
func _WWApi_ContainerList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(emptypb.Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WWApiServer).ContainerList(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/wwapi.v1.WWApi/ContainerList",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WWApiServer).ContainerList(ctx, req.(*emptypb.Empty))
}
return interceptor(ctx, in, info, handler)
}
func _WWApi_ContainerShow_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ContainerShowParameter)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WWApiServer).ContainerShow(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/wwapi.v1.WWApi/ContainerShow",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WWApiServer).ContainerShow(ctx, req.(*ContainerShowParameter))
}
return interceptor(ctx, in, info, handler)
}
func _WWApi_NodeAdd_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(NodeAddParameter)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WWApiServer).NodeAdd(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/wwapi.v1.WWApi/NodeAdd",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WWApiServer).NodeAdd(ctx, req.(*NodeAddParameter))
}
return interceptor(ctx, in, info, handler)
}
func _WWApi_NodeDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(NodeDeleteParameter)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WWApiServer).NodeDelete(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/wwapi.v1.WWApi/NodeDelete",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WWApiServer).NodeDelete(ctx, req.(*NodeDeleteParameter))
}
return interceptor(ctx, in, info, handler)
}
func _WWApi_NodeList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(NodeNames)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WWApiServer).NodeList(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/wwapi.v1.WWApi/NodeList",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WWApiServer).NodeList(ctx, req.(*NodeNames))
}
return interceptor(ctx, in, info, handler)
}
func _WWApi_NodeSet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(NodeSetParameter)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WWApiServer).NodeSet(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/wwapi.v1.WWApi/NodeSet",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WWApiServer).NodeSet(ctx, req.(*NodeSetParameter))
}
return interceptor(ctx, in, info, handler)
}
func _WWApi_NodeStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(NodeNames)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WWApiServer).NodeStatus(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/wwapi.v1.WWApi/NodeStatus",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WWApiServer).NodeStatus(ctx, req.(*NodeNames))
}
return interceptor(ctx, in, info, handler)
}
func _WWApi_Version_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(emptypb.Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WWApiServer).Version(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/wwapi.v1.WWApi/Version",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WWApiServer).Version(ctx, req.(*emptypb.Empty))
}
return interceptor(ctx, in, info, handler)
}
// WWApi_ServiceDesc is the grpc.ServiceDesc for WWApi service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var WWApi_ServiceDesc = grpc.ServiceDesc{
ServiceName: "wwapi.v1.WWApi",
HandlerType: (*WWApiServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ContainerBuild",
Handler: _WWApi_ContainerBuild_Handler,
},
{
MethodName: "ContainerDelete",
Handler: _WWApi_ContainerDelete_Handler,
},
{
MethodName: "ContainerImport",
Handler: _WWApi_ContainerImport_Handler,
},
{
MethodName: "ContainerList",
Handler: _WWApi_ContainerList_Handler,
},
{
MethodName: "ContainerShow",
Handler: _WWApi_ContainerShow_Handler,
},
{
MethodName: "NodeAdd",
Handler: _WWApi_NodeAdd_Handler,
},
{
MethodName: "NodeDelete",
Handler: _WWApi_NodeDelete_Handler,
},
{
MethodName: "NodeList",
Handler: _WWApi_NodeList_Handler,
},
{
MethodName: "NodeSet",
Handler: _WWApi_NodeSet_Handler,
},
{
MethodName: "NodeStatus",
Handler: _WWApi_NodeStatus_Handler,
},
{
MethodName: "Version",
Handler: _WWApi_Version_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "routes.proto",
}

View File

@@ -0,0 +1,21 @@
package util
import (
"github.com/manifoldco/promptui"
)
// ConfirmationPrompt prompt is a blocking confirmation prompt.
// Returns true on y or yes user input.
func ConfirmationPrompt(label string) (yes bool) {
prompt := promptui.Prompt{
Label: label,
IsConfirm: true,
}
result, _ := prompt.Run()
if result == "y" || result == "yes" {
yes = true
}
return
}

View File

@@ -24,8 +24,8 @@ func init() {
}
}
func New() (nodeYaml, error) {
var ret nodeYaml
func New() (NodeYaml, error) {
var ret NodeYaml
wwlog.Printf(wwlog.VERBOSE, "Opening node configuration file: %s\n", ConfigFile)
data, err := ioutil.ReadFile(ConfigFile)
@@ -49,7 +49,7 @@ Get all the nodes of a configuration. This function also merges
the nodes with the given profiles and set the default values
for every node
*/
func (config *nodeYaml) FindAllNodes() ([]NodeInfo, error) {
func (config *NodeYaml) FindAllNodes() ([]NodeInfo, error) {
var ret []NodeInfo
wwconfig, err := warewulfconf.New()
if err != nil {
@@ -180,7 +180,14 @@ func (config *nodeYaml) FindAllNodes() ([]NodeInfo, error) {
}
n.NetDevs[devname].Tags[keyname].Set(key)
}
n.NetDevs[devname].Tags = make(map[string]*Entry)
for keyname, key := range netdev.Tags {
if _, ok := n.Tags[keyname]; !ok {
var keyVar Entry
n.NetDevs[devname].Tags[keyname] = &keyVar
}
n.NetDevs[devname].Tags[keyname].Set(key)
}
}
// Merge Keys into Tags for backwards compatibility
@@ -302,7 +309,7 @@ func (config *nodeYaml) FindAllNodes() ([]NodeInfo, error) {
return ret, nil
}
func (config *nodeYaml) FindAllProfiles() ([]NodeInfo, error) {
func (config *NodeYaml) FindAllProfiles() ([]NodeInfo, error) {
var ret []NodeInfo
for name, profile := range config.NodeProfiles {
@@ -434,7 +441,7 @@ func (config *nodeYaml) FindAllProfiles() ([]NodeInfo, error) {
return ret, nil
}
func (config *nodeYaml) FindDiscoverableNode() (NodeInfo, string, error) {
func (config *NodeYaml) FindDiscoverableNode() (NodeInfo, string, error) {
var ret NodeInfo
nodes, _ := config.FindAllNodes()

View File

@@ -9,7 +9,7 @@ import (
* YAML data representations
******/
type nodeYaml struct {
type NodeYaml struct {
WWInternal int `yaml:"WW_INTERNAL"`
NodeProfiles map[string]*NodeConf
Nodes map[string]*NodeConf

View File

@@ -15,7 +15,7 @@ import (
*
****/
func (config *nodeYaml) AddNode(nodeID string) (NodeInfo, error) {
func (config *NodeYaml) AddNode(nodeID string) (NodeInfo, error) {
var node NodeConf
var n NodeInfo
@@ -37,7 +37,7 @@ func (config *nodeYaml) AddNode(nodeID string) (NodeInfo, error) {
return n, nil
}
func (config *nodeYaml) DelNode(nodeID string) error {
func (config *NodeYaml) DelNode(nodeID string) error {
if _, ok := config.Nodes[nodeID]; !ok {
return errors.New("Nodename does not exist: " + nodeID)
@@ -49,7 +49,7 @@ func (config *nodeYaml) DelNode(nodeID string) error {
return nil
}
func (config *nodeYaml) NodeUpdate(node NodeInfo) error {
func (config *NodeYaml) NodeUpdate(node NodeInfo) error {
nodeID := node.Id.Get()
if _, ok := config.Nodes[nodeID]; !ok {
@@ -126,7 +126,7 @@ func (config *nodeYaml) NodeUpdate(node NodeInfo) error {
*
****/
func (config *nodeYaml) AddProfile(profileID string) (NodeInfo, error) {
func (config *NodeYaml) AddProfile(profileID string) (NodeInfo, error) {
var node NodeConf
var n NodeInfo
@@ -143,7 +143,7 @@ func (config *nodeYaml) AddProfile(profileID string) (NodeInfo, error) {
return n, nil
}
func (config *nodeYaml) DelProfile(profileID string) error {
func (config *NodeYaml) DelProfile(profileID string) error {
if _, ok := config.NodeProfiles[profileID]; !ok {
return errors.New("Profile does not exist: " + profileID)
@@ -158,7 +158,7 @@ func (config *nodeYaml) DelProfile(profileID string) error {
/*
Update the the config for the given profile so that it can unmarshalled.
*/
func (config *nodeYaml) ProfileUpdate(profile NodeInfo) error {
func (config *NodeYaml) ProfileUpdate(profile NodeInfo) error {
profileID := profile.Id.Get()
if _, ok := config.NodeProfiles[profileID]; !ok {
@@ -228,7 +228,7 @@ func (config *nodeYaml) ProfileUpdate(profile NodeInfo) error {
*
****/
func (config *nodeYaml) Persist() error {
func (config *NodeYaml) Persist() error {
out, err := yaml.Marshal(config)
if err != nil {

View File

@@ -25,7 +25,7 @@ nodes:
hwaddr: 08:00:27:39:46:70
ipaddr: 10.0.8.150
`
var nodeYaml nodeYaml
var nodeYaml NodeYaml
err := yaml.Unmarshal([]byte(nodeConfig), &nodeYaml)
assert.NoError(t, err)

View File

@@ -6,7 +6,7 @@ import (
"strings"
)
func (config *nodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) {
func (config *NodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) {
if _, err := net.ParseMAC(hwa); err != nil {
return NodeInfo{}, errors.New("invalid hardware address: " + hwa)
}
@@ -26,7 +26,7 @@ func (config *nodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) {
return ret, errors.New("No nodes found with HW Addr: " + hwa)
}
func (config *nodeYaml) FindByIpaddr(ipaddr string) (NodeInfo, error) {
func (config *NodeYaml) FindByIpaddr(ipaddr string) (NodeInfo, error) {
if net.ParseIP(ipaddr) == nil {
return NodeInfo{}, errors.New("invalid IP:" + ipaddr)
}

View File

@@ -6,7 +6,7 @@ import (
"gopkg.in/yaml.v2"
)
func NewTestNode() (nodeYaml, error) {
func NewTestNode() (NodeYaml, error) {
var data = `
nodeprofiles:
default:
@@ -39,7 +39,7 @@ nodes:
default: false
ipaddr: fd1a:2b3c:4d5e:06f0:1234:5678:90ab:cdef
`
var ret nodeYaml
var ret NodeYaml
err := yaml.Unmarshal([]byte(data), &ret)
if err != nil {
return ret, err
@@ -59,7 +59,7 @@ func Test_nodeYaml_FindByHwaddr(t *testing.T) {
tests := []struct {
name string
//fields fields
config nodeYaml
config NodeYaml
args args
want string
wantErr bool
@@ -95,7 +95,7 @@ func Test_nodeYaml_FindByIpaddr(t *testing.T) {
}
tests := []struct {
name string
config nodeYaml
config NodeYaml
args args
want string
wantErr bool

View File

@@ -3,9 +3,24 @@ package version
import (
"fmt"
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
"github.com/hpcng/warewulf/internal/pkg/buildconfig"
)
/*
Return the version of wwctl
*/
func GetVersion() string {
return fmt.Sprintf("%s-%s", buildconfig.VERSION(), buildconfig.RELEASE())
}
/*
Returns the version of the api via grpc
*/
func Version() (versionResponse *wwapiv1.VersionResponse) {
versionResponse = &wwapiv1.VersionResponse{}
versionResponse.ApiPrefix = "rc1"
versionResponse.ApiVersion = "1"
versionResponse.WarewulfVersion = GetVersion()
return
}