fix AgentHostRequest panic found in GH-9546 (#9554)

* debug: refactor nodeclass test
* debug: add case to track down SIGSEGV on client to server Agent.Host RPC
* verify server to avoid panic on AgentHostRequest RPC call, fixes GH-9546
* simplify Agent.Host RPC lookup logic
This commit is contained in:
Dave May
2020-12-07 17:34:40 -05:00
committed by GitHub
parent 44c236788e
commit d757507341
2 changed files with 147 additions and 24 deletions

View File

@@ -95,7 +95,7 @@ func TestDebug_NodeClass(t *testing.T) {
srvRPCAddr := srv.GetConfig().AdvertiseAddrs.RPC
t.Logf("[TEST] Leader started, srv.GetConfig().AdvertiseAddrs.RPC: %s", srvRPCAddr)
// Setup Client 1 (nodeclass = clienta)
// Setup client 1 (nodeclass = clienta)
agentConfFunc1 := func(c *agent.Config) {
c.Region = "global"
c.Server.Enabled = false
@@ -104,16 +104,16 @@ func TestDebug_NodeClass(t *testing.T) {
c.Client.Servers = []string{srvRPCAddr}
}
// Start Client 1
// Start client 1
client1 := agent.NewTestAgent(t, "client1", agentConfFunc1)
defer client1.Shutdown()
// Wait for the client to connect
// Wait for client1 to connect
client1NodeID := client1.Agent.Client().NodeID()
testutil.WaitForClient(t, srv.Agent.RPC, client1NodeID)
t.Logf("[TEST] Client1 ready, id: %s", client1NodeID)
// Setup Client 2 (nodeclass = clientb)
// Setup client 2 (nodeclass = clientb)
agentConfFunc2 := func(c *agent.Config) {
c.Region = "global"
c.Server.Enabled = false
@@ -122,27 +122,27 @@ func TestDebug_NodeClass(t *testing.T) {
c.Client.Servers = []string{srvRPCAddr}
}
// Start Client 2
// Start client 2
client2 := agent.NewTestAgent(t, "client2", agentConfFunc2)
defer client2.Shutdown()
// Wait for the client to connect
// Wait for client2 to connect
client2NodeID := client2.Agent.Client().NodeID()
testutil.WaitForClient(t, srv.Agent.RPC, client2NodeID)
t.Logf("[TEST] Client2 ready, id: %s", client2NodeID)
// Setup Client 3 (nodeclass = clienta)
// Setup client 3 (nodeclass = clienta)
agentConfFunc3 := func(c *agent.Config) {
c.Server.Enabled = false
c.Client.NodeClass = "clienta"
c.Client.Servers = []string{srvRPCAddr}
}
// Start Client 3
// Start client 3
client3 := agent.NewTestAgent(t, "client3", agentConfFunc3)
defer client3.Shutdown()
// Wait for the client to connect
// Wait for client3 to connect
client3NodeID := client3.Agent.Client().NodeID()
testutil.WaitForClient(t, srv.Agent.RPC, client3NodeID)
t.Logf("[TEST] Client3 ready, id: %s", client3NodeID)
@@ -151,18 +151,58 @@ func TestDebug_NodeClass(t *testing.T) {
ui := cli.NewMockUi()
cmd := &OperatorDebugCommand{Meta: Meta{Ui: ui}}
// Debug on client - node class = "clienta"
code := cmd.Run([]string{"-address", url, "-duration", "250ms", "-server-id", "all", "-node-id", "all", "-node-class", "clienta", "-max-nodes", "2"})
// Setup test cases struct
cases := []struct {
name string
args []string
expectedCode int
expectedOutputs []string
expectedError string
}{
{
name: "address=api, node-class=clienta, max-nodes=2",
args: []string{"-address", url, "-duration", "250ms", "-server-id", "all", "-node-id", "all", "-node-class", "clienta", "-max-nodes", "2"},
expectedCode: 0,
expectedOutputs: []string{
"Starting debugger",
"Created debug archive",
"Max node count reached (2)",
"Node Class: clienta",
},
expectedError: "",
},
{
name: "address=api, node-class=clientb, max-nodes=2",
args: []string{"-address", url, "-duration", "250ms", "-server-id", "all", "-node-id", "all", "-node-class", "clientb", "-max-nodes", "2"},
expectedCode: 0,
expectedOutputs: []string{
"Starting debugger",
"Created debug archive",
"Node Class: clientb",
},
expectedError: "",
},
}
assert.Equal(t, 0, code)
require.Empty(t, ui.ErrorWriter.String(), "errorwriter should be empty")
require.Contains(t, ui.OutputWriter.String(), "Starting debugger")
require.Contains(t, ui.OutputWriter.String(), "Max node count reached (2)")
require.Contains(t, ui.OutputWriter.String(), "Node Class: clienta")
require.Contains(t, ui.OutputWriter.String(), "Created debug archive")
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
// Run test case
code := cmd.Run(c.args)
out := ui.OutputWriter.String()
outerr := ui.ErrorWriter.String()
ui.OutputWriter.Reset()
ui.ErrorWriter.Reset()
// Verify case expectations
require.Equalf(t, code, c.expectedCode, "expected exit code %d, got: %d: %s", c.expectedCode, code, outerr)
for _, expectedOutput := range c.expectedOutputs {
require.Contains(t, out, expectedOutput, "expected output \"%s\", got \"%s\"", expectedOutput, out)
}
require.Containsf(t, outerr, c.expectedError, "expected error \"%s\", got \"%s\"", c.expectedError, outerr)
// Reset buffers before next test
ui.OutputWriter.Reset()
ui.ErrorWriter.Reset()
})
}
}
func TestDebugFail_Pprof(t *testing.T) {
@@ -195,6 +235,87 @@ func TestDebugFail_Pprof(t *testing.T) {
ui.ErrorWriter.Reset()
}
func TestDebug_ClientToServer(t *testing.T) {
// Start test server and API client
srv, _, url := testServer(t, false, nil)
defer srv.Shutdown()
// Wait for leadership to establish
testutil.WaitForLeader(t, srv.Agent.RPC)
// Retrieve server RPC address to join client
srvRPCAddr := srv.GetConfig().AdvertiseAddrs.RPC
t.Logf("[TEST] Leader started, srv.GetConfig().AdvertiseAddrs.RPC: %s", srvRPCAddr)
// Setup client 1 (nodeclass = clienta)
agentConfFunc1 := func(c *agent.Config) {
c.Region = "global"
c.Server.Enabled = false
c.Client.NodeClass = "clienta"
c.Client.Enabled = true
c.Client.Servers = []string{srvRPCAddr}
}
// Start client 1
client1 := agent.NewTestAgent(t, "client1", agentConfFunc1)
defer client1.Shutdown()
// Wait for client 1 to connect
client1NodeID := client1.Agent.Client().NodeID()
testutil.WaitForClient(t, srv.Agent.RPC, client1NodeID)
t.Logf("[TEST] Client1 ready, id: %s", client1NodeID)
// Get API addresses
addrServer := srv.HTTPAddr()
addrClient1 := client1.HTTPAddr()
t.Logf("[TEST] testAgent api address: %s", url)
t.Logf("[TEST] Server api address: %s", addrServer)
t.Logf("[TEST] Client1 api address: %s", addrClient1)
// Setup mock UI
ui := cli.NewMockUi()
cmd := &OperatorDebugCommand{Meta: Meta{Ui: ui}}
// Setup test cases struct
cases := []struct {
name string
url string
}{
{
"testAgent api server",
url,
},
{
"server address",
addrServer,
},
{
"client1 address - verify no SIGSEGV panic",
addrClient1,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
// Run test case
code := cmd.Run([]string{"-address", c.url, "-duration", "250ms", "-server-id", "all", "-node-id", "all"})
out := ui.OutputWriter.String()
outerr := ui.ErrorWriter.String()
// Verify case expectations
assert.Equal(t, 0, code)
require.Empty(t, outerr, "errorwriter should be empty")
require.Contains(t, out, "Starting debugger")
require.Contains(t, out, "Created debug archive")
// Reset buffers before next test
ui.OutputWriter.Reset()
ui.ErrorWriter.Reset()
})
}
}
func TestDebugSuccesses(t *testing.T) {
srv, _, url := testServer(t, false, nil)
defer srv.Shutdown()