-
Notifications
You must be signed in to change notification settings - Fork 207
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
15f311f
commit 920bfbe
Showing
7 changed files
with
359 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
resource "okta_domain" "test" { | ||
name = "example.com" | ||
verify = false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
package okta | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
"github.com/okta/terraform-provider-okta/sdk" | ||
) | ||
|
||
func resourceDomain() *schema.Resource { | ||
return &schema.Resource{ | ||
CreateContext: resourceDomainCreate, | ||
ReadContext: resourceDomainRead, | ||
UpdateContext: resourceDomainUpdate, | ||
DeleteContext: resourceDomainDelete, | ||
Importer: &schema.ResourceImporter{ | ||
StateContext: schema.ImportStatePassthroughContext, | ||
}, | ||
Schema: map[string]*schema.Schema{ | ||
"name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "Custom Domain name", | ||
ForceNew: true, | ||
}, | ||
"verify": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
Description: "Indicates whether the domain should be verified during creation", | ||
Default: false, | ||
}, | ||
"validation_status": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "Status of the domain", | ||
}, | ||
"dns_records": { | ||
Type: schema.TypeList, | ||
Computed: true, | ||
Description: "TXT and CNAME records to be registered for the Domain", | ||
Elem: &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"expiration": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "TXT record expiration", | ||
}, | ||
"fqdn": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "DNS record name", | ||
}, | ||
"record_type": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Description: "Record type can be TXT or CNAME", | ||
}, | ||
"values": { | ||
Type: schema.TypeList, | ||
Computed: true, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
Description: "DNS verification value", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceDomainCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { | ||
domain, _, err := getSupplementFromMetadata(m).CreateDomain(ctx, buildDomain(d)) | ||
if err != nil { | ||
return diag.Errorf("failed to create domain: %v", err) | ||
} | ||
d.SetId(domain.ID) | ||
if d.Get("verify").(bool) { | ||
_, _, err := getSupplementFromMetadata(m).VerifyDomain(ctx, domain.ID) | ||
if err != nil { | ||
return diag.Errorf("failed to verify domain: %v", err) | ||
} | ||
} | ||
return resourceDomainRead(ctx, d, m) | ||
} | ||
|
||
func resourceDomainRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { | ||
domain, resp, err := getSupplementFromMetadata(m).GetDomain(ctx, d.Id()) | ||
if err := suppressErrorOn404(resp, err); err != nil { | ||
return diag.Errorf("failed to get domain: %v", err) | ||
} | ||
if domain == nil { | ||
d.SetId("") | ||
return nil | ||
} | ||
vd, err := validateDomain(ctx, d, m, domain.ValidationStatus) | ||
if err != nil { | ||
return diag.FromErr(err) | ||
} | ||
if vd != nil { | ||
_ = d.Set("validation_status", vd.ValidationStatus) | ||
} else { | ||
_ = d.Set("validation_status", domain.ValidationStatus) | ||
} | ||
arr := make([]map[string]interface{}, len(domain.DNSRecords)) | ||
for i := range domain.DNSRecords { | ||
arr[i] = map[string]interface{}{ | ||
"expiration": domain.DNSRecords[i].Expiration, | ||
"fqdn": domain.DNSRecords[i].Fqdn, | ||
"record_type": domain.DNSRecords[i].RecordType, | ||
"values": convertStringArrToInterface(domain.DNSRecords[i].Values), | ||
} | ||
} | ||
err = setNonPrimitives(d, map[string]interface{}{"dns_records": arr}) | ||
if err != nil { | ||
return diag.Errorf("failed to set OAuth application properties: %v", err) | ||
} | ||
if domain.ValidationStatus == "IN_PROGRESS" || domain.ValidationStatus == "VERIFIED" || domain.ValidationStatus == "COMPLETED" { | ||
return nil | ||
} | ||
if d.Get("verify").(bool) { | ||
_, _, err := getSupplementFromMetadata(m).VerifyDomain(ctx, d.Id()) | ||
if err != nil { | ||
return diag.Errorf("failed to verify domain: %v", err) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceDomainDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { | ||
logger(m).Info("deleting domain", "id", d.Id()) | ||
_, err := getSupplementFromMetadata(m).DeleteDomain(ctx, d.Id()) | ||
if err != nil { | ||
return diag.Errorf("failed to delete domain: %v", err) | ||
} | ||
return nil | ||
} | ||
|
||
func resourceDomainUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { | ||
_, err := validateDomain(ctx, d, m, d.Get("validation_status").(string)) | ||
if err != nil { | ||
return diag.FromErr(err) | ||
} | ||
return resourceDomainRead(ctx, d, m) | ||
} | ||
|
||
func validateDomain(ctx context.Context, d *schema.ResourceData, m interface{}, validationStatus string) (*sdk.Domain, error) { | ||
if validationStatus == "IN_PROGRESS" || validationStatus == "VERIFIED" || validationStatus == "COMPLETED" { | ||
return nil, nil | ||
} | ||
if !d.Get("verify").(bool) { | ||
return nil, nil | ||
} | ||
domain, _, err := getSupplementFromMetadata(m).VerifyDomain(ctx, d.Id()) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to verify domain: %v", err) | ||
} | ||
return domain, nil | ||
} | ||
|
||
func buildDomain(d *schema.ResourceData) sdk.Domain { | ||
return sdk.Domain{ | ||
Domain: d.Get("name").(string), | ||
CertificateSourceType: "MANUAL", | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package okta | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
) | ||
|
||
func TestAccOktaDomain(t *testing.T) { | ||
ri := acctest.RandInt() | ||
mgr := newFixtureManager(domain) | ||
config := mgr.GetFixtures("basic.tf", ri, t) | ||
resourceName := fmt.Sprintf("%s.test", domain) | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
ProviderFactories: testAccProvidersFactories, | ||
CheckDestroy: createCheckResourceDestroy(domain, domainExists), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: config, | ||
Check: resource.ComposeTestCheckFunc( | ||
ensureResourceExists(resourceName, domainExists), | ||
resource.TestCheckResourceAttr(resourceName, "name", "example.com"), | ||
resource.TestCheckResourceAttr(resourceName, "dns_records.#", "2"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func domainExists(id string) (bool, error) { | ||
domain, resp, err := getSupplementFromMetadata(testAccProvider.Meta()).GetDomain(context.Background(), id) | ||
if err := suppressErrorOn404(resp, err); err != nil { | ||
return false, err | ||
} | ||
return domain != nil, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package sdk | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
"time" | ||
|
||
"github.com/okta/okta-sdk-golang/v2/okta" | ||
) | ||
|
||
type Domain struct { | ||
ID string `json:"id,omitempty"` | ||
Domain string `json:"domain"` | ||
CertificateSourceType string `json:"certificateSourceType"` | ||
ValidationStatus string `json:"validationStatus,omitempty"` | ||
DNSRecords []struct { | ||
Expiration string `json:"expiration",omitempty"` | ||
Fqdn string `json:"fqdn,omitempty"` | ||
Values []string `json:"values,omitempty"` | ||
RecordType string `json:"recordType,omitempty"` | ||
} `json:"dnsRecords,omitempty"` | ||
PublicCertificate struct { | ||
Subject string `json:"subject,omitempty"` | ||
Fingerprint string `json:"fingerprint,omitempty"` | ||
Expiration time.Time `json:"expiration,omitempty"` | ||
} `json:"publicCertificate,omitempty"` | ||
} | ||
|
||
type Certificate struct { | ||
Type string `json:"type"` | ||
PrivateKey string `json:"privateKey"` | ||
Certificate string `json:"certificate"` | ||
CertificateChain string `json:"certificateChain,omitempty"` | ||
} | ||
|
||
func (m *ApiSupplement) CreateDomain(ctx context.Context, body Domain) (*Domain, *okta.Response, error) { | ||
url := "/api/v1/domains" | ||
req, err := m.RequestExecutor. | ||
WithAccept("application/json"). | ||
WithContentType("application/json"). | ||
NewRequest(http.MethodPost, url, body) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
var domain Domain | ||
resp, err := m.RequestExecutor.Do(ctx, req, &domain) | ||
if err != nil { | ||
return nil, resp, err | ||
} | ||
return &domain, resp, nil | ||
} | ||
|
||
func (m *ApiSupplement) VerifyDomain(ctx context.Context, id string) (*Domain, *okta.Response, error) { | ||
url := fmt.Sprintf("/api/v1/domains/%s/verify", id) | ||
req, err := m.RequestExecutor.NewRequest(http.MethodPost, url, nil) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
var domain Domain | ||
resp, err := m.RequestExecutor.Do(ctx, req, &domain) | ||
if err != nil { | ||
return nil, resp, err | ||
} | ||
return &domain, resp, nil | ||
} | ||
|
||
func (m *ApiSupplement) GetDomain(ctx context.Context, id string) (*Domain, *okta.Response, error) { | ||
url := fmt.Sprintf("/api/v1/domains/%v", id) | ||
req, err := m.RequestExecutor.NewRequest(http.MethodGet, url, nil) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
var domain Domain | ||
resp, err := m.RequestExecutor.Do(ctx, req, &domain) | ||
if err != nil { | ||
return nil, resp, err | ||
} | ||
return &domain, resp, nil | ||
} | ||
|
||
func (m *ApiSupplement) DeleteDomain(ctx context.Context, id string) (*okta.Response, error) { | ||
url := fmt.Sprintf("/api/v1/domains/%v", id) | ||
req, err := m.RequestExecutor.NewRequest("DELETE", url, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
resp, err := m.RequestExecutor.Do(ctx, req, nil) | ||
if err != nil { | ||
return resp, err | ||
} | ||
return resp, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
--- | ||
layout: 'okta' | ||
page_title: 'Okta: okta_domain' | ||
sidebar_current: 'docs-okta-resource-domain' | ||
description: |- | ||
Manages custom domain for your organization. | ||
--- | ||
|
||
# okta_domain | ||
|
||
Manages custom domain for your organization. | ||
|
||
## Example Usage | ||
|
||
```hcl | ||
resource "okta_domain" "example" { | ||
name = "www.example.com" | ||
verify = true | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
- `name` - (Required) Custom Domain name. | ||
|
||
- `verify` - (Optional) Indicates whether the domain should be verified. | ||
|
||
## Attributes Reference | ||
|
||
- `id` - Domain ID | ||
|
||
- `validation_status` - Status of the domain. | ||
|
||
- `dns_records` - TXT and CNAME records to be registered for the Domain. | ||
- `expiration` - TXT record expiration. | ||
- `fqdn` - DNS record name. | ||
- `record_type` - Record type can be TXT or CNAME. | ||
- `values` - DNS verification value | ||
|
||
## Import | ||
|
||
Okta Admin Role Targets can be imported via the Okta ID. | ||
|
||
``` | ||
$ terraform import okta_domain.example <domain_id> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters