cmd/transfer: recovery and retries for http requests

This commit is contained in:
nicksherron 2020-02-12 00:50:21 -05:00
parent 3d026eb239
commit b5381b2eab
2 changed files with 69 additions and 43 deletions

View file

@ -36,7 +36,7 @@ $ GO111MODULE=on go get -u github.com/nicksherron/bashhub-server
``` ```
#### Releases #### Releases
Binaries for various os and architectures can be found in [releases](https://github.com/nicksherron/bashhub-server/releases). Binaries for various os and architectures can be found in [releases](https://github.com/nicksherron/bashhub-server/releases).
If your system is not listed just submit a issue requesting your os and architecture. If your system is not listed just submit an issue requesting your os and architecture.
## Usage ## Usage
``` ```
@ -48,6 +48,7 @@ Usage:
Available Commands: Available Commands:
help Help about any command help Help about any command
transfer Transfer bashhub history from one server to another
version Print the version number and build info version Print the version number and build info
Flags: Flags:

View file

@ -26,7 +26,6 @@ import (
"log" "log"
"net/http" "net/http"
"os" "os"
"os/exec"
"strings" "strings"
"sync" "sync"
@ -43,7 +42,7 @@ type cList struct {
type commandsList []cList type commandsList []cList
var ( var (
barTemplate = `{{string . "message"}}{{counters . }} {{bar . }} {{percent . }} {{speed . "%s inserts/sec" }}` barTemplate = `{{string . "message" | green }}{{counters . }} {{bar . }} {{percent . }} {{speed . "%s inserts/sec" | green}}`
bar *pb.ProgressBar bar *pb.ProgressBar
progress bool progress bool
srcUser string srcUser string
@ -60,9 +59,29 @@ var (
cmdList commandsList cmdList commandsList
transferCmd = &cobra.Command{ transferCmd = &cobra.Command{
Use: "transfer", Use: "transfer",
Short: "transfer bashhub history ", Short: "Transfer bashhub history from one server to another",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmd.Flags().Parse(args) cmd.Flags().Parse(args)
switch {
case srcUser == "":
_ = cmd.Usage()
fmt.Print("\n\n")
log.Fatal("--src-user can't be blank")
case srcPass == "":
_ = cmd.Usage()
fmt.Print("\n\n")
log.Fatal("--src-pass can't be blank")
case dstUser == "":
_ = cmd.Usage()
fmt.Print("\n\n")
log.Fatal("--dst-user can't be blank")
case dstPass == "":
_ = cmd.Usage()
fmt.Print("\n\n")
log.Fatal("--dst-pass can't be blank")
}
if workers > 10 && srcURL == "https://bashhub.com" { if workers > 10 && srcURL == "https://bashhub.com" {
msg := fmt.Sprintf(` msg := fmt.Sprintf(`
WARNING: errors are likely to occur when setting workers higher WARNING: errors are likely to occur when setting workers higher
@ -78,16 +97,15 @@ var (
counter := 0 counter := 0
if !progress { if !progress {
bar = pb.ProgressBarTemplate(barTemplate).Start(len(cmdList)).SetMaxWidth(70) bar = pb.ProgressBarTemplate(barTemplate).Start(len(cmdList)).SetMaxWidth(70)
bar.Set("message", "inserting records \t") bar.Set("message", "transferring ")
} }
client := &http.Client{} client := &http.Client{}
// ignore http errors. We try and recover them
log.SetOutput(nil)
for _, v := range cmdList { for _, v := range cmdList {
wg.Add(1) wg.Add(1)
counter++ counter++
go func(c cList) { go commandLookup(v.UUID, client, 0)
defer wg.Done()
commandLookup(c.UUID, client)
}(v)
if counter > workers { if counter > workers {
wg.Wait() wg.Wait()
counter = 0 counter = 0
@ -164,7 +182,7 @@ func sysRegister(mac string, site string, user string, pass string) string {
} }
sys := map[string]interface{}{ sys := map[string]interface{}{
"clientVersion": "1.2.0", "clientVersion": "1.2.0",
"name": "migration", "name": "transfer",
"hostname": host, "hostname": host,
"mac": mac, "mac": mac,
} }
@ -189,26 +207,13 @@ func sysRegister(mac string, site string, user string, pass string) string {
} }
defer resp.Body.Close() defer resp.Body.Close()
log.Println(resp.StatusCode)
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
log.Println(string(b))
sysRegistered = true sysRegistered = true
return getToken(site, user, pass) return getToken(site, user, pass)
} }
func getToken(site string, user string, pass string) string { func getToken(site string, user string, pass string) string {
// function used by bashhub to identify system mac := "888888888888888"
cmd := exec.Command("python", "-c", "import uuid; print(str(uuid.getnode()))")
m, err := cmd.Output()
if err != nil {
log.Fatal(err)
}
mac := strings.ReplaceAll(string(m), "\n", ``)
auth := map[string]interface{}{ auth := map[string]interface{}{
"username": user, "username": user,
"password": pass, "password": pass,
@ -267,7 +272,7 @@ func getCommandList() commandsList {
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
log.Println("Error on response.\n", err) log.Fatal("Error on response.\n", err)
} }
defer resp.Body.Close() defer resp.Body.Close()
@ -279,40 +284,55 @@ func getCommandList() commandsList {
log.Fatal(err) log.Fatal(err)
} }
var result commandsList var result commandsList
json.Unmarshal(body, &result) err = json.Unmarshal(body, &result)
return result
}
func commandLookup(uuid string, client *http.Client) {
u := strings.TrimSpace(srcURL) + "/api/v1/command/" + strings.TrimSpace(uuid)
req, err := http.NewRequest("GET", u, nil)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
return result
}
func commandLookup(uuid string, client *http.Client, retries int) {
defer func() {
if r := recover(); r != nil {
mem := strings.Contains(fmt.Sprintf("%v", r), "runtime error: invalid memory address")
eof := strings.Contains(fmt.Sprintf("%v", r), "EOF")
if mem || eof {
if retries < 10 {
retries++
commandLookup(uuid, client, retries)
} else {
log.SetOutput(os.Stderr)
log.Println("ERROR: failed over 10 times looking up command from source with uuid: ", uuid)
log.SetOutput(nil)
}
} else {
log.SetOutput(os.Stderr)
log.Fatal(r)
}
}
}()
u := strings.TrimSpace(srcURL) + "/api/v1/command/" + strings.TrimSpace(uuid)
req, err := http.NewRequest("GET", u, nil)
if err != nil {
panic(err)
}
req.Header.Add("Authorization", srcToken) req.Header.Add("Authorization", srcToken)
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
log.Println("Error on response.\n", err) panic(err)
} }
//defer func() {
// err = resp.Body.Close()
// if err != nil {
// log.Println(err)
// }
//
//}()
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
log.Fatalf("failed command lookup from %v, go status code %v", srcURL, resp.StatusCode) log.Fatalf("failed command lookup from %v, go status code %v", srcURL, resp.StatusCode)
} }
body, err := ioutil.ReadAll(resp.Body) body, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
log.Fatal(err) panic(err)
} }
srcSend(body, client) srcSend(body, client)
} }
@ -322,19 +342,24 @@ func srcSend(data []byte, client *http.Client) {
if !progress { if !progress {
bar.Add(1) bar.Add(1)
} }
wg.Done()
}() }()
body := bytes.NewReader(data) body := bytes.NewReader(data)
u := dstURL + "/api/v1/import" u := dstURL + "/api/v1/import"
req, err := http.NewRequest("POST", u, body) req, err := http.NewRequest("POST", u, body)
if err != nil { if err != nil {
log.SetOutput(os.Stderr)
log.Fatal(err) log.Fatal(err)
} }
req.Header.Add("Authorization", dstToken) req.Header.Add("Authorization", dstToken)
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
log.SetOutput(os.Stderr)
log.Println("Error on response.\n", err) log.Println("Error on response.\n", err)
log.SetOutput(nil)
} }
defer resp.Body.Close() defer resp.Body.Close()