added hash check for node edit

Signed-off-by: Christian Goll <cgoll@suse.de>
This commit is contained in:
Christian Goll
2023-02-28 15:58:44 +01:00
parent ee4f9d53d6
commit b4acf0fdf2
10 changed files with 604 additions and 432 deletions

View File

@@ -35,6 +35,7 @@ func CobraRunE(vars *variables) func(cmd *cobra.Command, args []string) error {
set := wwapiv1.NodeAddParameter{
NodeConfYaml: string(buffer[:]),
NodeNames: args,
Force: true,
}
return apinode.NodeAdd(&set)
}

View File

@@ -29,11 +29,11 @@ var (
},
}
SetYes bool
SetForce bool // currently unused
SetForce bool // no hash checking, so always using force
)
func init() {
baseCmd.PersistentFlags().BoolVarP(&SetForce, "force", "f", false, "Force node delete")
SetForce = true
baseCmd.PersistentFlags().BoolVarP(&SetYes, "yes", "y", false, "Set 'yes' to all questions asked")
}
@@ -41,4 +41,4 @@ func init() {
// GetRootCommand returns the root cobra.Command for the application.
func GetCommand() *cobra.Command {
return baseCmd
}
}

View File

@@ -88,12 +88,20 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
if !yes {
break
}
err = apinode.NodeDelete(&wwapiv1.NodeDeleteParameter{NodeNames: nodeList, Force: true})
err = apinode.NodeDelete(&wwapiv1.NodeDeleteParameter{
NodeNames: nodeList,
Hash: nodeListMsg.Hash,
})
if err != nil {
wwlog.Verbose("Problem deleting nodes before modification %s")
wwlog.Error("Problem deleting nodes before modification: %s", err)
return err
}
buffer, _ = yaml.Marshal(modifiedNodeMap)
err = apinode.NodeAddFromYaml(&wwapiv1.NodeYaml{NodeConfMapYaml: string(buffer)})
newHash := apinode.Hash()
err = apinode.NodeAddFromYaml(&wwapiv1.NodeYaml{
NodeConfMapYaml: string(buffer),
Hash: newHash.Hash,
})
if err != nil {
wwlog.Error("Got following problem when writing back yaml: %s", err)
os.Exit(1)

View File

@@ -24,6 +24,7 @@ func FindAllNodeConfs() *wwapiv1.NodeYaml {
buffer, _ := yaml.Marshal(nodeMap)
retVal := wwapiv1.NodeYaml{
NodeConfMapYaml: string(buffer),
Hash: nodeDB.StringHash(),
}
return &retVal
}
@@ -42,6 +43,7 @@ func FilteredNodes(nodeList *wwapiv1.NodeList) *wwapiv1.NodeYaml {
buffer, _ := yaml.Marshal(nodeMap)
retVal := wwapiv1.NodeYaml{
NodeConfMapYaml: string(buffer),
Hash: nodeDB.StringHash(),
}
return &retVal
}

View File

@@ -0,0 +1,20 @@
package apinode
import (
"encoding/hex"
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
)
func Hash() *wwapiv1.NodeDBHash {
config, err := node.New()
if err != nil {
wwlog.Warn("couldb't read config")
}
hash := config.Hash()
return &wwapiv1.NodeDBHash{
Hash: hex.EncodeToString(hash[:]),
}
}

View File

@@ -1,6 +1,7 @@
package apinode
import (
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
@@ -29,7 +30,10 @@ func NodeAdd(nap *wwapiv1.NodeAddParameter) (err error) {
if err != nil {
return errors.Wrap(err, "failed to open node database")
}
dbHash := nodeDB.Hash()
if hex.EncodeToString(dbHash[:]) != nap.Hash && !nap.Force {
return fmt.Errorf("got wrong hash, not modifying node database")
}
node_args := hostlist.Expand(nap.NodeNames)
var nodeConf node.NodeConf
err = yaml.Unmarshal([]byte(nap.NodeConfYaml), &nodeConf)
@@ -95,6 +99,10 @@ func NodeDelete(ndp *wwapiv1.NodeDeleteParameter) (err error) {
wwlog.Error("Failed to open node database: %s", err)
return
}
dbHash := nodeDB.Hash()
if hex.EncodeToString(dbHash[:]) != ndp.Hash && !ndp.Force {
return fmt.Errorf("got wrong hash, not modifying node database")
}
for _, n := range nodeList {
err := nodeDB.DelNode(n.Id.Get())
@@ -133,6 +141,13 @@ func NodeDeleteParameterCheck(ndp *wwapiv1.NodeDeleteParameter, console bool) (n
wwlog.Error("Failed to open node database: %s", err)
return
}
dbHash := nodeDB.Hash()
if hex.EncodeToString(dbHash[:]) != ndp.Hash && !ndp.Force {
wwlog.Debug("got hash: %s", ndp.Hash)
wwlog.Debug("actual hash: %s", hex.EncodeToString(dbHash[:]))
err = fmt.Errorf("got wrong hash, not modifying node database")
return
}
nodes, err := nodeDB.FindAllNodes()
if err != nil {

View File

@@ -10,6 +10,12 @@ package wwapi.v1;
import "google/protobuf/empty.proto";
import "google/api/annotations.proto";
// Information about the database
message NodeDBHash {
string hash = 1;
}
// Container
// ContainerBuildParameter contains input for building zero or more containers.
@@ -133,9 +139,12 @@ message ProfileList {
}
// NodeAddParameter contains all input for adding a node to be managed by
// Warewulf.
// Warewulf. Only adds nodes if the hash matches the actual hash of the
// configuration.
message NodeAddParameter {
string nodeConfYaml = 1;
bool force = 2;
string hash = 3;
repeated string nodeNames = 10;
}
@@ -143,13 +152,17 @@ message NodeAddParameter {
// to nodes.conf (is resused for profile edit)
message NodeYaml {
string nodeConfMapYaml = 1;
string hash = 2;
}
// NodeDeleteParameter contains input for removing nodes from Warewulf
// management.
// management. If the given hash differs with the actual hash of the
// configuration, no node is deleted. The force option allows the deletion
// of nodes with a correct hash.
message NodeDeleteParameter {
bool force = 1;
repeated string nodeNames = 2;
string hash = 3;
}
// NodeSetParameter contains all fields for updating aspects of nodes managed

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@ package node
import (
"crypto/sha256"
"encoding/hex"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"gopkg.in/yaml.v2"
@@ -24,3 +25,11 @@ func (config *NodeYaml) Hash() [32]byte {
}
return sha256.Sum256(data)
}
/*
Return the hash as string
*/
func (config *NodeYaml) StringHash() string {
buffer := config.Hash()
return hex.EncodeToString(buffer[:])
}

View File

@@ -1,7 +1,6 @@
package node
import (
"fmt"
"testing"
"gopkg.in/yaml.v2"
@@ -30,7 +29,7 @@ nodes:
profiles:
- default
network devices:
testnet:
default:
ipaddr: 10.0.10.2
`
nodeConfYml2 := `
@@ -81,7 +80,6 @@ nodes:
`
var nodeConf1, nodeConf2, nodeConf3 NodeYaml
err := yaml.Unmarshal([]byte(nodeConfYml1), &nodeConf1)
fmt.Println(nodeConf1.Nodes["n01"])
assert.NoError(t, err)
err = yaml.Unmarshal([]byte(nodeConfYml2), &nodeConf2)
assert.NoError(t, err)
@@ -98,8 +96,12 @@ nodes:
})
t.Run("Different sorted NodeYaml with same conf", func(t *testing.T) {
yml1, err := yaml.Marshal(nodeConf1)
assert.NoError(t, err)
yml2, err := yaml.Marshal(nodeConf2)
assert.NoError(t, err)
if nodeConf2.Hash() != nodeConf1.Hash() {
t.Errorf("Hashes for same configuration differs: %x != %x", nodeConf2.Hash(), nodeConf1.Hash())
t.Errorf("Hashes for same configuration differs: %x != %x\njson1:\n%s,yml2:\n%s\n", nodeConf2.Hash(), nodeConf1.Hash(), yml1, yml2)
}
})