diff --git a/cmd/cluster_list.go b/cmd/cluster_list.go index a635c242d..5de599a1c 100644 --- a/cmd/cluster_list.go +++ b/cmd/cluster_list.go @@ -75,7 +75,7 @@ func (cmd *ClusterList) Execute(args []string) (err error) { clusters, err := client.ListClusters() if err != nil { - return err + return renderClientError(err, "failed to get your cluster list") } // TODO Add role (admin, team member ...) diff --git a/cmd/cluster_use.go b/cmd/cluster_use.go index 3ade2ab32..127cb4822 100644 --- a/cmd/cluster_use.go +++ b/cmd/cluster_use.go @@ -81,7 +81,8 @@ func (cmd *ClusterUse) Execute(args []string) (err error) { }) list, err := client.ListClusters() if err != nil { - return err + return renderClientError(err, "failed to list your clusters") + } var cluster *v1authpayload.GetClusterOutput @@ -89,12 +90,12 @@ func (cmd *ClusterUse) Execute(args []string) (err error) { if err != nil { cluster, err = lookByName(args[0], list.Clusters) if err != nil { - return err + return renderServiceError(err, "failed to find the specified cluster") } } cluster, err = client.GetCluster(cluster.URL) if err != nil { - return err + return renderClientError(err, "failed to get the specified cluster configuration") } if cluster == nil { cmd.out.Infof("Cluster not found. You can use `nerd cluster list` to see your clusters.") @@ -107,7 +108,7 @@ func (cmd *ClusterUse) Execute(args []string) (err error) { } p, err := populator.New("generic", kubeConfig, cluster) if err != nil { - return err + return renderConfigError(err, "failed to add configuration") } if cmd.Namespace == "" && len(cluster.Namespaces) >= 1 { cmd.Namespace = cluster.Namespaces[0].Name @@ -115,11 +116,11 @@ func (cmd *ClusterUse) Execute(args []string) (err error) { err = p.PopulateKubeConfig(cmd.Namespace) if err != nil { p.RemoveConfig(cluster.ShortName) - return err + return renderConfigError(err, "failed to remove configuration") } if err := checkNamespace(kubeConfig, cmd.Namespace); err != nil { p.RemoveConfig(cluster.ShortName) - return err + return renderConfigError(err, "failed to remove configuration") } if cluster.ServiceType != PublicCluster { @@ -131,14 +132,14 @@ func (cmd *ClusterUse) Execute(args []string) (err error) { ok, nerdDependencies, err := kube.IsNerdCompliant(ctx) if err != nil { - return err + return renderServiceError(err, "failed to check if cluster is nerd compliant") } if !ok { cmd.out.Info("Cluster is not nerd compliant, nerdalizing cluster...") // TODO move this to a new command err = kube.AddNerdDependencies(ctx, &svc.AddNerdDependenciesInput{Dependencies: nerdDependencies}) if err != nil { - return err + return renderServiceError(err, "failed to nerdalize cluster") } cmd.out.Info("Cluster is now nerdalized. It can take a few minutes before you can use it.") } diff --git a/cmd/errors.go b/cmd/errors.go index 9a49b21a3..13549bcfc 100644 --- a/cmd/errors.go +++ b/cmd/errors.go @@ -3,6 +3,8 @@ package cmd import ( "context" "fmt" + "net" + "net/url" "strings" "github.com/nerdalize/nerd/pkg/kubevisor" @@ -36,6 +38,15 @@ func renderServiceError(err error, format string, args ...interface{}) error { return nil } + switch err := err.(type) { + case net.Error: + return errors.Errorf("%s: please check your internet connection, and try again.", fmt.Errorf(format, args...)) + case *url.Error: + if err, ok := err.Err.(net.Error); ok && err.Timeout() { + return errors.Errorf("%s:please check your internet connection, and try again.", fmt.Errorf(format, args...)) + } + } + err = errors.Cause(err) if err == context.Canceled { return errors.Errorf("%s: process was canceled", fmt.Errorf(format, args...)) @@ -89,3 +100,23 @@ func renderConfigError(err error, format string, args ...interface{}) error { return err } } + +func renderClientError(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + + err = errors.Cause(err) + switch err := err.(type) { + case net.Error: + return errors.Errorf("%s: please check your internet connection, and try again.", fmt.Errorf(format, args...)) + case *url.Error: + if err, ok := err.Err.(net.Error); ok && err.Timeout() { + return errors.Errorf("%s:please check your internet connection, and try again.", fmt.Errorf(format, args...)) + } + default: + return err + } + + return err +} diff --git a/cmd/login.go b/cmd/login.go index 4d58c9f7c..e4e4d8de0 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -98,10 +98,14 @@ func (cmd *Login) Execute(args []string) (err error) { Base: authbase, Logger: cmd.Logger(), OAuthTokenProvider: oauth.NewConfigProvider(authOpsClient, cmd.config.Auth.SecureClientID, cmd.config.Auth.SecureClientSecret, cmd.session), + Doer: &http.Client{ + Timeout: time.Second * 30, + }, }) + cmd.out.Info("Setting up your local configuration...") list, err := client.ListClusters() if err != nil { - return renderServiceError(err, "cannot list clusters") + return renderClientError(err, "failed to list your clusters") } if len(list.Clusters) == 0 { @@ -112,7 +116,7 @@ func (cmd *Login) Execute(args []string) (err error) { for _, cluster := range list.Clusters { cluster, err = client.GetCluster(cluster.URL) if err != nil { - return err + return renderClientError(err, "failed to get the specified cluster configuration") } err = setCluster(cmd.globalOpts.KubeOpts.KubeConfig, cluster) if err != nil { diff --git a/nerd/client/auth/v1/client.go b/nerd/client/auth/v1/client.go index b025f19a7..aed7b9ae9 100644 --- a/nerd/client/auth/v1/client.go +++ b/nerd/client/auth/v1/client.go @@ -9,6 +9,7 @@ import ( "net/url" "os" "sync" + "time" "github.com/nerdalize/nerd/nerd/client" v1payload "github.com/nerdalize/nerd/nerd/client/auth/v1/payload" @@ -48,13 +49,15 @@ type Doer interface { //NewClient creates a new Auth. func NewClient(c ClientConfig) *Client { if c.Doer == nil { - c.Doer = http.DefaultClient - if os.Getenv("NERD_ENV") == "dev" { - c.Doer = &http.Client{Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - }} + c.Doer = &http.Client{ + Timeout: time.Second * 10, } } + if os.Getenv("NERD_ENV") == "dev" { + c.Doer = &http.Client{Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }} + } if c.Base.Path != "" && c.Base.Path[len(c.Base.Path)-1] != '/' { c.Base.Path = c.Base.Path + "/" } diff --git a/svc/kube_nerd_compliant.go b/svc/kube_nerd_compliant.go index 13a8b6583..bdb08f927 100644 --- a/svc/kube_nerd_compliant.go +++ b/svc/kube_nerd_compliant.go @@ -5,6 +5,7 @@ import ( "fmt" "io/ioutil" "net/http" + "time" "github.com/nerdalize/nerd/pkg/kubevisor" appsv1 "k8s.io/api/apps/v1" @@ -36,8 +37,11 @@ type AddNerdDependenciesInput struct { // IsNerdCompliant checks if the nlz-utils are running on the current cluster func (k *Kube) IsNerdCompliant(ctx context.Context) (ok bool, dependencies []string, err error) { + var netClient = &http.Client{ + Timeout: time.Second * 10, + } for resource, url := range files { - resp, err := http.Get(url) + resp, err := netClient.Get(url) if err != nil { return false, nil, err } @@ -92,9 +96,12 @@ func (k *Kube) IsNerdCompliant(ctx context.Context) (ok bool, dependencies []str // AddNerdDependencies will deploy necessary daemonsets, controllers and roles so that a private cluster can be used by the cli func (k *Kube) AddNerdDependencies(ctx context.Context, in *AddNerdDependenciesInput) (err error) { + var netClient = &http.Client{ + Timeout: time.Second * 10, + } for _, dependency := range in.Dependencies { // Get the data - resp, err := http.Get(files[dependency]) + resp, err := netClient.Get(files[dependency]) if err != nil { return err }