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

DS okta_user and okta_users bug fixes and improvements #1159

Merged
merged 3 commits into from
Jun 9, 2022
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
4 changes: 4 additions & 0 deletions examples/okta_user/datasource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ data "okta_user" "compound_search" {
value = okta_user.other.last_name
}

delay_read_seconds = 2

depends_on = [
okta_user.test,
okta_user.other
Expand All @@ -112,6 +114,8 @@ data "okta_user" "expression_search" {
expression = "profile.array123 eq \"feature\" and (created gt \"2021-01-01T00:00:00.000Z\")"
}

delay_read_seconds = 2

depends_on = [
okta_user.test,
okta_user.other
Expand Down
41 changes: 27 additions & 14 deletions okta/data_source_okta_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package okta
import (
"context"
"fmt"
"strconv"
"strings"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand Down Expand Up @@ -77,11 +79,26 @@ func dataSourceUser() *schema.Resource {
ValidateDiagFunc: elemInSlice([]string{"and", "or"}),
Description: "Search operator used when joining mulitple search clauses",
},
"delay_read_seconds": {
Type: schema.TypeString,
Optional: true,
Description: "Force delay of the user read by N seconds. Useful when eventual consistency of user information needs to be allowed for.",
},
}),
}
}

func dataSourceUserRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
if n, ok := d.GetOk("delay_read_seconds"); ok {
delay, err := strconv.Atoi(n.(string))
if err == nil {
logger(m).Info("delaying user read by ", delay, " seconds")
time.Sleep(time.Duration(delay) * time.Second)
} else {
logger(m).Warn("user read delay value ", n, " is not an integer")
}
}

client := getOktaClientFromMetadata(m)
var user *okta.User
var err error
Expand Down Expand Up @@ -112,25 +129,21 @@ func dataSourceUserRead(ctx context.Context, d *schema.ResourceData, m interface
return diag.Errorf("failed to set user's properties: %v", err)
}

skip := false
if val := d.Get("skip_roles"); val != nil {
skip = val.(bool)
}
if !skip {
err = setAdminRoles(ctx, d, m)
if err != nil {
return diag.Errorf("failed to set user's admin roles: %v", err)
if skip, ok := val.(bool); ok && !skip {
err = setAdminRoles(ctx, d, m)
if err != nil {
return diag.Errorf("failed to set user's admin roles: %v", err)
}
}
}

skip = false
if val := d.Get("skip_groups"); val != nil {
skip = val.(bool)
}
if !skip {
err = setAllGroups(ctx, d, client)
if err != nil {
return diag.Errorf("failed to set user's groups: %v", err)
if skip, ok := val.(bool); ok && !skip {
err = setAllGroups(ctx, d, client)
if err != nil {
return diag.Errorf("failed to set user's groups: %v", err)
}
}
}

Expand Down
147 changes: 143 additions & 4 deletions okta/data_source_okta_user_test.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
package okta

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccOktaDataSourceUser_read(t *testing.T) {
func TestAccDataSourceOktaUser_read(t *testing.T) {
ri := acctest.RandInt()
mgr := newFixtureManager(user)
baseConfig := mgr.GetFixtures("datasource.tf", ri, t)
createUserConfig := mgr.GetFixtures("datasource_create_user.tf", ri, t)

// NOTE: The ACC tests on the datasource.tf can flap as sometimes these
// tests can run faster than the Okta org becoming eventually consistent.
//
// NOTE: eliminated previous flapping issues when delay_read_seconds was added to okta_user
// TF_ACC=1 go test -tags unit -mod=readonly -test.v -run ^TestAccOktaDataSourceUser_read$
resource.Test(t, resource.TestCase{
PreCheck: func() {
Expand Down Expand Up @@ -62,3 +62,142 @@ func TestAccOktaDataSourceUser_read(t *testing.T) {
},
})
}

// TestAccDataSourceOktaUser_SkipAdminRoles pertains to https://github.com/okta/terraform-provider-okta/pull/1137 and https://github.com/okta/terraform-provider-okta/issues/1014
func TestAccDataSourceOktaUser_SkipAdminRoles(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
ProviderFactories: testAccProvidersFactories,
Steps: []resource.TestStep{
{
Config: testOktaUserRolesGroupsConfig(false, true),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.okta_user.test", "admin_roles.#", "0"), // skipped
resource.TestCheckResourceAttr("data.okta_user.test", "group_memberships.#", "2"), // Everyone, A Group
),
},
},
})
}

// TestAccDataSourceOktaUser_SkipGroups pertains to https://github.com/okta/terraform-provider-okta/pull/1137 and https://github.com/okta/terraform-provider-okta/issues/1014
func TestAccDataSourceOktaUser_SkipGroups(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
ProviderFactories: testAccProvidersFactories,
Steps: []resource.TestStep{
{
Config: testOktaUserRolesGroupsConfig(true, false),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.okta_user.test", "admin_roles.#", "2"), // SUPER_ADMIN, APP_ADMIN
resource.TestCheckResourceAttr("data.okta_user.test", "group_memberships.#", "0"), // skipped
),
},
},
})
}

