Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/cloud/gcp/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ func TestConvertAPIError(t *testing.T) {
}
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")
})
}
Expand Down
24 changes: 17 additions & 7 deletions lib/cloud/imds/gcp/imds.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,22 @@ func NewInstanceMetadataClient(ctx context.Context) (*InstanceMetadataClient, er

// IsAvailable checks if instance metadata is available.
func (client *InstanceMetadataClient) IsAvailable(ctx context.Context) bool {
instanceData, err := client.getMetadata(ctx, "instance")
return err == nil && instanceData != ""
id, err := client.getNumericID(ctx)
return err == nil && id != 0
}

func (client *InstanceMetadataClient) getNumericID(ctx context.Context) (uint64, error) {
idStr, err := client.GetID(ctx)
if err != nil {
return 0, trace.Wrap(err)
}
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
// Shouldn't ever happen on GCP, but at least one other cloud provider (Yandex)
// implements this metadata API and doesn't have numeric IDs.
return 0, trace.Wrap(err)
}
return id, nil
}

// GetTags gets all of the GCP instance's labels (note: these are separate from
Expand All @@ -96,11 +110,7 @@ func (client *InstanceMetadataClient) GetTags(ctx context.Context) (map[string]s
if err != nil {
return nil, trace.Wrap(err)
}
idStr, err := client.GetID(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
id, err := strconv.ParseUint(idStr, 10, 64)
id, err := client.getNumericID(ctx)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if this fails, are we going to continue to call GetTags on a periodic basis and continue to return the same error over and over again?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For getNumericID() in particular, it's called in IsAvailable(), so if it fails (e.g. because we're on Yandex) Teleport won't create a GCP metadata client at all. In general, yes errors here are returned periodically, but we only log them once.

func (l *CloudImporter) Sync(ctx context.Context) error {
tags, err := l.Client.GetTags(ctx)
if err != nil {
if trace.IsNotFound(err) || trace.IsAccessDenied(err) {
// Only show the error the first time around.
l.instanceTagsNotFoundOnce.Do(func() {
l.Log.Warning(l.instanceMetadataHint)
})
return nil
}
return trace.Wrap(err)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this fix #42312?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't, that issue is fixed by the logging changes in lib/service (I originally also tried to parse the *url.Errors, but per feedback on this PR I removed that as it was redundant).

Copy link
Copy Markdown
Contributor

@greedy52 greedy52 Jun 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does the logging change fix that?

I see, now we are just logging the error instead of failing. Ignore this comment.

if err != nil {
return nil, trace.Wrap(err)
}
Expand Down
40 changes: 34 additions & 6 deletions lib/cloud/imds/gcp/imds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,44 @@ func (m *mockInstanceGetter) GetInstanceTags(ctx context.Context, req *gcp.Insta
func TestIsInstanceMetadataAvailable(t *testing.T) {
t.Parallel()

t.Run("not available", func(t *testing.T) {
client := &InstanceMetadataClient{
tests := []struct {
name string
getMetadata metadataGetter
assert require.BoolAssertionFunc
}{
{
name: "not available",
getMetadata: func(ctx context.Context, path string) (string, error) {
return "", trace.NotFound("")
},
}
require.False(t, client.IsAvailable(context.Background()))
})
assert: require.False,
},
{
name: "not on gcp",
getMetadata: func(ctx context.Context, path string) (string, error) {
return "non-numeric id", nil
},
assert: require.False,
},
{
name: "on mocked gcp",
getMetadata: func(ctx context.Context, path string) (string, error) {
return "12345678", nil
},
assert: require.True,
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
client := &InstanceMetadataClient{
getMetadata: tc.getMetadata,
}
tc.assert(t, client.IsAvailable(context.Background()))
})
}

t.Run("on gcp", func(t *testing.T) {
t.Run("on real gcp", func(t *testing.T) {
if os.Getenv("TELEPORT_TEST_GCP") == "" {
t.Skip("not on gcp")
}
Expand Down
12 changes: 8 additions & 4 deletions lib/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand All @@ -985,15 +989,15 @@ 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{
Client: imClient,
Clock: cfg.Clock,
})
if err != nil {
return nil, trace.Wrap(err)
cfg.Logger.ErrorContext(supervisor.ExitContext(), "Cloud labels will not be imported.", "error", err)
}
}

Expand Down