2015-07-06 20:23:11 +00:00
|
|
|
package nomad
|
|
|
|
|
|
|
|
import (
|
2015-07-06 21:38:57 +00:00
|
|
|
"reflect"
|
2015-07-06 20:23:11 +00:00
|
|
|
"testing"
|
2015-08-23 02:17:49 +00:00
|
|
|
"time"
|
2015-07-06 20:23:11 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/net-rpc-msgpackrpc"
|
2015-08-11 21:27:14 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/mock"
|
2015-07-06 20:23:11 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
"github.com/hashicorp/nomad/testutil"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestClientEndpoint_Register(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
2015-08-11 21:27:14 +00:00
|
|
|
node := mock.Node()
|
2015-07-07 16:51:42 +00:00
|
|
|
req := &structs.NodeRegisterRequest{
|
2015-07-06 20:23:11 +00:00
|
|
|
Node: node,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-07-06 20:23:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
|
|
|
var resp structs.GenericResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp); err != nil {
|
2015-07-06 20:23:11 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2015-07-06 20:34:32 +00:00
|
|
|
if resp.Index == 0 {
|
|
|
|
t.Fatalf("bad index: %d", resp.Index)
|
|
|
|
}
|
2015-07-06 20:23:11 +00:00
|
|
|
|
|
|
|
// Check for the node in the FSM
|
|
|
|
state := s1.fsm.State()
|
2015-09-07 03:56:38 +00:00
|
|
|
out, err := state.NodeByID(node.ID)
|
2015-07-06 20:23:11 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if out == nil {
|
|
|
|
t.Fatalf("expected node")
|
|
|
|
}
|
2015-07-06 20:34:32 +00:00
|
|
|
if out.CreateIndex != resp.Index {
|
|
|
|
t.Fatalf("index mis-match")
|
|
|
|
}
|
2015-07-06 20:23:11 +00:00
|
|
|
}
|
2015-07-06 20:42:33 +00:00
|
|
|
|
|
|
|
func TestClientEndpoint_Deregister(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
2015-08-11 21:27:14 +00:00
|
|
|
node := mock.Node()
|
2015-07-07 16:51:42 +00:00
|
|
|
reg := &structs.NodeRegisterRequest{
|
2015-07-06 20:42:33 +00:00
|
|
|
Node: node,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-07-06 20:42:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
|
|
|
var resp structs.GenericResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil {
|
2015-07-06 20:42:33 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deregister
|
2015-07-07 16:51:42 +00:00
|
|
|
dereg := &structs.NodeDeregisterRequest{
|
2015-07-06 20:42:33 +00:00
|
|
|
NodeID: node.ID,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-07-06 20:42:33 +00:00
|
|
|
}
|
|
|
|
var resp2 structs.GenericResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.Deregister", dereg, &resp2); err != nil {
|
2015-07-06 20:42:33 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp2.Index == 0 {
|
|
|
|
t.Fatalf("bad index: %d", resp2.Index)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for the node in the FSM
|
|
|
|
state := s1.fsm.State()
|
2015-09-07 03:56:38 +00:00
|
|
|
out, err := state.NodeByID(node.ID)
|
2015-07-06 20:42:33 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if out != nil {
|
|
|
|
t.Fatalf("unexpected node")
|
|
|
|
}
|
|
|
|
}
|
2015-07-06 20:50:40 +00:00
|
|
|
|
|
|
|
func TestClientEndpoint_UpdateStatus(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
2015-08-11 21:27:14 +00:00
|
|
|
node := mock.Node()
|
2015-07-07 16:51:42 +00:00
|
|
|
reg := &structs.NodeRegisterRequest{
|
2015-07-06 20:50:40 +00:00
|
|
|
Node: node,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-07-06 20:50:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
2015-08-23 00:49:48 +00:00
|
|
|
var resp structs.NodeUpdateResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil {
|
2015-07-06 20:50:40 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-08-23 00:49:48 +00:00
|
|
|
// Check for heartbeat interval
|
2015-08-23 01:16:05 +00:00
|
|
|
ttl := resp.HeartbeatTTL
|
2015-08-31 01:10:12 +00:00
|
|
|
if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL {
|
2015-08-23 01:16:05 +00:00
|
|
|
t.Fatalf("bad: %#v", ttl)
|
2015-08-23 00:49:48 +00:00
|
|
|
}
|
|
|
|
|
2015-07-06 20:50:40 +00:00
|
|
|
// Update the status
|
2015-07-07 16:51:42 +00:00
|
|
|
dereg := &structs.NodeUpdateStatusRequest{
|
2015-07-06 20:50:40 +00:00
|
|
|
NodeID: node.ID,
|
2015-09-07 02:47:02 +00:00
|
|
|
Status: structs.NodeStatusInit,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-07-06 20:50:40 +00:00
|
|
|
}
|
2015-08-23 00:49:48 +00:00
|
|
|
var resp2 structs.NodeUpdateResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateStatus", dereg, &resp2); err != nil {
|
2015-07-06 20:50:40 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp2.Index == 0 {
|
|
|
|
t.Fatalf("bad index: %d", resp2.Index)
|
|
|
|
}
|
|
|
|
|
2015-08-23 00:49:48 +00:00
|
|
|
// Check for heartbeat interval
|
2015-08-23 01:16:05 +00:00
|
|
|
ttl = resp2.HeartbeatTTL
|
2015-08-31 01:10:12 +00:00
|
|
|
if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL {
|
2015-08-23 01:16:05 +00:00
|
|
|
t.Fatalf("bad: %#v", ttl)
|
2015-08-23 00:49:48 +00:00
|
|
|
}
|
|
|
|
|
2015-07-06 20:50:40 +00:00
|
|
|
// Check for the node in the FSM
|
|
|
|
state := s1.fsm.State()
|
2015-09-07 03:56:38 +00:00
|
|
|
out, err := state.NodeByID(node.ID)
|
2015-07-06 20:50:40 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if out == nil {
|
|
|
|
t.Fatalf("expected node")
|
|
|
|
}
|
|
|
|
if out.ModifyIndex != resp2.Index {
|
|
|
|
t.Fatalf("index mis-match")
|
|
|
|
}
|
|
|
|
}
|
2015-07-06 21:38:57 +00:00
|
|
|
|
2015-08-23 00:49:48 +00:00
|
|
|
func TestClientEndpoint_UpdateStatus_HeartbeatOnly(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
|
|
|
node := mock.Node()
|
|
|
|
reg := &structs.NodeRegisterRequest{
|
|
|
|
Node: node,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-08-23 00:49:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
|
|
|
var resp structs.NodeUpdateResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil {
|
2015-08-23 00:49:48 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for heartbeat interval
|
2015-08-23 01:16:05 +00:00
|
|
|
ttl := resp.HeartbeatTTL
|
2015-08-31 01:10:12 +00:00
|
|
|
if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL {
|
2015-08-23 01:16:05 +00:00
|
|
|
t.Fatalf("bad: %#v", ttl)
|
2015-08-23 00:49:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update the status, static state
|
|
|
|
dereg := &structs.NodeUpdateStatusRequest{
|
|
|
|
NodeID: node.ID,
|
|
|
|
Status: node.Status,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-08-23 00:49:48 +00:00
|
|
|
}
|
|
|
|
var resp2 structs.NodeUpdateResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateStatus", dereg, &resp2); err != nil {
|
2015-08-23 00:49:48 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp2.Index != 0 {
|
|
|
|
t.Fatalf("bad index: %d", resp2.Index)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for heartbeat interval
|
2015-08-23 01:16:05 +00:00
|
|
|
ttl = resp2.HeartbeatTTL
|
2015-08-31 01:10:12 +00:00
|
|
|
if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL {
|
2015-08-23 01:16:05 +00:00
|
|
|
t.Fatalf("bad: %#v", ttl)
|
2015-08-23 00:49:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-07 03:00:12 +00:00
|
|
|
func TestClientEndpoint_UpdateDrain(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
|
|
|
node := mock.Node()
|
|
|
|
reg := &structs.NodeRegisterRequest{
|
|
|
|
Node: node,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-09-07 03:00:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
|
|
|
var resp structs.NodeUpdateResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil {
|
2015-09-07 03:00:12 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the status
|
|
|
|
dereg := &structs.NodeUpdateDrainRequest{
|
|
|
|
NodeID: node.ID,
|
|
|
|
Drain: true,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-09-07 03:00:12 +00:00
|
|
|
}
|
|
|
|
var resp2 structs.NodeDrainUpdateResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateDrain", dereg, &resp2); err != nil {
|
2015-09-07 03:00:12 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp2.Index == 0 {
|
|
|
|
t.Fatalf("bad index: %d", resp2.Index)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for the node in the FSM
|
|
|
|
state := s1.fsm.State()
|
2015-09-07 03:56:38 +00:00
|
|
|
out, err := state.NodeByID(node.ID)
|
2015-09-07 03:00:12 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if !out.Drain {
|
|
|
|
t.Fatalf("bad: %#v", out)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-06 21:38:57 +00:00
|
|
|
func TestClientEndpoint_GetNode(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
2015-08-11 21:27:14 +00:00
|
|
|
node := mock.Node()
|
2015-07-07 16:51:42 +00:00
|
|
|
reg := &structs.NodeRegisterRequest{
|
2015-07-06 21:38:57 +00:00
|
|
|
Node: node,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-07-06 21:38:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
|
|
|
var resp structs.GenericResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil {
|
2015-07-06 21:38:57 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
node.CreateIndex = resp.Index
|
|
|
|
node.ModifyIndex = resp.Index
|
|
|
|
|
|
|
|
// Lookup the node
|
|
|
|
get := &structs.NodeSpecificRequest{
|
|
|
|
NodeID: node.ID,
|
2015-09-14 01:18:40 +00:00
|
|
|
QueryOptions: structs.QueryOptions{Region: "global"},
|
2015-07-06 21:38:57 +00:00
|
|
|
}
|
|
|
|
var resp2 structs.SingleNodeResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", get, &resp2); err != nil {
|
2015-07-06 21:38:57 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp2.Index != resp.Index {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(node, resp2.Node) {
|
|
|
|
t.Fatalf("bad: %#v %#v", node, resp2.Node)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup non-existing node
|
|
|
|
get.NodeID = "foobarbaz"
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", get, &resp2); err != nil {
|
2015-07-06 21:38:57 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp2.Index != resp.Index {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index)
|
|
|
|
}
|
|
|
|
if resp2.Node != nil {
|
|
|
|
t.Fatalf("unexpected node")
|
|
|
|
}
|
|
|
|
}
|
2015-08-06 23:39:20 +00:00
|
|
|
|
2015-08-23 02:17:49 +00:00
|
|
|
func TestClientEndpoint_GetAllocs(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
|
|
|
node := mock.Node()
|
|
|
|
reg := &structs.NodeRegisterRequest{
|
|
|
|
Node: node,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-08-23 02:17:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
|
|
|
var resp structs.GenericResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil {
|
2015-08-23 02:17:49 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
node.CreateIndex = resp.Index
|
|
|
|
node.ModifyIndex = resp.Index
|
|
|
|
|
|
|
|
// Inject fake evaluations
|
|
|
|
alloc := mock.Alloc()
|
|
|
|
alloc.NodeID = node.ID
|
|
|
|
state := s1.fsm.State()
|
2015-09-07 03:47:42 +00:00
|
|
|
err := state.UpsertAllocs(100, []*structs.Allocation{alloc})
|
2015-08-23 02:17:49 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup the allocs
|
|
|
|
get := &structs.NodeSpecificRequest{
|
|
|
|
NodeID: node.ID,
|
2015-09-14 01:18:40 +00:00
|
|
|
QueryOptions: structs.QueryOptions{Region: "global"},
|
2015-08-23 02:17:49 +00:00
|
|
|
}
|
|
|
|
var resp2 structs.NodeAllocsResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", get, &resp2); err != nil {
|
2015-08-23 02:17:49 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp2.Index != 100 {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp2.Index, 100)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(resp2.Allocs) != 1 || resp2.Allocs[0].ID != alloc.ID {
|
|
|
|
t.Fatalf("bad: %#v", resp2.Allocs)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup non-existing node
|
|
|
|
get.NodeID = "foobarbaz"
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", get, &resp2); err != nil {
|
2015-08-23 02:17:49 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp2.Index != 100 {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp2.Index, 100)
|
|
|
|
}
|
|
|
|
if len(resp2.Allocs) != 0 {
|
|
|
|
t.Fatalf("unexpected node")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestClientEndpoint_GetAllocs_Blocking(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
|
|
|
node := mock.Node()
|
|
|
|
reg := &structs.NodeRegisterRequest{
|
|
|
|
Node: node,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-08-23 02:17:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
|
|
|
var resp structs.GenericResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil {
|
2015-08-23 02:17:49 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
node.CreateIndex = resp.Index
|
|
|
|
node.ModifyIndex = resp.Index
|
|
|
|
|
|
|
|
// Inject fake evaluations async
|
|
|
|
alloc := mock.Alloc()
|
|
|
|
alloc.NodeID = node.ID
|
|
|
|
state := s1.fsm.State()
|
|
|
|
start := time.Now()
|
|
|
|
go func() {
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
2015-09-07 03:47:42 +00:00
|
|
|
err := state.UpsertAllocs(100, []*structs.Allocation{alloc})
|
2015-08-23 02:17:49 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Lookup the allocs in a blocking query
|
|
|
|
get := &structs.NodeSpecificRequest{
|
|
|
|
NodeID: node.ID,
|
|
|
|
QueryOptions: structs.QueryOptions{
|
2015-09-14 01:18:40 +00:00
|
|
|
Region: "global",
|
2015-08-23 02:17:49 +00:00
|
|
|
MinQueryIndex: 50,
|
|
|
|
MaxQueryTime: time.Second,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
var resp2 structs.NodeAllocsResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", get, &resp2); err != nil {
|
2015-08-23 02:17:49 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Should block at least 100ms
|
|
|
|
if time.Since(start) < 100*time.Millisecond {
|
|
|
|
t.Fatalf("too fast")
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp2.Index != 100 {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp2.Index, 100)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(resp2.Allocs) != 1 || resp2.Allocs[0].ID != alloc.ID {
|
|
|
|
t.Fatalf("bad: %#v", resp2.Allocs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-26 01:12:51 +00:00
|
|
|
func TestClientEndpoint_UpdateAlloc(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
|
|
|
node := mock.Node()
|
|
|
|
reg := &structs.NodeRegisterRequest{
|
|
|
|
Node: node,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-08-26 01:12:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
|
|
|
var resp structs.GenericResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil {
|
2015-08-26 01:12:51 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Inject fake evaluations
|
|
|
|
alloc := mock.Alloc()
|
|
|
|
alloc.NodeID = node.ID
|
|
|
|
state := s1.fsm.State()
|
2015-09-07 03:47:42 +00:00
|
|
|
err := state.UpsertAllocs(100, []*structs.Allocation{alloc})
|
2015-08-26 01:12:51 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt update
|
|
|
|
clientAlloc := new(structs.Allocation)
|
|
|
|
*clientAlloc = *alloc
|
|
|
|
clientAlloc.ClientStatus = structs.AllocClientStatusFailed
|
|
|
|
|
|
|
|
// Update the alloc
|
|
|
|
update := &structs.AllocUpdateRequest{
|
|
|
|
Alloc: []*structs.Allocation{clientAlloc},
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-08-26 01:12:51 +00:00
|
|
|
}
|
|
|
|
var resp2 structs.NodeAllocsResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateAlloc", update, &resp2); err != nil {
|
2015-08-26 01:12:51 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp2.Index == 0 {
|
|
|
|
t.Fatalf("Bad index: %d", resp2.Index)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup the alloc
|
2015-09-07 03:56:38 +00:00
|
|
|
out, err := state.AllocByID(alloc.ID)
|
2015-08-26 01:12:51 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if out.ClientStatus != structs.AllocClientStatusFailed {
|
|
|
|
t.Fatalf("Bad: %#v", out)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-06 23:39:20 +00:00
|
|
|
func TestClientEndpoint_CreateNodeEvals(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Inject fake evaluations
|
2015-08-11 21:27:14 +00:00
|
|
|
alloc := mock.Alloc()
|
2015-08-06 23:39:20 +00:00
|
|
|
state := s1.fsm.State()
|
2015-09-07 03:47:42 +00:00
|
|
|
err := state.UpsertAllocs(1, []*structs.Allocation{alloc})
|
2015-08-06 23:39:20 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create some evaluations
|
2015-09-07 03:31:32 +00:00
|
|
|
ids, index, err := s1.endpoints.Node.createNodeEvals(alloc.NodeID, 1)
|
2015-08-06 23:39:20 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if index == 0 {
|
|
|
|
t.Fatalf("bad: %d", index)
|
|
|
|
}
|
|
|
|
if len(ids) != 1 {
|
|
|
|
t.Fatalf("bad: %s", ids)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup the evaluation
|
2015-09-07 03:56:38 +00:00
|
|
|
eval, err := state.EvalByID(ids[0])
|
2015-08-06 23:39:20 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if eval == nil {
|
|
|
|
t.Fatalf("expected eval")
|
|
|
|
}
|
|
|
|
if eval.CreateIndex != index {
|
|
|
|
t.Fatalf("index mis-match")
|
|
|
|
}
|
|
|
|
|
|
|
|
if eval.Priority != alloc.Job.Priority {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.Type != alloc.Job.Type {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.TriggeredBy != structs.EvalTriggerNodeUpdate {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.JobID != alloc.JobID {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.NodeID != alloc.NodeID {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.NodeModifyIndex != 1 {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.Status != structs.EvalStatusPending {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
}
|
2015-08-16 01:20:35 +00:00
|
|
|
|
|
|
|
func TestClientEndpoint_Evaluate(t *testing.T) {
|
2015-10-08 22:36:42 +00:00
|
|
|
s1 := testServer(t, func(c *Config) {
|
|
|
|
c.NumSchedulers = 0 // Prevent automatic dequeue
|
|
|
|
})
|
2015-08-16 01:20:35 +00:00
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Inject fake evaluations
|
|
|
|
alloc := mock.Alloc()
|
|
|
|
node := mock.Node()
|
|
|
|
node.ID = alloc.NodeID
|
|
|
|
state := s1.fsm.State()
|
2015-09-07 03:47:42 +00:00
|
|
|
err := state.UpsertNode(1, node)
|
2015-08-16 01:20:35 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2015-09-07 03:47:42 +00:00
|
|
|
err = state.UpsertAllocs(2, []*structs.Allocation{alloc})
|
2015-08-16 01:20:35 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Re-evaluate
|
|
|
|
req := &structs.NodeEvaluateRequest{
|
|
|
|
NodeID: alloc.NodeID,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-08-16 01:20:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
|
|
|
var resp structs.NodeUpdateResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.Evaluate", req, &resp); err != nil {
|
2015-08-16 01:20:35 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp.Index == 0 {
|
|
|
|
t.Fatalf("bad index: %d", resp.Index)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create some evaluations
|
|
|
|
ids := resp.EvalIDs
|
|
|
|
if len(ids) != 1 {
|
|
|
|
t.Fatalf("bad: %s", ids)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup the evaluation
|
2015-09-07 03:56:38 +00:00
|
|
|
eval, err := state.EvalByID(ids[0])
|
2015-08-16 01:20:35 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if eval == nil {
|
|
|
|
t.Fatalf("expected eval")
|
|
|
|
}
|
|
|
|
if eval.CreateIndex != resp.Index {
|
|
|
|
t.Fatalf("index mis-match")
|
|
|
|
}
|
|
|
|
|
|
|
|
if eval.Priority != alloc.Job.Priority {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.Type != alloc.Job.Type {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.TriggeredBy != structs.EvalTriggerNodeUpdate {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.JobID != alloc.JobID {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.NodeID != alloc.NodeID {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.NodeModifyIndex != 1 {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
if eval.Status != structs.EvalStatusPending {
|
|
|
|
t.Fatalf("bad: %#v", eval)
|
|
|
|
}
|
|
|
|
}
|
2015-09-06 21:28:29 +00:00
|
|
|
|
|
|
|
func TestClientEndpoint_ListNodes(t *testing.T) {
|
|
|
|
s1 := testServer(t, nil)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
codec := rpcClient(t, s1)
|
|
|
|
testutil.WaitForLeader(t, s1.RPC)
|
|
|
|
|
|
|
|
// Create the register request
|
|
|
|
node := mock.Node()
|
|
|
|
reg := &structs.NodeRegisterRequest{
|
|
|
|
Node: node,
|
2015-09-14 01:18:40 +00:00
|
|
|
WriteRequest: structs.WriteRequest{Region: "global"},
|
2015-09-06 21:28:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch the response
|
|
|
|
var resp structs.GenericResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil {
|
2015-09-06 21:28:29 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
node.CreateIndex = resp.Index
|
|
|
|
node.ModifyIndex = resp.Index
|
|
|
|
|
|
|
|
// Lookup the node
|
|
|
|
get := &structs.NodeListRequest{
|
2015-09-14 01:18:40 +00:00
|
|
|
QueryOptions: structs.QueryOptions{Region: "global"},
|
2015-09-06 21:28:29 +00:00
|
|
|
}
|
|
|
|
var resp2 structs.NodeListResponse
|
2015-09-07 03:31:32 +00:00
|
|
|
if err := msgpackrpc.CallWithCodec(codec, "Node.List", get, &resp2); err != nil {
|
2015-09-06 21:28:29 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if resp2.Index != resp.Index {
|
|
|
|
t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(resp2.Nodes) != 1 {
|
|
|
|
t.Fatalf("bad: %#v", resp2.Nodes)
|
|
|
|
}
|
|
|
|
if resp2.Nodes[0].ID != node.ID {
|
|
|
|
t.Fatalf("bad: %#v", resp2.Nodes[0])
|
|
|
|
}
|
|
|
|
}
|