From bbd67e6b9c58861326d6ed30cb2acf43c828f401 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Mon, 13 Jan 2025 15:30:05 +0000 Subject: [PATCH] UserTasks - Discover RDS issues: add RDS known issues This PR adds a single RDS issue so that it's easier to review. Other issues will be added later on. --- api/types/usertasks/object.go | 132 ++++++++++++ api/types/usertasks/object_test.go | 200 ++++++++++++++++++ lib/auth/usertasks/usertasksv1/service.go | 2 + lib/usertasks/descriptions.go | 7 + .../descriptions/rds-iam-auth-disabled.md | 5 + lib/usertasks/descriptions_test.go | 3 + lib/usertasks/urls.go | 71 ++++++- lib/usertasks/urls_test.go | 46 ++++ lib/web/ui/usertask.go | 12 +- 9 files changed, 476 insertions(+), 2 deletions(-) create mode 100644 lib/usertasks/descriptions/rds-iam-auth-disabled.md diff --git a/api/types/usertasks/object.go b/api/types/usertasks/object.go index 9ac05733ac969..46a0334b6ee27 100644 --- a/api/types/usertasks/object.go +++ b/api/types/usertasks/object.go @@ -102,6 +102,34 @@ func NewDiscoverEKSUserTask(spec *usertasksv1.UserTaskSpec, opts ...UserTaskOpti return ut, nil } +// NewDiscoverRDSUserTask creates a new DiscoverRDS User Task Type. +func NewDiscoverRDSUserTask(spec *usertasksv1.UserTaskSpec, opts ...UserTaskOption) (*usertasksv1.UserTask, error) { + taskName := TaskNameForDiscoverRDS(TaskNameForDiscoverRDSParts{ + Integration: spec.GetIntegration(), + IssueType: spec.GetIssueType(), + AccountID: spec.GetDiscoverRds().GetAccountId(), + Region: spec.GetDiscoverRds().GetRegion(), + }) + + ut := &usertasksv1.UserTask{ + Kind: types.KindUserTask, + Version: types.V1, + Metadata: &headerv1.Metadata{ + Name: taskName, + }, + Spec: spec, + } + for _, o := range opts { + o(ut) + } + + if err := ValidateUserTask(ut); err != nil { + return nil, trace.Wrap(err) + } + + return ut, nil +} + const ( // TaskStateOpen identifies an issue with an instance that is not yet resolved. TaskStateOpen = "OPEN" @@ -121,6 +149,11 @@ const ( // when an auto-enrollment of an EKS cluster fails. // UserTasks that have this Task Type must include the DiscoverEKS field. TaskTypeDiscoverEKS = "discover-eks" + + // TaskTypeDiscoverRDS identifies a User Tasks that is created + // when an auto-enrollment of an RDS database fails or needs attention. + // UserTasks that have this Task Type must include the DiscoverRDS field. + TaskTypeDiscoverRDS = "discover-rds" ) // List of Auto Discover EC2 issues identifiers. @@ -197,6 +230,19 @@ var DiscoverEKSIssueTypes = []string{ AutoDiscoverEKSIssueAgentNotConnecting, } +// List of Auto Discover RDS issues identifiers. +// This value is used to populate the UserTasks.Spec.IssueType for Discover RDS tasks. +const ( + // AutoDiscoverRDSIssueIAMAuthenticationDisabled is used to identify databases that won't be + // accessible because IAM Authentication is not enabled. + AutoDiscoverRDSIssueIAMAuthenticationDisabled = "rds-iam-auth-disabled" +) + +// DiscoverRDSIssueTypes is a list of issue types that can occur when trying to auto enroll RDS databases. +var DiscoverRDSIssueTypes = []string{ + AutoDiscoverRDSIssueIAMAuthenticationDisabled, +} + // ValidateUserTask validates the UserTask object without modifying it. func ValidateUserTask(ut *usertasksv1.UserTask) error { switch { @@ -225,6 +271,10 @@ func ValidateUserTask(ut *usertasksv1.UserTask) error { if err := validateDiscoverEKSTaskType(ut); err != nil { return trace.Wrap(err) } + case TaskTypeDiscoverRDS: + if err := validateDiscoverRDSTaskType(ut); err != nil { + return trace.Wrap(err) + } default: return trace.BadParameter("task type %q is not valid", ut.Spec.TaskType) } @@ -345,6 +395,61 @@ func validateDiscoverEKSTaskType(ut *usertasksv1.UserTask) error { return nil } +func validateDiscoverRDSTaskType(ut *usertasksv1.UserTask) error { + if ut.GetSpec().Integration == "" { + return trace.BadParameter("integration is required") + } + if ut.GetSpec().DiscoverRds == nil { + return trace.BadParameter("%s requires the discover_rds field", TaskTypeDiscoverRDS) + } + if ut.GetSpec().DiscoverRds.AccountId == "" { + return trace.BadParameter("%s requires the discover_rds.account_id field", TaskTypeDiscoverRDS) + } + if ut.GetSpec().DiscoverRds.Region == "" { + return trace.BadParameter("%s requires the discover_rds.region field", TaskTypeDiscoverRDS) + } + + expectedTaskName := TaskNameForDiscoverRDS(TaskNameForDiscoverRDSParts{ + Integration: ut.Spec.Integration, + IssueType: ut.Spec.IssueType, + AccountID: ut.Spec.DiscoverRds.AccountId, + Region: ut.Spec.DiscoverRds.Region, + }) + if ut.Metadata.GetName() != expectedTaskName { + return trace.BadParameter("task name is pre-defined for discover-rds types, expected %s, got %s", + expectedTaskName, + ut.Metadata.GetName(), + ) + } + + if !slices.Contains(DiscoverRDSIssueTypes, ut.GetSpec().IssueType) { + return trace.BadParameter("invalid issue type state, allowed values: %v", DiscoverRDSIssueTypes) + } + + if len(ut.Spec.DiscoverRds.Databases) == 0 { + return trace.BadParameter("at least one database is required") + } + for databaseIdentifier, databaseIssue := range ut.Spec.DiscoverRds.Databases { + if databaseIdentifier == "" { + return trace.BadParameter("database identifier in discover_rds.databases map is required") + } + if databaseIssue.Name == "" { + return trace.BadParameter("database identifier in discover_rds.databases field is required") + } + if databaseIdentifier != databaseIssue.Name { + return trace.BadParameter("database identifier in discover_rds.databases map and field are different") + } + if databaseIssue.DiscoveryConfig == "" { + return trace.BadParameter("discovery config in discover_rds.databases field is required") + } + if databaseIssue.DiscoveryGroup == "" { + return trace.BadParameter("discovery group in discover_rds.databases field is required") + } + } + + return nil +} + // TaskNameForDiscoverEC2Parts are the fields that deterministically compute a Discover EC2 task name. // To be used with TaskNameForDiscoverEC2 function. type TaskNameForDiscoverEC2Parts struct { @@ -408,3 +513,30 @@ func TaskNameForDiscoverEKS(parts TaskNameForDiscoverEKSParts) string { // discoverEKSNamespace is an UUID that represents the name space to be used for generating UUIDs for DiscoverEKS User Task names. var discoverEKSNamespace = uuid.NewSHA1(uuid.Nil, []byte("discover-eks")) + +// TaskNameForDiscoverRDSParts are the fields that deterministically compute a Discover RDS task name. +// To be used with TaskNameForDiscoverRDS function. +type TaskNameForDiscoverRDSParts struct { + Integration string + IssueType string + AccountID string + Region string +} + +// TaskNameForDiscoverRDS returns a deterministic name for the DiscoverRDS task type. +// This method is used to ensure a single UserTask is created to report issues in enrolling RDS databases for a given integration, issue type, account id and region. +func TaskNameForDiscoverRDS(parts TaskNameForDiscoverRDSParts) string { + var bs []byte + bs = append(bs, binary.LittleEndian.AppendUint64(nil, uint64(len(parts.Integration)))...) + bs = append(bs, []byte(parts.Integration)...) + bs = append(bs, binary.LittleEndian.AppendUint64(nil, uint64(len(parts.IssueType)))...) + bs = append(bs, []byte(parts.IssueType)...) + bs = append(bs, binary.LittleEndian.AppendUint64(nil, uint64(len(parts.AccountID)))...) + bs = append(bs, []byte(parts.AccountID)...) + bs = append(bs, binary.LittleEndian.AppendUint64(nil, uint64(len(parts.Region)))...) + bs = append(bs, []byte(parts.Region)...) + return uuid.NewSHA1(discoverRDSNamespace, bs).String() +} + +// discoverRDSNamespace is an UUID that represents the name space to be used for generating UUIDs for DiscoverRDS User Task names. +var discoverRDSNamespace = uuid.NewSHA1(uuid.Nil, []byte("discover-rds")) diff --git a/api/types/usertasks/object_test.go b/api/types/usertasks/object_test.go index 396a18613502d..35d8028cdec2f 100644 --- a/api/types/usertasks/object_test.go +++ b/api/types/usertasks/object_test.go @@ -82,6 +82,32 @@ func TestValidateUserTask(t *testing.T) { return userTask } + exampleDatabaseName := "my-db" + baseRDSDiscoverTask := func(t *testing.T) *usertasksv1.UserTask { + userTask, err := usertasks.NewDiscoverRDSUserTask(&usertasksv1.UserTaskSpec{ + Integration: "my-integration", + TaskType: "discover-rds", + IssueType: "rds-iam-auth-disabled", + State: "OPEN", + DiscoverRds: &usertasksv1.DiscoverRDS{ + AccountId: "123456789012", + Region: "us-east-1", + Databases: map[string]*usertasksv1.DiscoverRDSDatabase{ + exampleDatabaseName: { + Name: exampleDatabaseName, + DiscoveryConfig: "dc01", + DiscoveryGroup: "dg01", + IsCluster: true, + Engine: "aurora-postgresql", + SyncTime: timestamppb.Now(), + }, + }, + }, + }) + require.NoError(t, err) + return userTask + } + tests := []struct { name string task func(t *testing.T) *usertasksv1.UserTask @@ -338,6 +364,119 @@ func TestValidateUserTask(t *testing.T) { }, wantErr: require.Error, }, + { + name: "DiscoverRDS: valid", + task: baseRDSDiscoverTask, + wantErr: require.NoError, + }, + { + name: "DiscoverRDS: invalid issue type", + task: func(t *testing.T) *usertasksv1.UserTask { + ut := baseRDSDiscoverTask(t) + ut.Spec.IssueType = "unknown error" + return ut + }, + wantErr: require.Error, + }, + { + name: "DiscoverRDS: missing integration", + task: func(t *testing.T) *usertasksv1.UserTask { + ut := baseRDSDiscoverTask(t) + ut.Spec.Integration = "" + return ut + }, + wantErr: require.Error, + }, + { + name: "DiscoverRDS: missing discover rds field", + task: func(t *testing.T) *usertasksv1.UserTask { + ut := baseRDSDiscoverTask(t) + ut.Spec.DiscoverRds = nil + return ut + }, + wantErr: require.Error, + }, + { + name: "DiscoverRDS: wrong task name", + task: func(t *testing.T) *usertasksv1.UserTask { + ut := baseRDSDiscoverTask(t) + ut.Metadata.Name = "another-name" + return ut + }, + wantErr: require.Error, + }, + { + name: "DiscoverRDS: missing account id", + task: func(t *testing.T) *usertasksv1.UserTask { + ut := baseRDSDiscoverTask(t) + ut.Spec.DiscoverRds.AccountId = "" + return ut + }, + wantErr: require.Error, + }, + { + name: "DiscoverRDS: missing region", + task: func(t *testing.T) *usertasksv1.UserTask { + ut := baseRDSDiscoverTask(t) + ut.Spec.DiscoverRds.Region = "" + return ut + }, + wantErr: require.Error, + }, + { + name: "DiscoverRDS: databases - missing database name in map key", + task: func(t *testing.T) *usertasksv1.UserTask { + ut := baseRDSDiscoverTask(t) + origDatabasdeMetadata := ut.Spec.DiscoverRds.Databases[exampleDatabaseName] + ut.Spec.DiscoverRds.Databases[""] = origDatabasdeMetadata + return ut + }, + wantErr: require.Error, + }, + { + name: "DiscoverRDS: databases - missing database name in metadata", + task: func(t *testing.T) *usertasksv1.UserTask { + ut := baseRDSDiscoverTask(t) + origDatabasdeMetadata := ut.Spec.DiscoverRds.Databases[exampleDatabaseName] + origDatabasdeMetadata.Name = "" + ut.Spec.DiscoverRds.Databases[exampleDatabaseName] = origDatabasdeMetadata + return ut + }, + wantErr: require.Error, + }, + { + name: "DiscoverRDS: databases - different database name", + task: func(t *testing.T) *usertasksv1.UserTask { + ut := baseRDSDiscoverTask(t) + origDatabasdeMetadata := ut.Spec.DiscoverRds.Databases[exampleDatabaseName] + origDatabasdeMetadata.Name = "another-database" + ut.Spec.DiscoverRds.Databases[exampleDatabaseName] = origDatabasdeMetadata + return ut + }, + wantErr: require.Error, + }, + { + name: "DiscoverRDS: databases - missing discovery config", + task: func(t *testing.T) *usertasksv1.UserTask { + ut := baseRDSDiscoverTask(t) + origDatabasdeMetadata := ut.Spec.DiscoverRds.Databases[exampleDatabaseName] + origDatabasdeMetadata.DiscoveryConfig = "" + ut.Spec.DiscoverRds.Databases[exampleDatabaseName] = origDatabasdeMetadata + return ut + }, + wantErr: require.Error, + }, + { + name: "DiscoverRDS: databases - missing discovery group", + task: func(t *testing.T) *usertasksv1.UserTask { + ut := baseRDSDiscoverTask(t) + origDatabasdeMetadata := ut.Spec.DiscoverRds.Databases[exampleDatabaseName] + origDatabasdeMetadata.DiscoveryGroup = "" + ut.Spec.DiscoverRds.Databases[exampleDatabaseName] = origDatabasdeMetadata + return ut + }, + wantErr: require.Error, + }, } for _, tt := range tests { @@ -465,3 +604,64 @@ func TestNewDiscoverEKSUserTask(t *testing.T) { }) } } + +func TestNewDiscoverRDSUserTask(t *testing.T) { + t.Parallel() + + userTaskExpirationTime := time.Now() + userTaskExpirationTimestamp := timestamppb.New(userTaskExpirationTime) + databaseSyncTimestamp := userTaskExpirationTimestamp + + baseRDSDiscoverTaskSpec := &usertasksv1.UserTaskSpec{ + Integration: "my-integration", + TaskType: "discover-rds", + IssueType: "rds-iam-auth-disabled", + State: "OPEN", + DiscoverRds: &usertasksv1.DiscoverRDS{ + AccountId: "123456789012", + Region: "us-east-1", + Databases: map[string]*usertasksv1.DiscoverRDSDatabase{ + "my-database": { + Name: "my-database", + DiscoveryConfig: "dc01", + DiscoveryGroup: "dg01", + SyncTime: databaseSyncTimestamp, + IsCluster: true, + Engine: "aurora-postgresql", + }, + }, + }, + } + + tests := []struct { + name string + taskSpec *usertasksv1.UserTaskSpec + taskOption []usertasks.UserTaskOption + expectedTask *usertasksv1.UserTask + }{ + { + name: "options are applied task type", + taskSpec: baseRDSDiscoverTaskSpec, + expectedTask: &usertasksv1.UserTask{ + Kind: "user_task", + Version: "v1", + Metadata: &headerv1.Metadata{ + Name: "8c6014e2-8275-54d7-b285-31e0194b7835", + Expires: userTaskExpirationTimestamp, + }, + Spec: baseRDSDiscoverTaskSpec, + }, + taskOption: []usertasks.UserTaskOption{ + usertasks.WithExpiration(userTaskExpirationTime), + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotTask, err := usertasks.NewDiscoverRDSUserTask(tt.taskSpec, tt.taskOption...) + require.NoError(t, err) + require.Equal(t, tt.expectedTask, gotTask) + }) + } +} diff --git a/lib/auth/usertasks/usertasksv1/service.go b/lib/auth/usertasks/usertasksv1/service.go index 74223f258369c..1c9f7eedcdb83 100644 --- a/lib/auth/usertasks/usertasksv1/service.go +++ b/lib/auth/usertasks/usertasksv1/service.go @@ -180,6 +180,8 @@ func userTaskToUserTaskStateEvent(ut *usertasksv1.UserTask) *usagereporter.UserT ret.InstancesCount = int32(len(ut.GetSpec().GetDiscoverEc2().GetInstances())) case usertasks.TaskTypeDiscoverEKS: ret.InstancesCount = int32(len(ut.GetSpec().GetDiscoverEks().GetClusters())) + case usertasks.TaskTypeDiscoverRDS: + ret.InstancesCount = int32(len(ut.GetSpec().GetDiscoverRds().GetDatabases())) } return ret } diff --git a/lib/usertasks/descriptions.go b/lib/usertasks/descriptions.go index 3068e1d02b023..a78009c9caef7 100644 --- a/lib/usertasks/descriptions.go +++ b/lib/usertasks/descriptions.go @@ -48,3 +48,10 @@ func DescriptionForDiscoverEC2Issue(issueType string) string { func DescriptionForDiscoverEKSIssue(issueType string) string { return loadIssueDescription(issueType) } + +// DescriptionForDiscoverRDSIssue returns the description of the issue and fixing steps. +// The returned string contains a markdown document. +// If issue type is not recognized or doesn't have a specific description, them an empty string is returned. +func DescriptionForDiscoverRDSIssue(issueType string) string { + return loadIssueDescription(issueType) +} diff --git a/lib/usertasks/descriptions/rds-iam-auth-disabled.md b/lib/usertasks/descriptions/rds-iam-auth-disabled.md new file mode 100644 index 0000000000000..33246597fb274 --- /dev/null +++ b/lib/usertasks/descriptions/rds-iam-auth-disabled.md @@ -0,0 +1,5 @@ +The Teleport Database Service uses [IAM authentication](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html) to communicate with RDS. + +The following RDS databases do not have IAM authentication enabled. + +You can enable by modifying the IAM DB Authentication property of the database. \ No newline at end of file diff --git a/lib/usertasks/descriptions_test.go b/lib/usertasks/descriptions_test.go index 6d0d2f4cd371f..d02fd05e5cd3d 100644 --- a/lib/usertasks/descriptions_test.go +++ b/lib/usertasks/descriptions_test.go @@ -33,4 +33,7 @@ func TestAllDescriptions(t *testing.T) { for _, issueType := range usertasksapi.DiscoverEKSIssueTypes { require.NotEmpty(t, DescriptionForDiscoverEKSIssue(issueType), "issue type %q is missing descriptions/%s.md file", issueType, issueType) } + for _, issueType := range usertasksapi.DiscoverRDSIssueTypes { + require.NotEmpty(t, DescriptionForDiscoverRDSIssue(issueType), "issue type %q is missing descriptions/%s.md file", issueType, issueType) + } } diff --git a/lib/usertasks/urls.go b/lib/usertasks/urls.go index 1f95960af0cb2..2eb0795b2cf5b 100644 --- a/lib/usertasks/urls.go +++ b/lib/usertasks/urls.go @@ -19,6 +19,7 @@ package usertasks import ( + "fmt" "net/url" "path" @@ -125,7 +126,7 @@ func EKSClustersWithURLs(ut *usertasksv1.UserTask) *UserTaskDiscoverEKSWithURLs type UserTaskDiscoverEC2WithURLs struct { *usertasksv1.DiscoverEC2 // Instances maps the instance ID name to the result of enrolling that instance into teleport. - Instances map[string]*DiscoverEC2InstanceWithURLs `json:"clusters,omitempty"` + Instances map[string]*DiscoverEC2InstanceWithURLs `json:"instances,omitempty"` } // DiscoverEC2InstanceWithURLs contains the result of enrolling an AWS EC2 Instance. @@ -172,3 +173,71 @@ func EC2InstancesWithURLs(ut *usertasksv1.UserTask) *UserTaskDiscoverEC2WithURLs Instances: instancesWithURLs, } } + +// UserTaskDiscoverRDSWithURLs contains the databases that failed to auto-enroll into the cluster. +type UserTaskDiscoverRDSWithURLs struct { + *usertasksv1.DiscoverRDS + // Databases maps a database resource id to the result of enrolling that database into teleport. + // For RDS Aurora Clusters, this is the DBClusterIdentifier. + // For other RDS databases, this is the DBInstanceIdentifier. + Databases map[string]*DiscoverRDSDatabaseWithURLs `json:"databases,omitempty"` +} + +// DiscoverRDSDatabaseWithURLs contains the result of enrolling an AWS RDS Database. +type DiscoverRDSDatabaseWithURLs struct { + *usertasksv1.DiscoverRDSDatabase + + // ResourceURL is the Amazon Web Console URL to access this RDS Database. + // Always present. + // Format for instances: https://console.aws.amazon.com/rds/home?region=#database:id=;is-cluster=false + // Format for clusters: https://console.aws.amazon.com/rds/home?region=#database:id=;is-cluster=true + ResourceURL string `json:"resourceUrl,omitempty"` + + // ConfigurationURL is the Amazon Web Console URL that shows the configuration of the database. + // Format https://console.aws.amazon.com/rds/home?region=#database:id=;is-cluster=;tab=configuration + ConfigurationURL string `json:"configurationUrl,omitempty"` +} + +func withRDSDatabaseIssueURL(metadata *usertasksv1.UserTask, database *usertasksv1.DiscoverRDSDatabase) *DiscoverRDSDatabaseWithURLs { + ret := &DiscoverRDSDatabaseWithURLs{ + DiscoverRDSDatabase: database, + } + + fragment := fmt.Sprintf("database:id=%s;is-cluster=%t", database.GetName(), database.GetIsCluster()) + databaseBaseURL := url.URL{ + Scheme: "https", + Host: "console.aws.amazon.com", + Path: path.Join("rds", "home"), + Fragment: fragment, + RawQuery: url.Values{ + "region": []string{metadata.Spec.DiscoverRds.GetRegion()}, + }.Encode(), + } + ret.ResourceURL = databaseBaseURL.String() + + switch metadata.Spec.IssueType { + case usertasksapi.AutoDiscoverRDSIssueIAMAuthenticationDisabled: + databaseBaseURL.Fragment = databaseBaseURL.Fragment + ";tab=configuration" + ret.ConfigurationURL = databaseBaseURL.String() + } + + return ret +} + +// RDSDatabasesWithURLs takes a UserTask and enriches the database list with URLs. +// Currently, the following URLs will be added: +// - ResourceURL: a link to open the database in Amazon Web Console. +// - ConfigurationURL: a link to open the database in Amazon Web Console in the configuration tab. +func RDSDatabasesWithURLs(ut *usertasksv1.UserTask) *UserTaskDiscoverRDSWithURLs { + databases := ut.Spec.GetDiscoverRds().GetDatabases() + databasesWithURLs := make(map[string]*DiscoverRDSDatabaseWithURLs, len(databases)) + + for databaseID, database := range databases { + databasesWithURLs[databaseID] = withRDSDatabaseIssueURL(ut, database) + } + + return &UserTaskDiscoverRDSWithURLs{ + DiscoverRDS: ut.Spec.GetDiscoverRds(), + Databases: databasesWithURLs, + } +} diff --git a/lib/usertasks/urls_test.go b/lib/usertasks/urls_test.go index 74f8e6c065fb3..879a76174b3be 100644 --- a/lib/usertasks/urls_test.go +++ b/lib/usertasks/urls_test.go @@ -149,3 +149,49 @@ func TestEC2URLs(t *testing.T) { }) } } + +func TestRDSURLs(t *testing.T) { + databaseName := "my-database" + dummyDatabase := &usertasksv1.DiscoverRDSDatabase{Name: databaseName} + baseDatabaseData := &usertasksv1.DiscoverRDS{ + Region: "us-east-1", + Databases: map[string]*usertasksv1.DiscoverRDSDatabase{ + databaseName: dummyDatabase, + }, + } + + for _, tt := range []struct { + name string + issueType string + expectedRDSDatabaseWithURL *DiscoverRDSDatabaseWithURLs + expected *UserTaskDiscoverRDSWithURLs + }{ + { + name: "url for rds database without IAM Authentication", + issueType: usertasksapi.AutoDiscoverRDSIssueIAMAuthenticationDisabled, + expectedRDSDatabaseWithURL: &DiscoverRDSDatabaseWithURLs{ + ResourceURL: "https://console.aws.amazon.com/rds/home?region=us-east-1#database:id=my-database;is-cluster=false", + ConfigurationURL: "https://console.aws.amazon.com/rds/home?region=us-east-1#database:id=my-database;is-cluster=false;tab=configuration", + }, + }, + } { + t.Run(tt.name, func(t *testing.T) { + databaseWithURL := tt.expectedRDSDatabaseWithURL + databaseWithURL.DiscoverRDSDatabase = dummyDatabase + expected := &UserTaskDiscoverRDSWithURLs{ + DiscoverRDS: baseDatabaseData, + Databases: map[string]*DiscoverRDSDatabaseWithURLs{ + databaseName: databaseWithURL, + }, + } + + got := RDSDatabasesWithURLs(&usertasksv1.UserTask{ + Spec: &usertasksv1.UserTaskSpec{ + IssueType: tt.issueType, + DiscoverRds: baseDatabaseData, + }, + }) + require.Equal(t, expected, got) + }) + } +} diff --git a/lib/web/ui/usertask.go b/lib/web/ui/usertask.go index 14fc86a8bd71f..6ce0457596567 100644 --- a/lib/web/ui/usertask.go +++ b/lib/web/ui/usertask.go @@ -55,6 +55,8 @@ type UserTaskDetail struct { DiscoverEC2 *usertasks.UserTaskDiscoverEC2WithURLs `json:"discoverEc2,omitempty"` // DiscoverEKS contains the task details for the DiscoverEKS tasks. DiscoverEKS *usertasks.UserTaskDiscoverEKSWithURLs `json:"discoverEks,omitempty"` + // DiscoverRDS contains the task details for the DiscoverRDS tasks. + DiscoverRDS *usertasks.UserTaskDiscoverRDSWithURLs `json:"discoverRds,omitempty"` } // UpdateUserTaskStateRequest is a request to update a UserTask @@ -96,16 +98,23 @@ func MakeUserTasks(uts []*usertasksv1.UserTask) []UserTask { // MakeDetailedUserTask creates a UI UserTask representation containing all the details. func MakeDetailedUserTask(ut *usertasksv1.UserTask) UserTaskDetail { var description string - var discoverEKS *usertasks.UserTaskDiscoverEKSWithURLs + var discoverEC2 *usertasks.UserTaskDiscoverEC2WithURLs + var discoverEKS *usertasks.UserTaskDiscoverEKSWithURLs + var discoverRDS *usertasks.UserTaskDiscoverRDSWithURLs switch ut.GetSpec().GetTaskType() { case apiusertasks.TaskTypeDiscoverEC2: description = usertasks.DescriptionForDiscoverEC2Issue(ut.GetSpec().GetIssueType()) discoverEC2 = usertasks.EC2InstancesWithURLs(ut) + case apiusertasks.TaskTypeDiscoverEKS: description = usertasks.DescriptionForDiscoverEKSIssue(ut.GetSpec().GetIssueType()) discoverEKS = usertasks.EKSClustersWithURLs(ut) + + case apiusertasks.TaskTypeDiscoverRDS: + description = usertasks.DescriptionForDiscoverRDSIssue(ut.GetSpec().GetIssueType()) + discoverRDS = usertasks.RDSDatabasesWithURLs(ut) } return UserTaskDetail{ @@ -113,6 +122,7 @@ func MakeDetailedUserTask(ut *usertasksv1.UserTask) UserTaskDetail { Description: description, DiscoverEC2: discoverEC2, DiscoverEKS: discoverEKS, + DiscoverRDS: discoverRDS, } }