1
0
Fork 0

Merge pull request #1086 from rqlite/restore-follow-body

Restoring via follower should have same response
master
Philip O'Toole 2 years ago committed by GitHub
commit f2bd5af766
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,3 +1,7 @@
## 7.9.1 (unreleased)
### Implementation changes and bug fixes
- [PR #1086](https://github.com/rqlite/rqlite/pull/1086): Restoring via follower should have same HTTP response body.
## 7.9.0 (October 22nd 2022) ## 7.9.0 (October 22nd 2022)
This release makes it more convenient to load SQLite files directly into rqlite, as any node can now process the request. For this to work however, all nodes in your cluster must be running 7.9.0 (or later). Otherwse 7.9.0 is fully compatible with earlier release, so a rolling upgrade process is an option. This release makes it more convenient to load SQLite files directly into rqlite, as any node can now process the request. For this to work however, all nodes in your cluster must be running 7.9.0 (or later). Otherwse 7.9.0 is fully compatible with earlier release, so a rolling upgrade process is an option.

@ -693,50 +693,49 @@ func (s *Service) handleLoad(w http.ResponseWriter, r *http.Request) {
Data: b, Data: b,
} }
err := s.store.Load(lr) err := s.store.Load(lr)
if err != nil { if err != nil && err != store.ErrNotLeader {
if err == store.ErrNotLeader { http.Error(w, err.Error(), http.StatusInternalServerError)
if redirect { return
leaderAPIAddr := s.LeaderAPIAddr() } else if err != nil && err == store.ErrNotLeader {
if leaderAPIAddr == "" { if redirect {
stats.Add(numLeaderNotFound, 1) leaderAPIAddr := s.LeaderAPIAddr()
http.Error(w, ErrLeaderNotFound.Error(), http.StatusServiceUnavailable) if leaderAPIAddr == "" {
return
}
redirect := s.FormRedirect(r, leaderAPIAddr)
http.Redirect(w, r, redirect, http.StatusMovedPermanently)
return
}
addr, err := s.store.LeaderAddr()
if err != nil {
http.Error(w, fmt.Sprintf("leader address: %s", err.Error()),
http.StatusInternalServerError)
return
}
if addr == "" {
stats.Add(numLeaderNotFound, 1) stats.Add(numLeaderNotFound, 1)
http.Error(w, ErrLeaderNotFound.Error(), http.StatusServiceUnavailable) http.Error(w, ErrLeaderNotFound.Error(), http.StatusServiceUnavailable)
return return
} }
username, password, ok := r.BasicAuth() redirect := s.FormRedirect(r, leaderAPIAddr)
if !ok { http.Redirect(w, r, redirect, http.StatusMovedPermanently)
username = "" return
} }
loadErr := s.cluster.Load(lr, addr, makeCredentials(username, password), timeout) addr, err := s.store.LeaderAddr()
if loadErr != nil && loadErr.Error() == "unauthorized" { if err != nil {
http.Error(w, "remote load not authorized", http.StatusUnauthorized) http.Error(w, fmt.Sprintf("leader address: %s", err.Error()),
return http.StatusInternalServerError)
} return
stats.Add(numRemoteLoads, 1) }
w.Header().Add(ServedByHTTPHeader, addr) if addr == "" {
stats.Add(numLeaderNotFound, 1)
http.Error(w, ErrLeaderNotFound.Error(), http.StatusServiceUnavailable)
return return
} }
http.Error(w, err.Error(), http.StatusBadRequest) username, password, ok := r.BasicAuth()
return if !ok {
username = ""
}
loadErr := s.cluster.Load(lr, addr, makeCredentials(username, password), timeout)
if loadErr != nil && loadErr.Error() == "unauthorized" {
http.Error(w, "remote load not authorized", http.StatusUnauthorized)
return
}
stats.Add(numRemoteLoads, 1)
w.Header().Add(ServedByHTTPHeader, addr)
// Allow this if block to exit, so response remains as before request
// forwarding was put in place.
} }
} else { } else {
// No JSON structure expected for this API. // No JSON structure expected for this API.

@ -708,6 +708,13 @@ func Test_LoadOK(t *testing.T) {
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
t.Fatalf("failed to get expected StatusOK for load, got %d", resp.StatusCode) t.Fatalf("failed to get expected StatusOK for load, got %d", resp.StatusCode)
} }
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatalf("failed to read response body: %s", err.Error())
}
if exp, got := `{"results":[]}`, string(body); exp != got {
t.Fatalf("incorrect response body, exp: %s, got %s", exp, got)
}
} }
func Test_LoadFlagsNoLeader(t *testing.T) { func Test_LoadFlagsNoLeader(t *testing.T) {
@ -749,6 +756,7 @@ func Test_LoadFlagsNoLeader(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to make load request") t.Fatalf("failed to make load request")
} }
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
t.Fatalf("failed to get expected StatusOK for load, got %d", resp.StatusCode) t.Fatalf("failed to get expected StatusOK for load, got %d", resp.StatusCode)
} }
@ -756,6 +764,14 @@ func Test_LoadFlagsNoLeader(t *testing.T) {
if !clusterLoadCalled { if !clusterLoadCalled {
t.Fatalf("cluster load was not called") t.Fatalf("cluster load was not called")
} }
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatalf("failed to read response body: %s", err.Error())
}
if exp, got := `{"results":[]}`, string(body); exp != got {
t.Fatalf("incorrect response body, exp: %s, got %s", exp, got)
}
} }
func Test_RegisterStatus(t *testing.T) { func Test_RegisterStatus(t *testing.T) {

Loading…
Cancel
Save