diff --git a/tsuru/http/client.go b/tsuru/http/client.go index 94b914ab..175dddab 100644 --- a/tsuru/http/client.go +++ b/tsuru/http/client.go @@ -69,12 +69,26 @@ func TsuruClientFromEnvironment() (*tsuru.APIClient, error) { return cli, nil } +type errWrapped interface { + Unwrap() error +} + +type errCauser interface { + Cause() error +} + func UnwrapErr(err error) error { - if err == nil { - return nil - } - if urlErr, ok := err.(*url.Error); ok { - return urlErr.Err + for err != nil { + if cause, ok := err.(errCauser); ok { + err = cause.Cause() + } else if u, ok := err.(errWrapped); ok { + err = u.Unwrap() + } else if urlErr, ok := err.(*url.Error); ok { + err = urlErr.Err + } else { + break + } } + return err } diff --git a/tsuru/http/transport.go b/tsuru/http/transport.go index fc03fc7f..ded69904 100644 --- a/tsuru/http/transport.go +++ b/tsuru/http/transport.go @@ -140,7 +140,7 @@ func detectClientError(err error) error { case x509.UnknownAuthorityError: return errors.Wrapf(e, "Failed to connect to tsuru server (%s)", target) } - return errors.Errorf("Failed to connect to tsuru server (%s), it's probably down, internal err: %q", target, e.Error()) + return errors.Wrapf(e, "Failed to connect to tsuru server (%s), it's probably down", target) } if urlErr, ok := err.(*url.Error); ok { diff --git a/tsuru/main.go b/tsuru/main.go index b9d806d6..198ac307 100644 --- a/tsuru/main.go +++ b/tsuru/main.go @@ -229,8 +229,20 @@ Services aren’t managed by tsuru, but by their creators.`) m.Register(&client.ServiceInstanceInfo{}) registerExtraCommands(m) m.RetryHook = func(err error) (retry bool) { + mustLogin := false + err = tsuruHTTP.UnwrapErr(err) - if httpErr, ok := err.(*tsuruErrors.HTTP); ok && httpErr.StatusCode() == http.StatusUnauthorized { + + if oauth2Err, ok := err.(*oauth2.RetrieveError); ok { + fmt.Fprintf(os.Stderr, "oauth2 error: %s, %s\n", oauth2Err.ErrorCode, oauth2Err.ErrorDescription) + mustLogin = true + } else if httpErr, ok := err.(*tsuruErrors.HTTP); ok && httpErr.StatusCode() == http.StatusUnauthorized { + fmt.Fprintf(os.Stderr, "http error: %d\n", httpErr.StatusCode()) + mustLogin = true + } + + if mustLogin { + fmt.Fprintln(os.Stderr, "trying to login again") c := &auth.Login{} loginErr := c.Run(&cmd.Context{ Stderr: stderr, @@ -238,6 +250,7 @@ Services aren’t managed by tsuru, but by their creators.`) }) if loginErr == nil { + initAuthorization() // re-init updated token provider return true } } @@ -271,6 +284,14 @@ func main() { name := cmd.ExtractProgramName(os.Args[0]) + initAuthorization() + + m := buildManager(name) + m.Run(os.Args[1:]) +} + +func initAuthorization() { + name := cmd.ExtractProgramName(os.Args[0]) roundTripper, tokenProvider := roundTripperAndTokenProvider() tsuruHTTP.AuthenticatedClient = tsuruHTTP.NewTerminalClient(tsuruHTTP.TerminalClientOptions{ @@ -281,9 +302,6 @@ func main() { Stderr: os.Stderr, }) config.DefaultTokenProvider = tokenProvider - - m := buildManager(name) - m.Run(os.Args[1:]) } func roundTripperAndTokenProvider() (http.RoundTripper, config.TokenProvider) {