From 6ba6b9ae197537049693e714d6d098176832c47d Mon Sep 17 00:00:00 2001 From: Andrew Burke Date: Tue, 4 Jun 2024 15:43:51 -0700 Subject: [PATCH] Handle *url.Error + improve logging --- lib/cloud/gcp/vm.go | 16 ++++++++++++++++ lib/cloud/gcp/vm_test.go | 13 ++++++++++++- lib/service/service.go | 12 ++++++++---- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/lib/cloud/gcp/vm.go b/lib/cloud/gcp/vm.go index 2539c00bedfb2..2ce122208f0b9 100644 --- a/lib/cloud/gcp/vm.go +++ b/lib/cloud/gcp/vm.go @@ -26,7 +26,10 @@ import ( "fmt" "io" "net" + "net/url" + "regexp" "slices" + "strconv" "strings" "time" @@ -55,6 +58,10 @@ const sshUser = "teleport" // sshDefaultTimeout is the default timeout for dialing an instance. const sshDefaultTimeout = 10 * time.Second +// urlErrorCodePattern is a regex for attempting to extract an HTTP error +// code from a *url.Error. +var urlErrorCodePattern = regexp.MustCompile(`\b[2-5]\d{2}\b`) + // convertAPIError converts an error from the GCP API into a trace error. func convertAPIError(err error) error { var googleError *googleapi.Error @@ -69,6 +76,15 @@ func convertAPIError(err error) error { return trail.FromGRPC(apiError) } } + var urlError *url.Error + if errors.As(err, &urlError) { + if codeStr := urlErrorCodePattern.FindString(urlError.Error()); codeStr != "" { + code, err := strconv.Atoi(codeStr) + if err == nil { + return trace.ReadError(code, []byte(urlError.Error())) + } + } + } return err } diff --git a/lib/cloud/gcp/vm_test.go b/lib/cloud/gcp/vm_test.go index 77cc248f84ba7..daab9f81f34eb 100644 --- a/lib/cloud/gcp/vm_test.go +++ b/lib/cloud/gcp/vm_test.go @@ -21,8 +21,10 @@ package gcp import ( "bytes" "context" + "fmt" "net" "net/http" + "net/url" "sync/atomic" "testing" "time" @@ -70,10 +72,19 @@ func TestConvertAPIError(t *testing.T) { name: "api grpc error", err: fromError(t, status.Error(codes.PermissionDenied, "abcd1234")), }, + { + name: "url error", + err: &url.Error{ + Op: http.MethodGet, + URL: "https://example.com", + Err: fmt.Errorf("wrong code 99, wrong code 2007, wrong code 678, right code 403, wrong code 401 abcd1234"), + }, + }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - require.True(t, trace.IsAccessDenied(convertAPIError(tc.err))) + err := convertAPIError(tc.err) + require.True(t, trace.IsAccessDenied(err), "unexpected error of type %T: %v", tc.err, err) require.Contains(t, tc.err.Error(), "abcd1234") }) } diff --git a/lib/service/service.go b/lib/service/service.go index 69eaf1452a1a4..56ec72cf29fdc 100644 --- a/lib/service/service.go +++ b/lib/service/service.go @@ -967,8 +967,12 @@ func NewTeleport(cfg *servicecfg.Config) (*TeleportProcess, error) { imClient := cfg.InstanceMetadataClient if imClient == nil { imClient, err = cloud.DiscoverInstanceMetadata(supervisor.ExitContext()) - if err != nil && !trace.IsNotFound(err) { - return nil, trace.Wrap(err) + if err == nil { + cfg.Logger.InfoContext(supervisor.ExitContext(), + "Found an instance metadata service. Teleport will import labels from this cloud instance.", + "type", imClient.GetType()) + } else if !trace.IsNotFound(err) { + cfg.Logger.ErrorContext(supervisor.ExitContext(), "Error looking for cloud instance metadata.", "error", err) } } @@ -985,7 +989,7 @@ func NewTeleport(cfg *servicecfg.Config) (*TeleportProcess, error) { cfg.Logger.InfoContext(supervisor.ExitContext(), "Found invalid hostname in cloud tag TeleportHostname.", "hostname", cloudHostname) } } else if !trace.IsNotFound(err) { - return nil, trace.Wrap(err) + cfg.Logger.ErrorContext(supervisor.ExitContext(), "Error looking for hostname tag.", "error", err) } cloudLabels, err = labels.NewCloudImporter(supervisor.ExitContext(), &labels.CloudConfig{ @@ -993,7 +997,7 @@ func NewTeleport(cfg *servicecfg.Config) (*TeleportProcess, error) { Clock: cfg.Clock, }) if err != nil { - return nil, trace.Wrap(err) + cfg.Logger.ErrorContext(supervisor.ExitContext(), "Error creating cloud label importer.", "error", err) } }