diff --git a/api/agent.go b/api/agent.go index 10248d9b6..ae2eb1a61 100644 --- a/api/agent.go +++ b/api/agent.go @@ -116,9 +116,42 @@ func (a *Agent) Join(addrs ...string) error { return nil } +// Members is used to query all of the known server members +func (a *Agent) Members() ([]*AgentMember, error) { + var resp []*AgentMember + + // Query the known members + _, err := a.client.query("/v1/agent/members", &resp, nil) + if err != nil { + return nil, err + } + return resp, nil +} + +// ForceLeave is used to eject an existing node from the cluster. +func (a *Agent) ForceLeave(node string) error { + _, err := a.client.write("/v1/agent/force-leave?node="+node, nil, nil, nil) + return err +} + // joinResponse is used to decode the response we get while // sending a member join request. type joinResponse struct { NumNodes int `json:"num_nodes"` Error string `json:"error"` } + +// AgentMember represents a cluster member known to the agent +type AgentMember struct { + Name string + Addr string + Port uint16 + Tags map[string]string + Status int + ProtocolMin uint8 + ProtocolMax uint8 + ProtocolCur uint8 + DelegateMin uint8 + DelegateMax uint8 + DelegateCur uint8 +} diff --git a/api/agent_test.go b/api/agent_test.go index 54de793ad..7eb891ea1 100644 --- a/api/agent_test.go +++ b/api/agent_test.go @@ -76,3 +76,36 @@ func TestAgent_Join(t *testing.T) { t.Fatalf("err: %s", err) } } + +func TestAgent_Members(t *testing.T) { + c, s := makeClient(t, nil, nil) + defer s.Stop() + a := c.Agent() + + // Query nomad for all the known members + mem, err := a.Members() + if err != nil { + t.Fatalf("err: %s", err) + } + + // Check that we got the expected result + if n := len(mem); n != 1 { + t.Fatalf("expected 1 member, got: %d", n) + } + if m := mem[0]; m.Name == "" || m.Addr == "" || m.Port == 0 { + t.Fatalf("bad member: %#v", m) + } +} + +func TestAgent_ForceLeave(t *testing.T) { + c, s := makeClient(t, nil, nil) + defer s.Stop() + a := c.Agent() + + // Force-leave on a non-existent node does not error + if err := a.ForceLeave("nope"); err != nil { + t.Fatalf("err: %s", err) + } + + // TODO: test force-leave on an existing node +}