give feedback to CLI user on forceleave command if node does not exist (#6841)

This commit is contained in:
Sarah Adams 2019-12-02 11:06:15 -08:00 committed by GitHub
parent 11f690479b
commit aed5cb7669
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 5 deletions

View File

@ -1782,6 +1782,9 @@ func (a *Agent) JoinWAN(addrs []string) (n int, err error) {
// ForceLeave is used to remove a failed node from the cluster // ForceLeave is used to remove a failed node from the cluster
func (a *Agent) ForceLeave(node string, prune bool) (err error) { func (a *Agent) ForceLeave(node string, prune bool) (err error) {
a.logger.Printf("[INFO] agent: Force leaving node: %v", node) a.logger.Printf("[INFO] agent: Force leaving node: %v", node)
if ok := a.IsMember(node); !ok {
return fmt.Errorf("agent: No node found with name '%s'", node)
}
err = a.delegate.RemoveFailedNode(node, prune) err = a.delegate.RemoveFailedNode(node, prune)
if err != nil { if err != nil {
a.logger.Printf("[WARN] agent: Failed to remove node: %v", err) a.logger.Printf("[WARN] agent: Failed to remove node: %v", err)
@ -1807,6 +1810,18 @@ func (a *Agent) WANMembers() []serf.Member {
return nil return nil
} }
// IsMember is used to check if a node with the given nodeName
// is a member
func (a *Agent) IsMember(nodeName string) bool {
for _, m := range a.LANMembers() {
if m.Name == nodeName {
return true
}
}
return false
}
// StartSync is called once Services and Checks are registered. // StartSync is called once Services and Checks are registered.
// This is called to prevent a race between clients and the anti-entropy routines // This is called to prevent a race between clients and the anti-entropy routines
func (a *Agent) StartSync() { func (a *Agent) StartSync() {

View File

@ -1632,15 +1632,17 @@ func TestAgent_ForceLeave_ACLDeny(t *testing.T) {
defer a.Shutdown() defer a.Shutdown()
testrpc.WaitForLeader(t, a.RPC, "dc1") testrpc.WaitForLeader(t, a.RPC, "dc1")
uri := fmt.Sprintf("/v1/agent/force-leave/%s", a.Config.NodeName)
t.Run("no token", func(t *testing.T) { t.Run("no token", func(t *testing.T) {
req, _ := http.NewRequest("PUT", "/v1/agent/force-leave/nope", nil) req, _ := http.NewRequest("PUT", uri, nil)
if _, err := a.srv.AgentForceLeave(nil, req); !acl.IsErrPermissionDenied(err) { if _, err := a.srv.AgentForceLeave(nil, req); !acl.IsErrPermissionDenied(err) {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
}) })
t.Run("agent master token", func(t *testing.T) { t.Run("agent master token", func(t *testing.T) {
req, _ := http.NewRequest("PUT", "/v1/agent/force-leave/nope?token=towel", nil) req, _ := http.NewRequest("PUT", uri+"?token=towel", nil)
if _, err := a.srv.AgentForceLeave(nil, req); err != nil { if _, err := a.srv.AgentForceLeave(nil, req); err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
@ -1648,7 +1650,7 @@ func TestAgent_ForceLeave_ACLDeny(t *testing.T) {
t.Run("read-only token", func(t *testing.T) { t.Run("read-only token", func(t *testing.T) {
ro := makeReadOnlyAgentACL(t, a.srv) ro := makeReadOnlyAgentACL(t, a.srv)
req, _ := http.NewRequest("PUT", fmt.Sprintf("/v1/agent/force-leave/nope?token=%s", ro), nil) req, _ := http.NewRequest("PUT", fmt.Sprintf(uri+"?token=%s", ro), nil)
if _, err := a.srv.AgentForceLeave(nil, req); !acl.IsErrPermissionDenied(err) { if _, err := a.srv.AgentForceLeave(nil, req); !acl.IsErrPermissionDenied(err) {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }

View File

@ -1073,7 +1073,7 @@ func TestAPI_AgentForceLeave(t *testing.T) {
agent := c.Agent() agent := c.Agent()
// Eject somebody // Eject somebody
err := agent.ForceLeave("foo") err := agent.ForceLeave(s.Config.NodeName)
if err != nil { if err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
@ -1087,7 +1087,7 @@ func TestAPI_AgentForceLeavePrune(t *testing.T) {
agent := c.Agent() agent := c.Agent()
// Eject somebody // Eject somebody
err := agent.ForceLeavePrune("foo") err := agent.ForceLeavePrune(s.Config.NodeName)
if err != nil { if err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }

View File

@ -56,6 +56,24 @@ func TestForceLeaveCommand(t *testing.T) {
}) })
} }
func TestForceLeaveCommand_NoNodeWithName(t *testing.T) {
t.Parallel()
a1 := agent.NewTestAgent(t, t.Name(), ``)
defer a1.Shutdown()
ui := cli.NewMockUi()
c := New(ui)
args := []string{
"-http-addr=" + a1.HTTPAddr(),
"garbage-name",
}
code := c.Run(args)
if code != 1 {
t.Fatalf("bad: %d. %#v", code, ui.ErrorWriter.String())
}
}
func TestForceLeaveCommand_prune(t *testing.T) { func TestForceLeaveCommand_prune(t *testing.T) {
t.Parallel() t.Parallel()
a1 := agent.NewTestAgent(t, t.Name()+"-a1", ``) a1 := agent.NewTestAgent(t, t.Name()+"-a1", ``)