mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
Setting a null value to a node metadata is expected to remove it from subsequent reads. This is true both for static node metadata (defined in the agent configuration file) as well as for dynamic node metadata (defined via the Nomad API). Null values for static metadata must be persisted to indicate that the value has been removed, but strictly dynamic metadata null values can be removed from state and client memory.
184 lines
5.0 KiB
Go
184 lines
5.0 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package client
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/hashicorp/nomad/acl"
|
|
"github.com/hashicorp/nomad/ci"
|
|
"github.com/hashicorp/nomad/client/config"
|
|
"github.com/hashicorp/nomad/helper/pointer"
|
|
"github.com/hashicorp/nomad/nomad"
|
|
"github.com/hashicorp/nomad/nomad/mock"
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
"github.com/hashicorp/nomad/testutil"
|
|
"github.com/shoenig/test/must"
|
|
)
|
|
|
|
func TestNodeMeta_ACL(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
s, _, cleanupS := nomad.TestACLServer(t, nil)
|
|
defer cleanupS()
|
|
testutil.WaitForLeader(t, s.RPC)
|
|
|
|
c1, cleanup := TestClient(t, func(c *config.Config) {
|
|
c.ACLEnabled = true
|
|
c.Servers = []string{s.GetConfig().RPCAddr.String()}
|
|
})
|
|
defer cleanup()
|
|
|
|
// Dynamic node metadata endpoints should fail without auth
|
|
applyReq := &structs.NodeMetaApplyRequest{
|
|
NodeID: c1.NodeID(),
|
|
Meta: map[string]*string{
|
|
"foo": pointer.Of("bar"),
|
|
},
|
|
}
|
|
|
|
resp := structs.NodeMetaResponse{}
|
|
err := c1.ClientRPC("NodeMeta.Apply", applyReq, &resp)
|
|
must.ErrorContains(t, err, structs.ErrPermissionDenied.Error())
|
|
|
|
readReq := &structs.NodeSpecificRequest{
|
|
NodeID: c1.NodeID(),
|
|
}
|
|
err = c1.ClientRPC("NodeMeta.Read", readReq, &resp)
|
|
must.ErrorContains(t, err, structs.ErrPermissionDenied.Error())
|
|
|
|
// Create a token to make it work
|
|
policyGood := mock.NodePolicy(acl.PolicyWrite)
|
|
tokenGood := mock.CreatePolicyAndToken(t, s.State(), 1009, "meta", policyGood)
|
|
|
|
applyReq.AuthToken = tokenGood.SecretID
|
|
err = c1.ClientRPC("NodeMeta.Apply", applyReq, &resp)
|
|
must.NoError(t, err)
|
|
must.Eq(t, "bar", resp.Meta["foo"])
|
|
|
|
readReq.AuthToken = tokenGood.SecretID
|
|
err = c1.ClientRPC("NodeMeta.Read", readReq, &resp)
|
|
must.NoError(t, err)
|
|
}
|
|
|
|
func TestNodeMeta_Validation(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
s, cleanupS := nomad.TestServer(t, nil)
|
|
defer cleanupS()
|
|
testutil.WaitForLeader(t, s.RPC)
|
|
|
|
c1, cleanup := TestClient(t, func(c *config.Config) {
|
|
c.Servers = []string{s.GetConfig().RPCAddr.String()}
|
|
})
|
|
defer cleanup()
|
|
|
|
applyReq := &structs.NodeMetaApplyRequest{
|
|
NodeID: c1.NodeID(),
|
|
Meta: map[string]*string{},
|
|
}
|
|
|
|
resp := struct{}{}
|
|
|
|
// An empty map is an error
|
|
err := c1.ClientRPC("NodeMeta.Apply", applyReq, &resp)
|
|
must.ErrorContains(t, err, "missing required Meta")
|
|
|
|
// empty keys are prohibited
|
|
applyReq.Meta[""] = pointer.Of("bad")
|
|
err = c1.ClientRPC("NodeMeta.Apply", applyReq, &resp)
|
|
must.ErrorContains(t, err, "empty")
|
|
|
|
// * is prohibited in keys
|
|
delete(applyReq.Meta, "")
|
|
applyReq.Meta["*"] = pointer.Of("bad")
|
|
err = c1.ClientRPC("NodeMeta.Apply", applyReq, &resp)
|
|
must.ErrorContains(t, err, "*")
|
|
}
|
|
|
|
func TestNodeMeta_unset(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
s, cleanupS := nomad.TestServer(t, nil)
|
|
defer cleanupS()
|
|
testutil.WaitForLeader(t, s.RPC)
|
|
|
|
c1, cleanup := TestClient(t, func(c *config.Config) {
|
|
c.Servers = []string{s.GetConfig().RPCAddr.String()}
|
|
c.Node.Meta["static_meta"] = "true"
|
|
})
|
|
defer cleanup()
|
|
|
|
// Set dynamic node metadata.
|
|
applyReq := &structs.NodeMetaApplyRequest{
|
|
NodeID: c1.NodeID(),
|
|
Meta: map[string]*string{
|
|
"dynamic_meta": pointer.Of("true"),
|
|
},
|
|
}
|
|
var resp structs.NodeMetaResponse
|
|
err := c1.ClientRPC("NodeMeta.Apply", applyReq, &resp)
|
|
must.NoError(t, err)
|
|
|
|
// Check static_meta:
|
|
// 1. must be present in Static.
|
|
// 2. must be present in Meta
|
|
must.Eq(t, resp.Static["static_meta"], "true")
|
|
must.Eq(t, resp.Meta["static_meta"], "true")
|
|
|
|
// Check dynamic_meta:
|
|
// 1. must be present in Dynamic.
|
|
// 2. must be present in Meta
|
|
must.Eq(t, *resp.Dynamic["dynamic_meta"], "true")
|
|
must.Eq(t, resp.Meta["dynamic_meta"], "true")
|
|
|
|
// Unset static node metada.
|
|
applyReq = &structs.NodeMetaApplyRequest{
|
|
NodeID: c1.NodeID(),
|
|
Meta: map[string]*string{
|
|
"static_meta": nil,
|
|
},
|
|
}
|
|
err = c1.ClientRPC("NodeMeta.Apply", applyReq, &resp)
|
|
must.NoError(t, err)
|
|
|
|
// Check static_meta:
|
|
// 1. must be present in Static.
|
|
// 2. must not be present in Meta
|
|
// 3. must be nil in Dynamic to persist its removal even on restarts.
|
|
must.Eq(t, resp.Static["static_meta"], "true")
|
|
must.MapNotContainsKey(t, resp.Meta, "static_meta")
|
|
must.Nil(t, resp.Dynamic["static_meta"])
|
|
|
|
// Check dynamic_meta:
|
|
// 1. must be present in Dynamic.
|
|
// 2. must be present in Meta
|
|
must.Eq(t, *resp.Dynamic["dynamic_meta"], "true")
|
|
must.Eq(t, resp.Meta["dynamic_meta"], "true")
|
|
|
|
// Unset dynamic node metada.
|
|
applyReq = &structs.NodeMetaApplyRequest{
|
|
NodeID: c1.NodeID(),
|
|
Meta: map[string]*string{
|
|
"dynamic_meta": nil,
|
|
},
|
|
}
|
|
err = c1.ClientRPC("NodeMeta.Apply", applyReq, &resp)
|
|
must.NoError(t, err)
|
|
|
|
// Check static_meta:
|
|
// 1. must be present in Static.
|
|
// 2. must not be present in Meta
|
|
// 3. must be nil in Dynamic to persist its removal even on restarts.
|
|
must.Eq(t, resp.Static["static_meta"], "true")
|
|
must.MapNotContainsKey(t, resp.Meta, "static_meta")
|
|
must.Nil(t, resp.Dynamic["static_meta"])
|
|
|
|
// Check dynamic_meta:
|
|
// 1. must not be present in Dynamic.
|
|
// 2. must not be present in Meta
|
|
must.MapNotContainsKey(t, resp.Dynamic, "dynamic_meta")
|
|
must.MapNotContainsKey(t, resp.Meta, "dynamic_meta")
|
|
}
|