From a1ca453b4b9097783e11a8f07f3376fc666bce37 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Mon, 6 Jul 2015 14:42:33 -0600 Subject: [PATCH] nomad: adding client deregister endpoint --- nomad/client_endpoint.go | 21 +++++++++++++++++ nomad/client_endpoint_test.go | 43 +++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/nomad/client_endpoint.go b/nomad/client_endpoint.go index 64e851c6b..cb156c192 100644 --- a/nomad/client_endpoint.go +++ b/nomad/client_endpoint.go @@ -51,6 +51,27 @@ func (c *Client) Register(args *structs.RegisterRequest, reply *structs.GenericR return nil } +// Deregister is used to remove a client from the client. If a client should +// just be made unavailable for scheduling, a status update is prefered. func (c *Client) Deregister(args *structs.DeregisterRequest, reply *structs.GenericResponse) error { + if done, err := c.srv.forward("Client.Deregister", args, args, reply); done { + return err + } + defer metrics.MeasureSince([]string{"nomad", "client", "deregister"}, time.Now()) + + // Verify the arguments + if args.NodeID == "" { + return fmt.Errorf("missing node ID for client deregistration") + } + + // Commit this update via Raft + _, index, err := c.srv.raftApply(structs.DeregisterRequestType, args) + if err != nil { + c.srv.logger.Printf("[ERR] nomad.client: Deregister failed: %v", err) + return err + } + + // Set the reply index + reply.Index = index return nil } diff --git a/nomad/client_endpoint_test.go b/nomad/client_endpoint_test.go index 1965e6f2f..b1fcc6f2e 100644 --- a/nomad/client_endpoint_test.go +++ b/nomad/client_endpoint_test.go @@ -43,3 +43,46 @@ func TestClientEndpoint_Register(t *testing.T) { t.Fatalf("index mis-match") } } + +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 + node := mockNode() + reg := &structs.RegisterRequest{ + Node: node, + WriteRequest: structs.WriteRequest{Region: "region1"}, + } + + // Fetch the response + var resp structs.GenericResponse + if err := msgpackrpc.CallWithCodec(codec, "Client.Register", reg, &resp); err != nil { + t.Fatalf("err: %v", err) + } + + // Deregister + dereg := &structs.DeregisterRequest{ + NodeID: node.ID, + WriteRequest: structs.WriteRequest{Region: "region1"}, + } + var resp2 structs.GenericResponse + if err := msgpackrpc.CallWithCodec(codec, "Client.Deregister", dereg, &resp2); err != nil { + 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() + out, err := state.GetNodeByID(node.ID) + if err != nil { + t.Fatalf("err: %v", err) + } + if out != nil { + t.Fatalf("unexpected node") + } +}