diff --git a/lib/client/api.go b/lib/client/api.go index 643426c31fc0d..75916ff4f87fd 100644 --- a/lib/client/api.go +++ b/lib/client/api.go @@ -2378,13 +2378,22 @@ func isRemoteDest(name string) bool { // ListNodesWithFilters returns all nodes that match the filters in the current cluster // that the logged in user has access to. func (tc *TeleportClient) ListNodesWithFilters(ctx context.Context) ([]types.Server, error) { - req := tc.ResourceFilter(types.KindNode) + req := proto.ListUnifiedResourcesRequest{ + Kinds: []string{types.KindNode}, + Labels: tc.Labels, + SearchKeywords: tc.SearchKeywords, + PredicateExpression: tc.PredicateExpression, + UseSearchAsRoles: tc.UseSearchAsRoles, + SortBy: types.SortBy{ + Field: types.ResourceKind, + }, + } + ctx, span := tc.Tracer.Start( ctx, "teleportClient/ListNodesWithFilters", oteltrace.WithSpanKind(oteltrace.SpanKindClient), oteltrace.WithAttributes( - attribute.String("resource", req.ResourceType), attribute.Int("limit", int(req.Limit)), attribute.String("predicate", req.PredicateExpression), attribute.StringSlice("keywords", req.SearchKeywords), @@ -2398,8 +2407,30 @@ func (tc *TeleportClient) ListNodesWithFilters(ctx context.Context) ([]types.Ser } defer clt.Close() - servers, err := client.GetAllResources[types.Server](ctx, clt.AuthClient, req) - return servers, trace.Wrap(err) + var servers []types.Server + for { + page, err := client.ListUnifiedResourcePage(ctx, clt.AuthClient, &req) + if err != nil { + return nil, trace.Wrap(err) + } + + for _, r := range page.Resources { + srv, ok := r.(types.Server) + if !ok { + log.Warnf("expected types.Server but received unexpected type %T", r) + continue + } + + servers = append(servers, srv) + } + + req.StartKey = page.NextKey + if req.StartKey == "" { + break + } + } + + return servers, nil } // GetClusterAlerts returns a list of matching alerts from the current cluster. diff --git a/tool/tctl/common/resource_command.go b/tool/tctl/common/resource_command.go index ccfccb059750c..ea20b7cb13149 100644 --- a/tool/tctl/common/resource_command.go +++ b/tool/tctl/common/resource_command.go @@ -1852,19 +1852,53 @@ func (rc *ResourceCommand) getCollection(ctx context.Context, client *auth.Clien } return &authorityCollection{cas: []types.CertAuthority{authority}}, nil case types.KindNode: - nodes, err := client.GetNodes(ctx, rc.namespace) - if err != nil { - return nil, trace.Wrap(err) + var search []string + if rc.ref.Name != "" { + search = []string{rc.ref.Name} } - if rc.ref.Name == "" { - return &serverCollection{servers: nodes}, nil + + req := proto.ListUnifiedResourcesRequest{ + Kinds: []string{types.KindNode}, + SearchKeywords: search, + SortBy: types.SortBy{Field: types.ResourceKind}, } - for _, node := range nodes { - if node.GetName() == rc.ref.Name || node.GetHostname() == rc.ref.Name { - return &serverCollection{servers: []types.Server{node}}, nil + + var collection serverCollection + for { + page, err := apiclient.ListUnifiedResourcePage(ctx, client, &req) + if err != nil { + return nil, trace.Wrap(err) + } + + for _, r := range page.Resources { + srv, ok := r.(types.Server) + if !ok { + log.Warnf("expected types.Server but received unexpected type %T", r) + continue + } + + if rc.ref.Name == "" { + collection.servers = append(collection.servers, srv) + continue + } + + if srv.GetName() == rc.ref.Name || srv.GetHostname() == rc.ref.Name { + collection.servers = []types.Server{srv} + return &collection, nil + } + } + + req.StartKey = page.NextKey + if req.StartKey == "" { + break } } - return nil, trace.NotFound("node with ID %q not found", rc.ref.Name) + + if len(collection.servers) == 0 && rc.ref.Name != "" { + return nil, trace.NotFound("node with ID %q not found", rc.ref.Name) + } + + return &collection, nil case types.KindAuthServer: servers, err := client.GetAuthServers() if err != nil {