Skip to content

Commit

Permalink
Merge pull request #1617 from okta/steveAG_okta_group_rule
Browse files Browse the repository at this point in the history
@steveAG okta_group_rule data source
  • Loading branch information
MikeMondragon-okta authored Jun 29, 2023
2 parents 3ca4832 + 14bf799 commit 11ce3ff
Show file tree
Hide file tree
Showing 8 changed files with 1,488 additions and 0 deletions.
24 changes: 24 additions & 0 deletions examples/okta_group_rule/datasource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
resource "okta_group" "test" {
name = "testAcc_replace_with_uuid"
}

resource "okta_group_rule" "test" {
name = "testAcc_replace_with_uuid"
status = "ACTIVE"
group_assignments = [okta_group.test.id]
expression_type = "urn:okta:expression:1.0"
expression_value = "String.startsWith(user.firstName,\"andy\")"
}

# This example is for syntax purposes only. If it was actually run
# data.okta_group_rule.test_by_id would fail because okta_group_rule.test
# wouldn't be in the search index yet. The data source implementation relies on
# a group rule search function in the Okta API

data "okta_group_rule" "test_by_id" {
id = okta_group_rule.test.id
}

data "okta_group_rule" "test_by_name" {
name = "testAcc_replace_with_uuid"
}
100 changes: 100 additions & 0 deletions okta/data_source_okta_group_rule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package okta

import (
"context"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/okta/terraform-provider-okta/sdk"
"github.com/okta/terraform-provider-okta/sdk/query"
)

func dataSourceGroupRule() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceGroupRuleRead,
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Optional: true,
ConflictsWith: []string{"name"},
},
"name": {
Type: schema.TypeString,
Optional: true,
},
"group_assignments": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"expression_type": {
Type: schema.TypeString,
Computed: true,
},
"expression_value": {
Type: schema.TypeString,
Computed: true,
},
"status": statusSchema,
"users_excluded": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
}
}

func dataSourceGroupRuleRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
var rule *sdk.GroupRule
ruleID, idOk := d.GetOk("id")
if idOk {
respRule, _, err := getOktaClientFromMetadata(m).Group.GetGroupRule(ctx, ruleID.(string), nil)
if err != nil {
return diag.Errorf("failed get group rule by ID: %v", err)
}
rule = respRule
} else {
ruleName, nameOk := d.GetOk("name")
if nameOk {
var name = ruleName.(string)
searchParams := &query.Params{Search: name, Limit: 1}
rules, _, err := getOktaClientFromMetadata(m).Group.ListGroupRules(ctx, searchParams)
switch {
case err != nil:
return diag.Errorf("failed to get group rule by name: %v", err)
case len(rules) < 1:
return diag.Errorf("group rule with name '%s' does not exist", name)
}
// exact name search should only return one result, but loop through to be safe
for _, ruleCandidate := range rules {
if ruleName == ruleCandidate.Name {
rule = ruleCandidate
break
}
}
}
}

if rule == nil {
return diag.Errorf("config must provide 'name' or 'id' to retrieve a group rule")
}

d.SetId(rule.Id)
_ = d.Set("name", rule.Name)
_ = d.Set("status", rule.Status)
if rule.Conditions != nil {
_ = d.Set("expression_type", rule.Conditions.Expression.Type)
_ = d.Set("expression_value", rule.Conditions.Expression.Value)
}
if rule.Conditions.People != nil && rule.Conditions.People.Users != nil {
_ = d.Set("users_excluded", convertStringSliceToSet(rule.Conditions.People.Users.Exclude))
}
err := setNonPrimitives(d, map[string]interface{}{
"group_assignments": convertStringSliceToSet(rule.Actions.AssignUserToGroups.GroupIds),
})
if err != nil {
return diag.Errorf("failed to set group rule properties: %v", err)
}
return nil
}
73 changes: 73 additions & 0 deletions okta/data_source_okta_group_rule_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package okta

import (
"fmt"
"testing"

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

func TestAccOktaDataSourceGroupRule_read(t *testing.T) {
mgr := newFixtureManager(groupRule, t.Name())
step1config := groupAndRule
step2config := fmt.Sprintf("%s%s", groupAndRule, groupRuleDataSources)

oktaResourceTest(t, resource.TestCase{
PreCheck: testAccPreCheck(t),
ErrorCheck: testAccErrorChecks(t),
ProviderFactories: testAccProvidersFactories,
Steps: []resource.TestStep{
{
Config: mgr.ConfigReplace(step1config),
},
{
Config: mgr.ConfigReplace(step2config),
Check: resource.ComposeTestCheckFunc(
// hack for eventual consistency on the group rule creation on Okta API side
sleepInSecondsForTest(2),

resource.TestCheckResourceAttrSet("data.okta_group_rule.test_by_id", "id"),
resource.TestCheckResourceAttr("data.okta_group_rule.test_by_id", "name", fmt.Sprintf("testAccTwo_%d", mgr.Seed)),
resource.TestCheckResourceAttr("data.okta_group_rule.test_by_id", "status", "ACTIVE"),

resource.TestCheckResourceAttrSet("data.okta_group_rule.test_by_name", "id"),
resource.TestCheckResourceAttr("data.okta_group_rule.test_by_name", "name", fmt.Sprintf("testAccTwo_%d", mgr.Seed)),
resource.TestCheckResourceAttr("data.okta_group_rule.test_by_name", "status", "ACTIVE"),
),
},
},
})
}

const groupAndRule = `
resource "okta_group" "test" {
name = "testAcc_replace_with_uuid"
}
resource "okta_group_rule" "test1" {
name = "testAccOne_replace_with_uuid"
status = "ACTIVE"
group_assignments = [okta_group.test.id]
expression_type = "urn:okta:expression:1.0"
expression_value = "String.startsWith(user.firstName,\"andy\")"
}
resource "okta_group_rule" "test2" {
name = "testAccTwo_replace_with_uuid"
status = "ACTIVE"
group_assignments = [okta_group.test.id]
expression_type = "urn:okta:expression:1.0"
expression_value = "String.startsWith(user.firstName,\"andy\")"
depends_on = [okta_group_rule.test1]
}
`

const groupRuleDataSources = `
data "okta_group_rule" "test_by_id" {
id = okta_group_rule.test2.id
}
data "okta_group_rule" "test_by_name" {
name = "testAccTwo_replace_with_uuid"
}
`
1 change: 1 addition & 0 deletions okta/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ func Provider() *schema.Provider {
defaultPolicy: dataSourceDefaultPolicy(),
group: dataSourceGroup(),
groupEveryone: dataSourceEveryoneGroup(),
groupRule: dataSourceGroupRule(),
groups: dataSourceGroups(),
idpMetadataSaml: dataSourceIdpMetadataSaml(),
idpOidc: dataSourceIdpOidc(),
Expand Down
10 changes: 10 additions & 0 deletions okta/utils_for_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"
"strings"
"testing"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
Expand Down Expand Up @@ -204,3 +205,12 @@ func testAttributeJSON(name, attribute, expectedJSON string) resource.TestCheckF
return nil
}
}

// sleepInSecondsForTest Add sleep in a test to allow for eventual consistency
// thanks github.com/hashicorp/terraform-provider-google/google/provider_test.go
func sleepInSecondsForTest(t int) resource.TestCheckFunc {
return func(s *terraform.State) error {
time.Sleep(time.Duration(t) * time.Second)
return nil
}
}
Loading

0 comments on commit 11ce3ff

Please sign in to comment.