Skip to content

Commit

Permalink
Integration Status endpoint: include pending UserTasks (#51702) (#51863)
Browse files Browse the repository at this point in the history
This PR changes the Integration Status endpoint to include the pending
UserTasks for the integration.
This will be used by the frontend to show the number of pending tasks.
  • Loading branch information
marcoandredinis authored Feb 5, 2025
1 parent 5dcf6cc commit efcd46e
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 0 deletions.
26 changes: 26 additions & 0 deletions lib/web/integrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ import (

discoveryconfigv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/discoveryconfig/v1"
pluginspb "github.com/gravitational/teleport/api/gen/proto/go/teleport/plugins/v1"
usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/types/discoveryconfig"
"github.com/gravitational/teleport/api/types/usertasks"
"github.com/gravitational/teleport/integrations/access/msteams"
"github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/httplib"
Expand Down Expand Up @@ -227,6 +229,7 @@ func (h *Handler) integrationStats(w http.ResponseWriter, r *http.Request, p htt
discoveryConfigLister: clt.DiscoveryConfigClient(),
databaseGetter: clt,
awsOIDCClient: clt.IntegrationAWSOIDCClient(),
userTasksClient: clt.UserTasksServiceClient(),
}
summary, err := collectIntegrationStats(r.Context(), req)
if err != nil {
Expand All @@ -236,12 +239,17 @@ func (h *Handler) integrationStats(w http.ResponseWriter, r *http.Request, p htt
return summary, nil
}

type userTasksByIntegrationLister interface {
ListUserTasksByIntegration(ctx context.Context, pageSize int64, nextToken string, integration string) ([]*usertasksv1.UserTask, string, error)
}

type collectIntegrationStatsRequest struct {
logger *slog.Logger
integration types.Integration
discoveryConfigLister discoveryConfigLister
databaseGetter databaseGetter
awsOIDCClient deployedDatabaseServiceLister
userTasksClient userTasksByIntegrationLister
}

func collectIntegrationStats(ctx context.Context, req collectIntegrationStatsRequest) (*ui.IntegrationWithSummary, error) {
Expand All @@ -254,6 +262,24 @@ func collectIntegrationStats(ctx context.Context, req collectIntegrationStatsReq
ret.Integration = uiIg

var nextPage string
for {
userTasks, nextToken, err := req.userTasksClient.ListUserTasksByIntegration(ctx, 0, nextPage, req.integration.GetName())
if err != nil {
return nil, err
}
for _, userTask := range userTasks {
if userTask.GetSpec().GetState() == usertasks.TaskStateOpen {
ret.UnresolvedUserTasks++
}
}

if nextToken == "" {
break
}
nextPage = nextToken
}

nextPage = ""
for {
discoveryConfigs, nextToken, err := req.discoveryConfigLister.ListDiscoveryConfigs(ctx, 0, nextPage)
if err != nil {
Expand Down
85 changes: 85 additions & 0 deletions lib/web/integrations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package web
import (
"context"
"encoding/json"
"strconv"
"testing"
"time"

Expand All @@ -31,9 +32,11 @@ import (
"github.com/gravitational/teleport/api/client/proto"
discoveryconfigv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/discoveryconfig/v1"
integrationv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/integration/v1"
usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/types/discoveryconfig"
"github.com/gravitational/teleport/api/types/header"
"github.com/gravitational/teleport/api/types/usertasks"
"github.com/gravitational/teleport/lib/services"
libui "github.com/gravitational/teleport/lib/ui"
"github.com/gravitational/teleport/lib/utils"
Expand Down Expand Up @@ -99,6 +102,44 @@ func TestIntegrationsCreateWithAudience(t *testing.T) {
}
}

type mockUserTasksLister struct {
defaultPageSize int64
userTasks []*usertasksv1.UserTask
}

func (m *mockUserTasksLister) ListUserTasksByIntegration(ctx context.Context, pageSize int64, nextToken string, integration string) ([]*usertasksv1.UserTask, string, error) {
var ret []*usertasksv1.UserTask
if pageSize == 0 {
pageSize = m.defaultPageSize
}

if len(m.userTasks) == 0 {
return ret, "", nil
}

var sliceStart int
if nextToken != "" {
nextTokenInt, err := strconv.Atoi(nextToken)
if err != nil {
return nil, "", trace.Wrap(err)
}
sliceStart = nextTokenInt
}
userTasksSlice := m.userTasks[sliceStart:]

for i, userTask := range userTasksSlice {
if userTask.GetSpec().GetState() == "OPEN" {
ret = append(ret, userTask)
if len(ret) == int(pageSize) {
nextTokenInt := sliceStart + i + 1
return ret, strconv.Itoa(nextTokenInt), nil
}
}
}

return ret, "", nil
}

func TestCollectAWSOIDCAutoDiscoverStats(t *testing.T) {
ctx := context.Background()
logger := utils.NewSlogLoggerForTests()
Expand Down Expand Up @@ -135,6 +176,47 @@ func TestCollectAWSOIDCAutoDiscoverStats(t *testing.T) {
discoveryConfigLister: clt,
databaseGetter: clt,
awsOIDCClient: deployedDatabaseServicesClient,
userTasksClient: &mockUserTasksLister{},
}
gotSummary, err := collectIntegrationStats(ctx, req)
require.NoError(t, err)
expectedSummary := &ui.IntegrationWithSummary{
Integration: &ui.Integration{
Name: integrationName,
SubKind: "aws-oidc",
AWSOIDC: &ui.IntegrationAWSOIDCSpec{RoleARN: "arn:role"},
},
}
require.Equal(t, expectedSummary, gotSummary)
})

t.Run("returns the number of unresolved user tasks", func(t *testing.T) {
clt := &mockRelevantAWSRegionsClient{
databaseServices: &proto.ListResourcesResponse{
Resources: []*proto.PaginatedResource{},
},
databases: make([]types.Database, 0),
discoveryConfigs: make([]*discoveryconfig.DiscoveryConfig, 0),
}

var userTasksList []*usertasksv1.UserTask
for range 10 {
userTasksList = append(userTasksList, &usertasksv1.UserTask{Spec: &usertasksv1.UserTaskSpec{State: usertasks.TaskStateOpen}})
userTasksList = append(userTasksList, &usertasksv1.UserTask{Spec: &usertasksv1.UserTaskSpec{State: usertasks.TaskStateResolved}})
}

userTasksClient := &mockUserTasksLister{
defaultPageSize: 3,
userTasks: userTasksList,
}

req := collectIntegrationStatsRequest{
logger: logger,
integration: integration,
discoveryConfigLister: clt,
databaseGetter: clt,
awsOIDCClient: deployedDatabaseServicesClient,
userTasksClient: userTasksClient,
}
gotSummary, err := collectIntegrationStats(ctx, req)
require.NoError(t, err)
Expand All @@ -144,6 +226,7 @@ func TestCollectAWSOIDCAutoDiscoverStats(t *testing.T) {
SubKind: "aws-oidc",
AWSOIDC: &ui.IntegrationAWSOIDCSpec{RoleARN: "arn:role"},
},
UnresolvedUserTasks: 10,
}
require.Equal(t, expectedSummary, gotSummary)
})
Expand Down Expand Up @@ -214,6 +297,7 @@ func TestCollectAWSOIDCAutoDiscoverStats(t *testing.T) {
discoveryConfigLister: clt,
databaseGetter: clt,
awsOIDCClient: deployedDatabaseServicesClient,
userTasksClient: &mockUserTasksLister{},
}
gotSummary, err := collectIntegrationStats(ctx, req)
require.NoError(t, err)
Expand Down Expand Up @@ -283,6 +367,7 @@ func TestCollectAWSOIDCAutoDiscoverStats(t *testing.T) {
discoveryConfigLister: clt,
databaseGetter: clt,
awsOIDCClient: deployedDatabaseServicesClient,
userTasksClient: &mockUserTasksLister{},
}
gotSummary, err := collectIntegrationStats(ctx, req)
require.NoError(t, err)
Expand Down
2 changes: 2 additions & 0 deletions lib/web/ui/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ func (r *IntegrationAWSOIDCSpec) CheckAndSetDefaults() error {
// IntegrationWithSummary describes Integration fields and the fields required to return the summary.
type IntegrationWithSummary struct {
*Integration
// UnresolvedUserTasks contains the count of unresolved user tasks related to this integration.
UnresolvedUserTasks int `json:"unresolvedUserTasks,omitempty"`
// AWSEC2 contains the summary for the AWS EC2 resources for this integration.
AWSEC2 ResourceTypeSummary `json:"awsec2,omitempty"`
// AWSRDS contains the summary for the AWS RDS resources and agents for this integration.
Expand Down

0 comments on commit efcd46e

Please sign in to comment.