// TestAccDataSourceOktaUser_SkipGroupsSkipRoles pertains to https://github.com/okta/terraform-provider-okta/pull/1137 and https://github.com/okta/terraform-provider-okta/issues/1014
func TestAccDataSourceOktaUser_SkipGroupsSkipRoles(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
ProviderFactories: testAccProvidersFactories,
Steps: []resource.TestStep{
{
Config: testOktaUserRolesGroupsConfig(true, true),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.okta_user.test", "admin_roles.#", "0"), // skipped
resource.TestCheckResourceAttr("data.okta_user.test", "group_memberships.#", "0"), // skipped
),
},
},
})
}

// TestAccDataSourceOktaUser_NoSkips pertains to https://github.com/okta/terraform-provider-okta/pull/1137 and https://github.com/okta/terraform-provider-okta/issues/1014
func TestAccDataSourceOktaUser_NoSkips(t *testing.T) {
allAdminRolesRegexp, _ := regexp.Compile("APP_ADMIN, SUPER_ADMIN")
allGroupMembershipsRegexp, _ := regexp.Compile("00g[a-z,A-Z,0-9]{17}, 00g[a-z,A-Z,0-9]{17}")
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
ProviderFactories: testAccProvidersFactories,
Steps: []resource.TestStep{
{
Config: testOktaUserRolesGroupsConfig(false, false),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.okta_user.test", "admin_roles.#", "2"), // SUPER_ADMIN, APP_ADMIN
resource.TestCheckResourceAttr("data.okta_user.test", "group_memberships.#", "2"), // Everyone, A Group
resource.TestMatchOutput("output_admin_roles", allAdminRolesRegexp),
resource.TestMatchOutput("output_group_memberships", allGroupMembershipsRegexp),
),
},
},
})
}

func testOktaUserRolesGroupsConfig(skipGroups, skipRoles bool) string {
prepend := `

resource "okta_group" "test" {
name = "Example"
description = "A Group"
}
resource "okta_user" "test" {
first_name = "TestAcc"
last_name = "Smith"
login = "[email protected]"
email = "[email protected]"
lifecycle {
ignore_changes = [admin_roles]
}
}
resource "okta_user_admin_roles" "test" {
user_id = okta_user.test.id
admin_roles = [
"SUPER_ADMIN",
"APP_ADMIN",
]
}
resource "okta_user_group_memberships" "test" {
user_id = okta_user.test.id
groups = [
okta_group.test.id,
]
}
data "okta_user" "test" {
user_id = okta_user.test.id
`

var clause string
if skipGroups {
clause = " skip_groups = true"
}
if skipRoles {
clause = fmt.Sprintf("%s\n skip_roles = true\n", clause)
}

append := `
depends_on = [
okta_user_admin_roles.test,
okta_user_admin_roles.test,
okta_user_group_memberships.test,
]
}
output "output_admin_roles" {
value = join(", ", data.okta_user.test.admin_roles)
}
output "output_group_memberships" {
value = join(", ", data.okta_user.test.group_memberships)
}
`

return fmt.Sprintf("%s%s%s", prepend, clause, append)
}
36 changes: 34 additions & 2 deletions okta/data_source_okta_users.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"fmt"
"hash/crc32"
"strconv"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand All @@ -27,6 +29,12 @@ func dataSourceUsers() *schema.Resource {
Default: false,
Description: "Fetch group memberships for each user",
},
"include_roles": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Fetch user roles for each user",
},
"search": {
Type: schema.TypeSet,
Optional: true,
Expand Down Expand Up @@ -56,11 +64,26 @@ func dataSourceUsers() *schema.Resource {
ValidateDiagFunc: elemInSlice([]string{"and", "or"}),
Description: "Search operator used when joining mulitple search clauses",
},
"delay_read_seconds": {
Type: schema.TypeString,
Optional: true,
Description: "Force delay of the users read by N seconds. Useful when eventual consistency of users information needs to be allowed for.",
},
},
}
}

func dataSourceUsersRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
if n, ok := d.GetOk("delay_read_seconds"); ok {
delay, err := strconv.Atoi(n.(string))
if err == nil {
logger(m).Info("delaying users read by ", delay, " seconds")
time.Sleep(time.Duration(delay) * time.Second)
} else {
logger(m).Warn("users read delay value ", n, " is not an integer")
}
}

var (
users []*okta.User
id string
Expand All @@ -84,20 +107,29 @@ func dataSourceUsersRead(ctx context.Context, d *schema.ResourceData, m interfac
return diag.Errorf("failed to list users: %v", err)
}
d.SetId(id)
shouldGetGroups := d.Get("include_groups").(bool)
includeGroups := d.Get("include_groups").(bool)
includeRoles := d.Get("include_roles").(bool)
arr := make([]map[string]interface{}, len(users))
for i, user := range users {
rawMap := flattenUser(user)
rawMap["id"] = user.Id
if shouldGetGroups {
if includeGroups {
groups, err := getGroupsForUser(ctx, user.Id, client)
if err != nil {
return diag.Errorf("failed to list users: %v", err)
}
rawMap["group_memberships"] = groups
}
if includeRoles {
roles, err := getAdminRoles(ctx, user.Id, client)
if err != nil {
return diag.Errorf("failed to set user's admin roles: %v", err)
}
rawMap["admin_roles"] = roles
}
arr[i] = rawMap
}

_ = d.Set("users", arr)
return nil
}
Expand Down
Loading