Skip to content

Commit 6efe554

Browse files
committed
Add IaC label and usertasks to integration stats
1 parent e3adbd1 commit 6efe554

File tree

5 files changed

+56
-2
lines changed

5 files changed

+56
-2
lines changed

api/types/constants.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,8 @@ const (
779779
// ADLabel is a resource metadata label name used to identify if resource is part of Active Directory
780780
ADLabel = TeleportNamespace + "/ad"
781781

782+
// CreatedByIaCLabel is a resource metadata label name used to identify if resource was created by IaC tooling.
783+
CreatedByIaCLabel = TeleportNamespace + "/iac-tool"
782784
// OriginDefaults is an origin value indicating that the resource was
783785
// constructed as a default value.
784786
OriginDefaults = common.OriginDefaults

lib/web/integrations.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,12 @@ func collectIntegrationStats(ctx context.Context, req collectIntegrationStatsReq
338338
}
339339
ret.Integration = uiIg
340340

341+
if req.integration != nil {
342+
if val, ok := req.integration.GetLabel(types.CreatedByIaCLabel); ok && val == ui.IaCTerraformLabel {
343+
ret.IsManagedByTerraform = true
344+
}
345+
}
346+
341347
var nextPage string
342348
for {
343349
filters := &usertasksv1.ListUserTasksFilters{
@@ -349,7 +355,7 @@ func collectIntegrationStats(ctx context.Context, req collectIntegrationStatsReq
349355
return nil, err
350356
}
351357

352-
ret.UnresolvedUserTasks += len(userTasks)
358+
ret.UserTasks = append(ret.UserTasks, ui.MakeUserTasks(userTasks)...)
353359

354360
for _, userTask := range userTasks {
355361
switch userTask.GetSpec().GetTaskType() {
@@ -368,6 +374,8 @@ func collectIntegrationStats(ctx context.Context, req collectIntegrationStatsReq
368374
nextPage = nextToken
369375
}
370376

377+
ret.UnresolvedUserTasks = len(ret.UserTasks)
378+
371379
nextPage = ""
372380
for {
373381
discoveryConfigs, nextToken, err := req.discoveryConfigLister.ListDiscoveryConfigs(ctx, 0, nextPage)

lib/web/integrations_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,13 @@ func TestCollectIntegrationStats(t *testing.T) {
317317
userTasksList = append(userTasksList, &usertasksv1.UserTask{Spec: &usertasksv1.UserTaskSpec{State: usertasks.TaskStateResolved, TaskType: usertasks.TaskTypeDiscoverEC2}})
318318
}
319319

320+
var openUserTasksList []*usertasksv1.UserTask
321+
for _, ut := range userTasksList {
322+
if ut.GetSpec().GetState() == usertasks.TaskStateOpen {
323+
openUserTasksList = append(openUserTasksList, ut)
324+
}
325+
}
326+
320327
userTasksClient := &mockUserTasksLister{
321328
defaultPageSize: 3,
322329
userTasks: userTasksList,
@@ -339,6 +346,7 @@ func TestCollectIntegrationStats(t *testing.T) {
339346
AWSOIDC: &ui.IntegrationAWSOIDCSpec{RoleARN: "arn:role"},
340347
},
341348
UnresolvedUserTasks: ec2UserTasks + rdsUserTasks,
349+
UserTasks: ui.MakeUserTasks(openUserTasksList),
342350
AWSEC2: ui.ResourceTypeSummary{
343351
UnresolvedUserTasks: ec2UserTasks,
344352
},

lib/web/ui/integration.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ type IntegrationWithSummary struct {
118118
*Integration
119119
// UnresolvedUserTasks contains the count of unresolved user tasks related to this integration.
120120
UnresolvedUserTasks int `json:"unresolvedUserTasks"`
121+
// UserTasks contains the list of unresolved user tasks related to this integration.
122+
UserTasks []UserTask `json:"userTasks,omitempty"`
121123
// AWSEC2 contains the summary for the AWS EC2 resources for this integration.
122124
AWSEC2 ResourceTypeSummary `json:"awsec2"`
123125
// AWSRDS contains the summary for the AWS RDS resources and agents for this integration.
@@ -127,6 +129,10 @@ type IntegrationWithSummary struct {
127129

128130
// RolesAnywhereProfileSync contains the summary for the AWS Roles Anywhere Profile Sync.
129131
RolesAnywhereProfileSync *RolesAnywhereProfileSync `json:"rolesAnywhereProfileSync,omitempty"`
132+
133+
// IsManagedByTerraform indicates if this integration was created by Terraform.
134+
// This is set when the label "teleport.dev/iac" has the value "terraform".
135+
IsManagedByTerraform bool `json:"isManagedByTerraform"`
130136
}
131137

132138
// ResourceTypeSummary contains the summary of the enrollment rules and found resources by the integration.
@@ -210,6 +216,8 @@ type Integration struct {
210216
AWSRA *IntegrationAWSRASpec `json:"awsra,omitempty"`
211217
// GitHub contains the fields for `github` subkind integration.
212218
GitHub *IntegrationGitHub `json:"github,omitempty"`
219+
// IsManagedByTerraform indicates if this integration was created by Terraform.
220+
IsManagedByTerraform bool `json:"isManagedByTerraform"`
213221
}
214222

215223
// CheckAndSetDefaults for the create request.
@@ -349,13 +357,17 @@ func MakeIntegrations(igs []types.Integration) ([]*Integration, error) {
349357
return uiList, nil
350358
}
351359

360+
const IaCTerraformLabel = "terraform"
361+
352362
// MakeIntegration creates a UI Integration representation.
353363
func MakeIntegration(ig types.Integration) (*Integration, error) {
354364
ret := &Integration{
355365
Name: ig.GetName(),
356366
SubKind: ig.GetSubKind(),
357367
}
358-
368+
if val, ok := ig.GetLabel(types.CreatedByIaCLabel); ok && val == IaCTerraformLabel {
369+
ret.IsManagedByTerraform = true
370+
}
359371
switch ig.GetSubKind() {
360372
case types.IntegrationSubKindAWSOIDC:
361373
var s3Bucket string

lib/web/ui/integration_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,19 @@ func TestMakeIntegration(t *testing.T) {
4747
)
4848
require.NoError(t, err)
4949

50+
terraformManagedIntegration, err := types.NewIntegrationAWSOIDC(
51+
types.Metadata{
52+
Name: "terraform-managed",
53+
Labels: map[string]string{
54+
types.CreatedByIaCLabel: IaCTerraformLabel,
55+
},
56+
},
57+
&types.AWSOIDCIntegrationSpecV1{
58+
RoleARN: "arn:aws:iam::123456789012:role/TerraformRole",
59+
},
60+
)
61+
require.NoError(t, err)
62+
5063
testCases := []struct {
5164
integration types.Integration
5265
want Integration
@@ -71,6 +84,17 @@ func TestMakeIntegration(t *testing.T) {
7184
},
7285
},
7386
},
87+
{
88+
integration: terraformManagedIntegration,
89+
want: Integration{
90+
Name: "terraform-managed",
91+
SubKind: types.IntegrationSubKindAWSOIDC,
92+
AWSOIDC: &IntegrationAWSOIDCSpec{
93+
RoleARN: "arn:aws:iam::123456789012:role/TerraformRole",
94+
},
95+
IsManagedByTerraform: true,
96+
},
97+
},
7498
}
7599

76100
for _, tc := range testCases {

0 commit comments

Comments
 (0)