Skip to content

Commit

Permalink
roachtest: teach cluster-init to reproduce startup crash
Browse files Browse the repository at this point in the history
Teach the cluster-init test to reproduce the crash during bootup
described in issue cockroachdb#25771. The trick is to send requests with a session
cookie, as the admin UI would, while the cluster is waiting for init.

Note that the crash was caused by the authenticationMux, which is used
to protect secure clusters, but this test uses an insecure cluster. This
is relying on a wart: an authenticationMux is installed for UI assets
whether or not the cluster is secure. This could change in the future. A
better test would use a secure cluster, however roachprod/roachtest do
not easily support that at this time, nor is it easy to write a unit
test that exercises the crash more robustly.

Release note: None
  • Loading branch information
benesch authored and Pete Vilter committed Oct 1, 2018
1 parent b351cf5 commit 857ba8b
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 13 deletions.
41 changes: 32 additions & 9 deletions pkg/cmd/roachtest/cluster_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"strings"
"time"

"github.com/cockroachdb/cockroach/pkg/server"
"github.com/cockroachdb/cockroach/pkg/server/serverpb"
"github.com/cockroachdb/cockroach/pkg/util/retry"
"golang.org/x/sync/errgroup"
)
Expand Down Expand Up @@ -143,16 +145,37 @@ func runClusterInit(ctx context.Context, t *test, c *cluster) {
{"/_status/nodes", http.StatusNotFound},
}
for _, tc := range httpTests {
resp, err := http.Get(urlMap[1] + tc.endpoint)
if err != nil {
t.Fatalf("unexpected error hitting %s endpoint: %v", tc.endpoint, err)
}
defer resp.Body.Close()
if resp.StatusCode != tc.expectedStatus {
bodyBytes, _ := ioutil.ReadAll(resp.Body)
t.Fatalf("unexpected response code %d (expected %d) hitting %s endpoint: %v",
resp.StatusCode, tc.expectedStatus, tc.endpoint, string(bodyBytes))
for _, withCookie := range []bool{false, true} {
req, err := http.NewRequest("GET", urlMap[1]+tc.endpoint, nil /* body */)
if err != nil {
t.Fatalf("unexpected error while constructing request for %s: %s", tc.endpoint, err)
}
if withCookie {
// Prevent regression of #25771 by also sending authenticated
// requests, like would be sent if an admin UI were open against
// this node while it booted.
cookie, err := server.EncodeSessionCookie(&serverpb.SessionCookie{
// The actual contents of the cookie don't matter; the presence of
// a valid encoded cookie is enough to trigger the authentication
// code paths.
})
if err != nil {
t.Fatal(err)
}
req.AddCookie(cookie)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatalf("unexpected error hitting %s endpoint: %v", tc.endpoint, err)
}
defer resp.Body.Close()
if resp.StatusCode != tc.expectedStatus {
bodyBytes, _ := ioutil.ReadAll(resp.Body)
t.Fatalf("unexpected response code %d (expected %d) hitting %s endpoint: %v",
resp.StatusCode, tc.expectedStatus, tc.endpoint, string(bodyBytes))
}
}

}

c.Run(ctx, c.Node(initNode),
Expand Down
5 changes: 3 additions & 2 deletions pkg/server/authentication.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func (s *authenticationServer) UserLogin(
ID: id,
Secret: secret,
}
cookie, err := encodeSessionCookie(cookieValue)
cookie, err := EncodeSessionCookie(cookieValue)
if err != nil {
return nil, apiInternalError(ctx, err)
}
Expand Down Expand Up @@ -369,7 +369,8 @@ func (am *authenticationMux) ServeHTTP(w http.ResponseWriter, req *http.Request)
am.inner.ServeHTTP(w, req)
}

func encodeSessionCookie(sessionCookie *serverpb.SessionCookie) (*http.Cookie, error) {
// EncodeSessionCookie encodes a SessionCookie proto into an http.Cookie.
func EncodeSessionCookie(sessionCookie *serverpb.SessionCookie) (*http.Cookie, error) {
cookieValueBytes, err := protoutil.Marshal(sessionCookie)
if err != nil {
return nil, errors.Wrap(err, "session cookie could not be encoded")
Expand Down
2 changes: 1 addition & 1 deletion pkg/server/authentication_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ func TestLogout(t *testing.T) {
if err != nil {
t.Fatal(err)
}
encodedCookie, err := encodeSessionCookie(cookie)
encodedCookie, err := EncodeSessionCookie(cookie)
if err != nil {
t.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/server/testserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ func (ts *TestServer) getAuthenticatedHTTPClientAndCookie() (
Secret: secret,
}
// Encode a session cookie and store it in a cookie jar.
cookie, err := encodeSessionCookie(rawCookie)
cookie, err := EncodeSessionCookie(rawCookie)
if err != nil {
return err
}
Expand Down

0 comments on commit 857ba8b

Please sign in to comment.