github.com/zoomfoo/nomad@v0.8.5-0.20180907175415-f28fd3a1a056/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 }