Skip to content

Commit 6e9d19f

Browse files
Truncate DiscoveryConfig.Status ErrorMessage (#52347) (#52844)
Some fetchers might generate a lot of errors which are aggregated and sent to the `DiscoveryConfig.Status.ErrorMessage`. This might cause gRPC clients to fail when listing DiscoveryConfigs with a `grpc: received message larger than max (xyz vs. 4194304)` error. Allowing 100KB for the error message should give the user enough context on what's causing the errors.
1 parent e88a679 commit 6e9d19f

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

api/defaults/defaults.go

+6
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ const (
148148
DefaultChunkSize = 1000
149149
)
150150

151+
const (
152+
// DefaultMaxErrorMessageSize is the default maximum size of an error message.
153+
// This can be used to truncate large error messages, which might cause gRPC messages to exceed the maximum allowed size.
154+
DefaultMaxErrorMessageSize = 1024 * 100 // 100KB
155+
)
156+
151157
const (
152158
// When running in "SSH Proxy" role this port will be used for incoming
153159
// connections from SSH nodes who wish to use "reverse tunnell" (when they

lib/srv/discovery/access_graph.go

+20
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"google.golang.org/grpc/credentials"
3434

3535
"github.com/gravitational/teleport/api/client/proto"
36+
"github.com/gravitational/teleport/api/defaults"
3637
discoveryconfigv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/discoveryconfig/v1"
3738
usageeventsv1 "github.com/gravitational/teleport/api/gen/proto/go/usageevents/v1"
3839
"github.com/gravitational/teleport/api/metadata"
@@ -490,6 +491,11 @@ func (s *Server) updateDiscoveryConfigStatus(fetchers []aws_sync.AWSSync, pushEr
490491
// If this is a pre-run, the status is syncing.
491492
status.State = discoveryconfigv1.DiscoveryConfigState_DISCOVERY_CONFIG_STATE_SYNCING.String()
492493
}
494+
495+
// Ensure the error message is truncated to the maximum allowed size.
496+
// Too large error messages will cause failures when clients (which use the default MaxCallRecvMsgSize of 4MB) try to read DiscoveryConfigs.
497+
status.ErrorMessage = truncateErrorMessage(status)
498+
493499
ctx, cancel := context.WithTimeout(s.ctx, 5*time.Second)
494500
defer cancel()
495501
_, err := s.AccessPoint.UpdateDiscoveryConfigStatus(ctx, fetcher.DiscoveryConfigName(), status)
@@ -502,6 +508,20 @@ func (s *Server) updateDiscoveryConfigStatus(fetchers []aws_sync.AWSSync, pushEr
502508
}
503509
}
504510

511+
func truncateErrorMessage(discoveryConfigStatus discoveryconfig.Status) *string {
512+
if discoveryConfigStatus.ErrorMessage == nil {
513+
return nil
514+
}
515+
516+
if len(*discoveryConfigStatus.ErrorMessage) <= defaults.DefaultMaxErrorMessageSize {
517+
return discoveryConfigStatus.ErrorMessage
518+
}
519+
520+
newErrorMessage := (*discoveryConfigStatus.ErrorMessage)[:defaults.DefaultMaxErrorMessageSize]
521+
522+
return &newErrorMessage
523+
}
524+
505525
func buildFetcherStatus(fetcher aws_sync.AWSSync, pushErr error, lastUpdate time.Time) discoveryconfig.Status {
506526
count, err := fetcher.Status()
507527
err = trace.NewAggregate(err, pushErr)

lib/srv/discovery/status_test.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Teleport
3+
* Copyright (C) 2025 Gravitational, Inc.
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Affero General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Affero General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Affero General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
package discovery
20+
21+
import (
22+
"strings"
23+
"testing"
24+
25+
"github.com/stretchr/testify/require"
26+
27+
"github.com/gravitational/teleport/api/types/discoveryconfig"
28+
)
29+
30+
func stringPointer(s string) *string {
31+
return &s
32+
}
33+
34+
func TestTruncateErrorMessage(t *testing.T) {
35+
for _, tt := range []struct {
36+
name string
37+
in discoveryconfig.Status
38+
expected *string
39+
}{
40+
{
41+
name: "nil error message",
42+
in: discoveryconfig.Status{},
43+
expected: nil,
44+
},
45+
{
46+
name: "small error messages are not changed",
47+
in: discoveryconfig.Status{ErrorMessage: stringPointer("small error message")},
48+
expected: stringPointer("small error message"),
49+
},
50+
{
51+
name: "large error messages are truncated",
52+
in: discoveryconfig.Status{ErrorMessage: stringPointer(strings.Repeat("A", 1024*100+1))},
53+
expected: stringPointer(strings.Repeat("A", 1024*100)),
54+
},
55+
} {
56+
t.Run(tt.name, func(t *testing.T) {
57+
got := truncateErrorMessage(tt.in)
58+
require.Equal(t, tt.expected, got)
59+
})
60+
}
61+
}

0 commit comments

Comments
 (0)