github.com/djenriquez/nomad-1@v0.8.1/nomad/client_stats_endpoint_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"testing"
     5  
     6  	msgpackrpc "github.com/hashicorp/net-rpc-msgpackrpc"
     7  	"github.com/hashicorp/nomad/acl"
     8  	"github.com/hashicorp/nomad/client"
     9  	"github.com/hashicorp/nomad/client/config"
    10  	cstructs "github.com/hashicorp/nomad/client/structs"
    11  	"github.com/hashicorp/nomad/helper/uuid"
    12  	"github.com/hashicorp/nomad/nomad/mock"
    13  	"github.com/hashicorp/nomad/nomad/structs"
    14  	"github.com/hashicorp/nomad/testutil"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  func TestClientStats_Stats_Local(t *testing.T) {
    19  	t.Parallel()
    20  	require := require.New(t)
    21  
    22  	// Start a server and client
    23  	s := TestServer(t, nil)
    24  	defer s.Shutdown()
    25  	codec := rpcClient(t, s)
    26  	testutil.WaitForLeader(t, s.RPC)
    27  
    28  	c := client.TestClient(t, func(c *config.Config) {
    29  		c.Servers = []string{s.config.RPCAddr.String()}
    30  	})
    31  	defer c.Shutdown()
    32  
    33  	testutil.WaitForResult(func() (bool, error) {
    34  		nodes := s.connectedNodes()
    35  		return len(nodes) == 1, nil
    36  	}, func(err error) {
    37  		t.Fatalf("should have a clients")
    38  	})
    39  
    40  	// Make the request without having a node-id
    41  	req := &structs.NodeSpecificRequest{
    42  		QueryOptions: structs.QueryOptions{Region: "global"},
    43  	}
    44  
    45  	// Fetch the response
    46  	var resp cstructs.ClientStatsResponse
    47  	err := msgpackrpc.CallWithCodec(codec, "ClientStats.Stats", req, &resp)
    48  	require.NotNil(err)
    49  	require.Contains(err.Error(), "missing")
    50  
    51  	// Fetch the response setting the node id
    52  	req.NodeID = c.NodeID()
    53  	var resp2 cstructs.ClientStatsResponse
    54  	err = msgpackrpc.CallWithCodec(codec, "ClientStats.Stats", req, &resp2)
    55  	require.Nil(err)
    56  	require.NotNil(resp2.HostStats)
    57  }
    58  
    59  func TestClientStats_Stats_Local_ACL(t *testing.T) {
    60  	t.Parallel()
    61  	require := require.New(t)
    62  
    63  	// Start a server
    64  	s, root := TestACLServer(t, nil)
    65  	defer s.Shutdown()
    66  	codec := rpcClient(t, s)
    67  	testutil.WaitForLeader(t, s.RPC)
    68  
    69  	// Create a bad token
    70  	policyBad := mock.NamespacePolicy("other", "", []string{acl.NamespaceCapabilityReadFS})
    71  	tokenBad := mock.CreatePolicyAndToken(t, s.State(), 1005, "invalid", policyBad)
    72  
    73  	policyGood := mock.NodePolicy(acl.PolicyRead)
    74  	tokenGood := mock.CreatePolicyAndToken(t, s.State(), 1009, "valid2", policyGood)
    75  
    76  	cases := []struct {
    77  		Name          string
    78  		Token         string
    79  		ExpectedError string
    80  	}{
    81  		{
    82  			Name:          "bad token",
    83  			Token:         tokenBad.SecretID,
    84  			ExpectedError: structs.ErrPermissionDenied.Error(),
    85  		},
    86  		{
    87  			Name:          "good token",
    88  			Token:         tokenGood.SecretID,
    89  			ExpectedError: "Unknown node",
    90  		},
    91  		{
    92  			Name:          "root token",
    93  			Token:         root.SecretID,
    94  			ExpectedError: "Unknown node",
    95  		},
    96  	}
    97  
    98  	for _, c := range cases {
    99  		t.Run(c.Name, func(t *testing.T) {
   100  
   101  			// Make the request without having a node-id
   102  			req := &structs.NodeSpecificRequest{
   103  				NodeID: uuid.Generate(),
   104  				QueryOptions: structs.QueryOptions{
   105  					AuthToken: c.Token,
   106  					Region:    "global",
   107  				},
   108  			}
   109  
   110  			// Fetch the response
   111  			var resp cstructs.ClientStatsResponse
   112  			err := msgpackrpc.CallWithCodec(codec, "ClientStats.Stats", req, &resp)
   113  			require.NotNil(err)
   114  			require.Contains(err.Error(), c.ExpectedError)
   115  		})
   116  	}
   117  }
   118  
   119  func TestClientStats_Stats_NoNode(t *testing.T) {
   120  	t.Parallel()
   121  	require := require.New(t)
   122  
   123  	// Start a server and client
   124  	s := TestServer(t, nil)
   125  	defer s.Shutdown()
   126  	codec := rpcClient(t, s)
   127  	testutil.WaitForLeader(t, s.RPC)
   128  
   129  	// Make the request with a nonexistent node-id
   130  	req := &structs.NodeSpecificRequest{
   131  		NodeID:       uuid.Generate(),
   132  		QueryOptions: structs.QueryOptions{Region: "global"},
   133  	}
   134  
   135  	// Fetch the response
   136  	var resp cstructs.ClientStatsResponse
   137  	err := msgpackrpc.CallWithCodec(codec, "ClientStats.Stats", req, &resp)
   138  	require.Nil(resp.HostStats)
   139  	require.NotNil(err)
   140  	require.Contains(err.Error(), "Unknown node")
   141  }
   142  
   143  func TestClientStats_Stats_OldNode(t *testing.T) {
   144  	t.Parallel()
   145  	require := require.New(t)
   146  
   147  	// Start a server
   148  	s := TestServer(t, nil)
   149  	defer s.Shutdown()
   150  	state := s.State()
   151  	codec := rpcClient(t, s)
   152  	testutil.WaitForLeader(t, s.RPC)
   153  
   154  	// Test for an old version error
   155  	node := mock.Node()
   156  	node.Attributes["nomad.version"] = "0.7.1"
   157  	require.Nil(state.UpsertNode(1005, node))
   158  
   159  	req := &structs.NodeSpecificRequest{
   160  		NodeID:       node.ID,
   161  		QueryOptions: structs.QueryOptions{Region: "global"},
   162  	}
   163  
   164  	// Fetch the response
   165  	var resp cstructs.ClientStatsResponse
   166  	err := msgpackrpc.CallWithCodec(codec, "ClientStats.Stats", req, &resp)
   167  	require.True(structs.IsErrNodeLacksRpc(err), err.Error())
   168  }
   169  
   170  func TestClientStats_Stats_Remote(t *testing.T) {
   171  	t.Parallel()
   172  	require := require.New(t)
   173  
   174  	// Start a server and client
   175  	s1 := TestServer(t, nil)
   176  	defer s1.Shutdown()
   177  	s2 := TestServer(t, func(c *Config) {
   178  		c.DevDisableBootstrap = true
   179  	})
   180  	defer s2.Shutdown()
   181  	TestJoin(t, s1, s2)
   182  	testutil.WaitForLeader(t, s1.RPC)
   183  	testutil.WaitForLeader(t, s2.RPC)
   184  	codec := rpcClient(t, s2)
   185  
   186  	c := client.TestClient(t, func(c *config.Config) {
   187  		c.Servers = []string{s2.config.RPCAddr.String()}
   188  	})
   189  	defer c.Shutdown()
   190  
   191  	testutil.WaitForResult(func() (bool, error) {
   192  		nodes := s2.connectedNodes()
   193  		return len(nodes) == 1, nil
   194  	}, func(err error) {
   195  		t.Fatalf("should have a clients")
   196  	})
   197  
   198  	// Force remove the connection locally in case it exists
   199  	s1.nodeConnsLock.Lock()
   200  	delete(s1.nodeConns, c.NodeID())
   201  	s1.nodeConnsLock.Unlock()
   202  
   203  	// Make the request without having a node-id
   204  	req := &structs.NodeSpecificRequest{
   205  		NodeID:       uuid.Generate(),
   206  		QueryOptions: structs.QueryOptions{Region: "global"},
   207  	}
   208  
   209  	// Fetch the response
   210  	req.NodeID = c.NodeID()
   211  	var resp cstructs.ClientStatsResponse
   212  	err := msgpackrpc.CallWithCodec(codec, "ClientStats.Stats", req, &resp)
   213  	require.Nil(err)
   214  	require.NotNil(resp.HostStats)
   215  }