Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration Status endpoint: include number of open UserTasks #51702

Merged
Merged
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
26 changes: 26 additions & 0 deletions lib/web/integrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ import (
discoveryconfigv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/discoveryconfig/v1"
integrationv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/integration/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 @@ -265,6 +267,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 @@ -274,12 +277,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 @@ -292,6 +300,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 @@ -32,9 +33,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/auth/integration/credentials"
"github.com/gravitational/teleport/lib/modules"
"github.com/gravitational/teleport/lib/services"
Expand Down Expand Up @@ -102,6 +105,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 @@ -138,6 +179,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 @@ -147,6 +229,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 @@ -217,6 +300,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 @@ -286,6 +370,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
Loading