1
0
Fork 0

rqlite CLI backs up and dumps using streaming

master
Philip O'Toole 9 months ago
parent c1cd29e163
commit 585feb473f

@ -45,12 +45,14 @@ func backup(ctx *cli.Context, filename string, argv *argT) error {
Path: fmt.Sprintf("%sdb/backup", argv.Prefix), Path: fmt.Sprintf("%sdb/backup", argv.Prefix),
RawQuery: queryStr.Encode(), RawQuery: queryStr.Encode(),
} }
response, err := sendRequest(ctx, makeBackupRequest, u.String(), argv)
fd, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil { if err != nil {
return err return err
} }
defer fd.Close()
err = os.WriteFile(filename, *response, 0644) _, err = sendRequestW(ctx, makeBackupRequest, u.String(), argv, fd)
if err != nil { if err != nil {
return err return err
} }
@ -68,12 +70,14 @@ func dump(ctx *cli.Context, filename string, argv *argT) error {
Path: fmt.Sprintf("%sdb/backup", argv.Prefix), Path: fmt.Sprintf("%sdb/backup", argv.Prefix),
RawQuery: queryStr.Encode(), RawQuery: queryStr.Encode(),
} }
response, err := sendRequest(ctx, makeBackupRequest, u.String(), argv)
fd, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil { if err != nil {
return err return err
} }
defer fd.Close()
err = os.WriteFile(filename, *response, 0644) _, err = sendRequestW(ctx, makeBackupRequest, u.String(), argv, fd)
if err != nil { if err != nil {
return err return err
} }

@ -2,6 +2,7 @@
package main package main
import ( import (
"bytes"
"crypto/tls" "crypto/tls"
"encoding/json" "encoding/json"
"errors" "errors"
@ -458,10 +459,21 @@ func getVersionWithClient(client *http.Client, argv *argT) (string, error) {
} }
func sendRequest(ctx *cli.Context, makeNewRequest func(string) (*http.Request, error), urlStr string, argv *argT) (*[]byte, error) { func sendRequest(ctx *cli.Context, makeNewRequest func(string) (*http.Request, error), urlStr string, argv *argT) (*[]byte, error) {
// create a byte-based buffer that implments io.Writer
var buf []byte
w := bytes.NewBuffer(buf)
_, err := sendRequestW(ctx, makeNewRequest, urlStr, argv, w)
if err != nil {
return nil, err
}
return &buf, nil
}
func sendRequestW(ctx *cli.Context, makeNewRequest func(string) (*http.Request, error), urlStr string, argv *argT, w io.Writer) (int64, error) {
url := urlStr url := urlStr
tlsConfig, err := rtls.CreateClientConfig(argv.ClientCert, argv.ClientKey, argv.CACert, rtls.NoServerName, argv.Insecure) tlsConfig, err := rtls.CreateClientConfig(argv.ClientCert, argv.ClientKey, argv.CACert, rtls.NoServerName, argv.Insecure)
if err != nil { if err != nil {
return nil, err return 0, err
} }
tlsConfig.NextProtos = nil // CLI refuses to connect otherwise. tlsConfig.NextProtos = nil // CLI refuses to connect otherwise.
client := http.Client{Transport: &http.Transport{ client := http.Client{Transport: &http.Transport{
@ -478,45 +490,46 @@ func sendRequest(ctx *cli.Context, makeNewRequest func(string) (*http.Request, e
for { for {
req, err := makeNewRequest(url) req, err := makeNewRequest(url)
if err != nil { if err != nil {
return nil, err return 0, err
} }
if argv.Credentials != "" { if argv.Credentials != "" {
creds := strings.Split(argv.Credentials, ":") creds := strings.Split(argv.Credentials, ":")
if len(creds) != 2 { if len(creds) != 2 {
return nil, fmt.Errorf("invalid Basic Auth credentials format") return 0, fmt.Errorf("invalid Basic Auth credentials format")
} }
req.SetBasicAuth(creds[0], creds[1]) req.SetBasicAuth(creds[0], creds[1])
} }
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
return nil, err return 0, err
} }
response, err := io.ReadAll(resp.Body)
n, err := io.Copy(w, resp.Body)
if err != nil { if err != nil {
return nil, err return n, err
} }
resp.Body.Close() resp.Body.Close()
if resp.StatusCode == http.StatusUnauthorized { if resp.StatusCode == http.StatusUnauthorized {
return nil, fmt.Errorf("unauthorized") return 0, fmt.Errorf("unauthorized")
} }
if resp.StatusCode == http.StatusMovedPermanently { if resp.StatusCode == http.StatusMovedPermanently {
nRedirect++ nRedirect++
if nRedirect > maxRedirect { if nRedirect > maxRedirect {
return nil, fmt.Errorf("maximum leader redirect limit exceeded") return 0, fmt.Errorf("maximum leader redirect limit exceeded")
} }
url = resp.Header["Location"][0] url = resp.Header["Location"][0]
continue continue
} }
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("server responded with: %s", resp.Status) return 0, fmt.Errorf("server responded with: %s", resp.Status)
} }
return &response, nil return n, nil
} }
} }

Loading…
Cancel
Save