Skip to content

Commit bef060e

Browse files
committed
feat: adds basic realm support
1 parent b437c78 commit bef060e

13 files changed

Lines changed: 500 additions & 0 deletions
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
data "okta_realm" "example_name" {
2+
name = "Example Realm"
3+
}
4+
5+
data "okta_realm" "example_id" {
6+
id = "<realm_id>"
7+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
resource "okta_realm" "test" {
2+
name = "AccTest Example Realm"
3+
realm_type = "DEFAULT"
4+
}
5+
6+
data "okta_realm" "test" {
7+
name = "AccTest Example Realm"
8+
depends_on = [okta_realm.test]
9+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Should fail to find the realm doesn't exist
2+
data "okta_realm" "test_not_found" {
3+
name = "Unknown Example Realm"
4+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# okta_realm
2+
3+
Represents an Okta
4+
Realm. [See Okta documentation for more details](https://developer.okta.com/docs/api/openapi/okta-management/management/tag/Realm/).
5+
6+
- Example of a simple realm [can be found here](./resource.tf)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
terraform import okta_realm.example <realm_id>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
resource "okta_realm" "example" {
2+
name = "TestAcc Example Realm"
3+
realm_type = "DEFAULT"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
resource "okta_realm" "example" {
2+
name = "TestAcc Example Realm Updated"
3+
realm_type = "PARTNER"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
resource "okta_realm" "example" {
2+
name = "Example Realm"
3+
realm_type = "DEFAULT"
4+
}

okta/data_source_okta_realm.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package okta
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io"
7+
"time"
8+
9+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
10+
"github.com/hashicorp/terraform-plugin-framework/datasource"
11+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
12+
"github.com/hashicorp/terraform-plugin-framework/path"
13+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
14+
"github.com/hashicorp/terraform-plugin-framework/types"
15+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
16+
"github.com/okta/okta-sdk-golang/v5/okta"
17+
)
18+
19+
type realmDataSource struct {
20+
config *Config
21+
}
22+
23+
func NewRealmDataSource() datasource.DataSource {
24+
return &realmDataSource{}
25+
}
26+
27+
func (r *realmDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
28+
resp.TypeName = req.ProviderTypeName + "_realm"
29+
}
30+
31+
func (r *realmDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
32+
r.config = dataSourceConfiguration(req, resp)
33+
}
34+
35+
func (r *realmDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
36+
resp.Schema = schema.Schema{
37+
Attributes: map[string]schema.Attribute{
38+
"id": schema.StringAttribute{
39+
Computed: true,
40+
Optional: true,
41+
Description: "The id of the Okta Realm.",
42+
Validators: []validator.String{
43+
stringvalidator.ConflictsWith(path.Expressions{
44+
path.MatchRoot("name"),
45+
}...),
46+
},
47+
},
48+
"name": schema.StringAttribute{
49+
Computed: true,
50+
Optional: true,
51+
Description: "The name of the Okta Realm.",
52+
Validators: []validator.String{
53+
stringvalidator.ConflictsWith(path.Expressions{
54+
path.MatchRoot("id"),
55+
}...),
56+
},
57+
},
58+
"realm_type": schema.StringAttribute{
59+
Optional: true,
60+
Description: "The realm type. Valid values: `PARTNER` and `DEFAULT`",
61+
},
62+
"is_default": schema.BoolAttribute{
63+
Computed: true,
64+
Description: "Indicates whether the realm is the default realm.",
65+
},
66+
},
67+
Description: "Get a realm from Okta.",
68+
}
69+
}
70+
71+
func (r *realmDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
72+
var state realmModel
73+
resp.Diagnostics.Append(req.Config.Get(ctx, &state)...)
74+
if resp.Diagnostics.HasError() {
75+
return
76+
}
77+
78+
var selectedRealm *okta.Realm
79+
if state.ID.ValueString() != "" {
80+
realm, response, err := r.config.oktaSDKClientV5.RealmAPI.GetRealm(ctx, state.ID.ValueString()).Execute()
81+
if err != nil {
82+
body, ioErr := io.ReadAll(response.Body)
83+
defer response.Body.Close()
84+
if ioErr != nil {
85+
resp.Diagnostics.AddError(err.Error(), "failed to read response body")
86+
return
87+
}
88+
resp.Diagnostics.AddError("failed to read realm:"+err.Error(), string(body))
89+
return
90+
}
91+
selectedRealm = realm
92+
} else if state.Name.ValueString() != "" {
93+
searchString := fmt.Sprintf(`profile.name eq "%s"`, state.Name.ValueString())
94+
95+
err := retry.RetryContext(ctx, 3*time.Second, func() *retry.RetryError {
96+
realms, response, err := r.config.oktaSDKClientV5.RealmAPI.ListRealms(ctx).Search(searchString).Execute()
97+
if err != nil {
98+
body, ioErr := io.ReadAll(response.Body)
99+
defer response.Body.Close()
100+
if ioErr != nil {
101+
resp.Diagnostics.AddError(err.Error(), "failed to read response body")
102+
return retry.NonRetryableError(ioErr)
103+
}
104+
resp.Diagnostics.AddError("failed to list realms:"+err.Error(), string(body))
105+
return retry.NonRetryableError(err)
106+
}
107+
108+
if len(realms) == 0 {
109+
resp.Diagnostics.AddWarning("Realm not found", fmt.Sprintf("No realm found with name %s. Retrying...", state.Name.ValueString()))
110+
return retry.RetryableError(fmt.Errorf("no realm found with name %s", state.Name.ValueString()))
111+
}
112+
113+
if len(realms) != 1 {
114+
resp.Diagnostics.AddError("Multiple realms found", fmt.Sprintf("Found %d realms with name %s. Please specify a unique name.", len(realms), state.Name.ValueString()))
115+
return retry.NonRetryableError(fmt.Errorf("multiple realms found"))
116+
}
117+
118+
selectedRealm = &realms[0]
119+
return nil
120+
})
121+
if err != nil {
122+
resp.Diagnostics.AddError(fmt.Sprintf("Realm with name %s not found", state.Name), "Please check the name and try again.")
123+
return
124+
}
125+
126+
} else {
127+
resp.Diagnostics.AddError("Error reading realm", "Either 'id' or 'name' must be specified.")
128+
return
129+
}
130+
131+
state.ID = types.StringPointerValue(selectedRealm.Id)
132+
state.Name = types.StringValue(selectedRealm.Profile.Name)
133+
state.RealmType = types.StringPointerValue(selectedRealm.Profile.RealmType)
134+
state.IsDefault = types.BoolPointerValue(selectedRealm.IsDefault)
135+
136+
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
137+
if resp.Diagnostics.HasError() {
138+
return
139+
}
140+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package okta
2+
3+
import (
4+
"regexp"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8+
)
9+
10+
func TestAccDataSourceOktaRealm_read(t *testing.T) {
11+
mgr := newFixtureManager("data-sources", realm, t.Name())
12+
config := mgr.GetFixtures("datasource.tf", t)
13+
configInvalid := mgr.GetFixtures("datasource_not_found.tf", t)
14+
15+
oktaResourceTest(t, resource.TestCase{
16+
PreCheck: testAccPreCheck(t),
17+
ErrorCheck: testAccErrorChecks(t),
18+
ProtoV5ProviderFactories: testAccMergeProvidersFactories,
19+
Steps: []resource.TestStep{
20+
{
21+
Config: config,
22+
Check: resource.ComposeTestCheckFunc(
23+
resource.TestCheckResourceAttrSet("data.okta_realm.test", "id"),
24+
resource.TestCheckResourceAttr("data.okta_realm.test", "name", "AccTest Example Realm"),
25+
resource.TestCheckResourceAttr("data.okta_realm.test", "realm_type", "DEFAULT"),
26+
),
27+
},
28+
{
29+
Config: configInvalid,
30+
ExpectError: regexp.MustCompile(`Realm with name "Unknown Example Realm" not found`),
31+
},
32+
},
33+
})
34+
}

0 commit comments

Comments
 (0)