open-nomad/client/meta_endpoint_test.go

184 lines
5.0 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
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")
}