From e5bb2758ba4b94989b27c9dc97462fcc020a6df6 Mon Sep 17 00:00:00 2001 From: Siddharth Mishra Date: Fri, 19 Sep 2025 18:00:50 +0530 Subject: [PATCH 1/2] ignore non-service account member ids --- .../resource_tfe_team_organization_members.go | 49 +++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/internal/provider/resource_tfe_team_organization_members.go b/internal/provider/resource_tfe_team_organization_members.go index 84696b0f2..2c10d46cf 100644 --- a/internal/provider/resource_tfe_team_organization_members.go +++ b/internal/provider/resource_tfe_team_organization_members.go @@ -85,10 +85,19 @@ func resourceTFETeamOrganizationMembersRead(d *schema.ResourceData, meta interfa return fmt.Errorf("Error reading organization memberships from team %s: %w", d.Id(), err) } + log.Printf("[DEBUG] Read users from team: %s", d.Id()) + nonServiceAccountUsers, err := fetchNonServiceAccountUserIds(config.Client, d.Id()) + if err != nil { + return fmt.Errorf("Error reading users from team %s: %w", d.Id(), err) + } + // Get all organization memberships and add them to object var organizationMembershipIDs []interface{} for _, membership := range organizationMemberships { - organizationMembershipIDs = append(organizationMembershipIDs, membership.ID) + // Service accounts should not be managed by this resource + if _, ok := nonServiceAccountUsers[membership.User.ID]; ok { + organizationMembershipIDs = append(organizationMembershipIDs, membership.ID) + } } // Check if organization memberships were added at all @@ -103,15 +112,39 @@ func resourceTFETeamOrganizationMembersRead(d *schema.ResourceData, meta interfa return nil } +func fetchNonServiceAccountUserIds(config *tfe.Client, teamID string) (map[string]interface{}, error) { + users, err := config.TeamMembers.ListUsers(ctx, teamID) + if err != nil { + return nil, fmt.Errorf("failed to fetch existing users for team %s: %w", teamID, err) + } + + nonServiceAccountUserIDSet := make(map[string]interface{}) + for _, u := range users { + if !u.IsServiceAccount { + nonServiceAccountUserIDSet[u.ID] = nil + } + } + + return nonServiceAccountUserIDSet, nil +} + func fetchExistingTeamMembershipIds(config *tfe.Client, teamID string) (map[string]interface{}, error) { teamMembers, err := config.TeamMembers.ListOrganizationMemberships(ctx, teamID) if err != nil { return nil, fmt.Errorf("failed to fetch existing organization memberships for team %s: %w", teamID, err) } + nonServiceAccountUserIds, err := fetchNonServiceAccountUserIds(config, teamID) + if err != nil { + return nil, err + } + teamMembersIDSet := make(map[string]interface{}) for _, m := range teamMembers { - teamMembersIDSet[m.ID] = nil + // Service accounts should not be managed by this resource + if _, ok := nonServiceAccountUserIds[m.User.ID]; ok { + teamMembersIDSet[m.ID] = nil + } } return teamMembersIDSet, nil @@ -195,12 +228,20 @@ func resourceTFETeamOrganizationMembersDelete(d *schema.ResourceData, meta inter return fmt.Errorf("Error reading organization memberships from team %s: %w", d.Id(), err) } + nonServiceAccountUserIds, err := fetchNonServiceAccountUserIds(config.Client, d.Id()) + if err != nil { + return fmt.Errorf("Error fetching account user IDs for team %s: %w", d.Id(), err) + } + // Create a new options struct. options := tfe.TeamMemberRemoveOptions{} // Add all the users that need to be removed. - for _, memberships := range organizationMemberships { - options.OrganizationMembershipIDs = append(options.OrganizationMembershipIDs, memberships.ID) + for _, m := range organizationMemberships { + // Service accounts should not be managed by this resource + if _, ok := nonServiceAccountUserIds[m.User.ID]; ok { + options.OrganizationMembershipIDs = append(options.OrganizationMembershipIDs, m.ID) + } } log.Printf("[DEBUG] Remove organization memberships %v from team: %s", options.OrganizationMembershipIDs, d.Id()) From e050a56740161a068eb9678fec135dbfc6322fe9 Mon Sep 17 00:00:00 2001 From: Siddharth Mishra Date: Mon, 22 Sep 2025 13:28:48 +0530 Subject: [PATCH 2/2] ignore sa members and fix uts --- .../resource_tfe_team_organization_members.go | 51 ++++++++----------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/internal/provider/resource_tfe_team_organization_members.go b/internal/provider/resource_tfe_team_organization_members.go index 2c10d46cf..965afa589 100644 --- a/internal/provider/resource_tfe_team_organization_members.go +++ b/internal/provider/resource_tfe_team_organization_members.go @@ -86,18 +86,15 @@ func resourceTFETeamOrganizationMembersRead(d *schema.ResourceData, meta interfa } log.Printf("[DEBUG] Read users from team: %s", d.Id()) - nonServiceAccountUsers, err := fetchNonServiceAccountUserIds(config.Client, d.Id()) + nonServiceAccountOrganizationMemberships, err := filterNonServiceAccountOrganizationMembers(config.Client, organizationMemberships) if err != nil { return fmt.Errorf("Error reading users from team %s: %w", d.Id(), err) } // Get all organization memberships and add them to object var organizationMembershipIDs []interface{} - for _, membership := range organizationMemberships { - // Service accounts should not be managed by this resource - if _, ok := nonServiceAccountUsers[membership.User.ID]; ok { - organizationMembershipIDs = append(organizationMembershipIDs, membership.ID) - } + for _, membership := range nonServiceAccountOrganizationMemberships { + organizationMembershipIDs = append(organizationMembershipIDs, membership.ID) } // Check if organization memberships were added at all @@ -112,20 +109,22 @@ func resourceTFETeamOrganizationMembersRead(d *schema.ResourceData, meta interfa return nil } -func fetchNonServiceAccountUserIds(config *tfe.Client, teamID string) (map[string]interface{}, error) { - users, err := config.TeamMembers.ListUsers(ctx, teamID) - if err != nil { - return nil, fmt.Errorf("failed to fetch existing users for team %s: %w", teamID, err) - } +func filterNonServiceAccountOrganizationMembers(config *tfe.Client, organizationMemberships []*tfe.OrganizationMembership) ([]tfe.OrganizationMembership, error) { + var nonServiceAccountMemberships []tfe.OrganizationMembership - nonServiceAccountUserIDSet := make(map[string]interface{}) - for _, u := range users { - if !u.IsServiceAccount { - nonServiceAccountUserIDSet[u.ID] = nil + for _, om := range organizationMemberships { + organizationMembershipDetails, err := config.OrganizationMemberships.ReadWithOptions(ctx, om.ID, tfe.OrganizationMembershipReadOptions{ + Include: []tfe.OrgMembershipIncludeOpt{tfe.OrgMembershipUser}, + }) + if err != nil { + return nil, fmt.Errorf("failed to fetch organization membership details for membership %s in organization %s: %w", om.ID, om.Organization.Name, err) } - } - return nonServiceAccountUserIDSet, nil + if !organizationMembershipDetails.User.IsServiceAccount { + nonServiceAccountMemberships = append(nonServiceAccountMemberships, *organizationMembershipDetails) + } + } + return nonServiceAccountMemberships, nil } func fetchExistingTeamMembershipIds(config *tfe.Client, teamID string) (map[string]interface{}, error) { @@ -134,17 +133,14 @@ func fetchExistingTeamMembershipIds(config *tfe.Client, teamID string) (map[stri return nil, fmt.Errorf("failed to fetch existing organization memberships for team %s: %w", teamID, err) } - nonServiceAccountUserIds, err := fetchNonServiceAccountUserIds(config, teamID) + nonServiceAccountOrganizationMemberships, err := filterNonServiceAccountOrganizationMembers(config, teamMembers) if err != nil { return nil, err } teamMembersIDSet := make(map[string]interface{}) - for _, m := range teamMembers { - // Service accounts should not be managed by this resource - if _, ok := nonServiceAccountUserIds[m.User.ID]; ok { - teamMembersIDSet[m.ID] = nil - } + for _, m := range nonServiceAccountOrganizationMemberships { + teamMembersIDSet[m.ID] = nil } return teamMembersIDSet, nil @@ -228,7 +224,7 @@ func resourceTFETeamOrganizationMembersDelete(d *schema.ResourceData, meta inter return fmt.Errorf("Error reading organization memberships from team %s: %w", d.Id(), err) } - nonServiceAccountUserIds, err := fetchNonServiceAccountUserIds(config.Client, d.Id()) + nonServiceAccountOrganizationMemberships, err := filterNonServiceAccountOrganizationMembers(config.Client, organizationMemberships) if err != nil { return fmt.Errorf("Error fetching account user IDs for team %s: %w", d.Id(), err) } @@ -237,11 +233,8 @@ func resourceTFETeamOrganizationMembersDelete(d *schema.ResourceData, meta inter options := tfe.TeamMemberRemoveOptions{} // Add all the users that need to be removed. - for _, m := range organizationMemberships { - // Service accounts should not be managed by this resource - if _, ok := nonServiceAccountUserIds[m.User.ID]; ok { - options.OrganizationMembershipIDs = append(options.OrganizationMembershipIDs, m.ID) - } + for _, m := range nonServiceAccountOrganizationMemberships { + options.OrganizationMembershipIDs = append(options.OrganizationMembershipIDs, m.ID) } log.Printf("[DEBUG] Remove organization memberships %v from team: %s", options.OrganizationMembershipIDs, d.Id())