diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fdcfae5..93e6fa23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ FEATURES: - **New Resource:** `dnsimple_registered_domain_contact` (dnsimple/terraform-provider-dnsimple#142) - **New Data Source:** `dnsimple_registrant_change_check` (dnsimple/terraform-provider-dnsimple#142) +- **Updated Resource:** `dnsimple_registered_domain` now supports `transfer_lock_enabled` argument which you can use to manage the domain transfer lock state of your registered domains (dnsimple/terraform-provider-dnsimple#143) ## 1.1.2 diff --git a/docs/resources/registered_domain.md b/docs/resources/registered_domain.md index 9d600cea..cbd75a43 100644 --- a/docs/resources/registered_domain.md +++ b/docs/resources/registered_domain.md @@ -31,6 +31,7 @@ resource "dnsimple_registered_domain" "appleseed_bio" { contact_id = dnsimple_contact.alice_main.id auto_renew_enabled = true + transfer_lock_enabled = true whois_privacy_enabled = true dnssec_enabled = false @@ -49,6 +50,7 @@ The following argument(s) are supported: * `auto_renew_enabled` - (Optional) Whether the domain should be set to auto-renew (default: `false`) * `whois_privacy_enabled` - (Optional) Whether the domain should have WhoIs privacy enabled (default: `false`) * `dnssec_enabled` - (Optional) Whether the domain should have DNSSEC enabled (default: `false`) +* `transfer_lock_enabled` - (Optional) Whether the domain transfer lock protection is enabled (default: `true`) * `premium_price` - (Optional) The premium price for the domain registration. This is only required if the domain is a premium domain. You can use our [Check domain API](https://developer.dnsimple.com/v2/registrar/#checkDomain) to check if a domain is premium. And [Retrieve domain prices API](https://developer.dnsimple.com/v2/registrar/#getDomainPrices) to retrieve the premium price for a domain. * `extended_attributes` - (Optional) A map of extended attributes to be set for the domain registration. To see if there are any required extended attributes for any TLD use our [Lists the TLD Extended Attributes API](https://developer.dnsimple.com/v2/tlds/#getTldExtendedAttributes). * `timeouts` - (Optional) (see [below for nested schema](#nestedblock--timeouts)) diff --git a/go.mod b/go.mod index daf6f5ad..d1d13858 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module github.com/terraform-providers/terraform-provider-dnsimple require ( - github.com/dnsimple/dnsimple-go v1.3.0 + github.com/dnsimple/dnsimple-go v1.4.0 github.com/hashicorp/terraform-plugin-docs v0.14.1 github.com/hashicorp/terraform-plugin-framework v1.2.0 github.com/hashicorp/terraform-plugin-go v0.15.0 diff --git a/go.sum b/go.sum index f1687e77..b74d036d 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dnsimple/dnsimple-go v1.3.0 h1:8hv9JZdfMLGUp5QIX1VndDWsMd3kY/9H3TRA7Zyyo/E= -github.com/dnsimple/dnsimple-go v1.3.0/go.mod h1:G7a16dj2TULTldjxg1EAcSxonEqx0gkTOP8PESBai+4= +github.com/dnsimple/dnsimple-go v1.4.0 h1:nBqtRXI9dYx6k6YJDlPZ1x/JuTP86KMtgbsBj6/6sMA= +github.com/dnsimple/dnsimple-go v1.4.0/go.mod h1:G7a16dj2TULTldjxg1EAcSxonEqx0gkTOP8PESBai+4= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= diff --git a/internal/framework/resources/registered_domain/common.go b/internal/framework/resources/registered_domain/common.go index 44fb60e2..e69e3ba9 100644 --- a/internal/framework/resources/registered_domain/common.go +++ b/internal/framework/resources/registered_domain/common.go @@ -103,7 +103,35 @@ func (r *RegisteredDomainResource) setDNSSEC(ctx context.Context, data *Register return diagnostics } -func (r *RegisteredDomainResource) updateModelFromAPIResponse(ctx context.Context, data *RegisteredDomainResourceModel, domainRegistration *dnsimple.DomainRegistration, domain *dnsimple.Domain, dnssec *dnsimple.Dnssec) diag.Diagnostics { +func (r *RegisteredDomainResource) setTransferLock(ctx context.Context, data *RegisteredDomainResourceModel) diag.Diagnostics { + diagnostics := diag.Diagnostics{} + + tflog.Debug(ctx, fmt.Sprintf("setting transfer_lock_enabled to %t", data.TransferLockEnabled.ValueBool())) + + if data.TransferLockEnabled.ValueBool() { + _, err := r.config.Client.Registrar.EnableDomainTransferLock(ctx, r.config.AccountID, data.Name.ValueString()) + + if err != nil { + diagnostics.AddError( + fmt.Sprintf("failed to enable DNSimple Domain transfer lock: %s, %d", data.Name.ValueString(), data.Id.ValueInt64()), + err.Error(), + ) + } + return diagnostics + } + + _, err := r.config.Client.Registrar.DisableDomainTransferLock(ctx, r.config.AccountID, data.Name.ValueString()) + if err != nil { + diagnostics.AddError( + fmt.Sprintf("failed to disable DNSimple Domain transfer lock: %s, %d", data.Name.ValueString(), data.Id.ValueInt64()), + err.Error(), + ) + } + + return diagnostics +} + +func (r *RegisteredDomainResource) updateModelFromAPIResponse(ctx context.Context, data *RegisteredDomainResourceModel, domainRegistration *dnsimple.DomainRegistration, domain *dnsimple.Domain, dnssec *dnsimple.Dnssec, transferLock *dnsimple.DomainTransferLock) diag.Diagnostics { diags := diag.Diagnostics{} if domainRegistration != nil { @@ -149,6 +177,10 @@ Until the change has completed successfully you will continue to receive this wa data.DNSSECEnabled = types.BoolValue(dnssec.Enabled) } + if transferLock != nil { + data.TransferLockEnabled = types.BoolValue(transferLock.Enabled) + } + return diags } @@ -181,6 +213,7 @@ func (r *RegisteredDomainResource) updateModelFromAPIResponsePartialCreate(ctx c } data.DNSSECEnabled = types.BoolValue(false) + data.TransferLockEnabled = types.BoolValue(false) return nil } diff --git a/internal/framework/resources/registered_domain/create.go b/internal/framework/resources/registered_domain/create.go index 9366387c..f21fb466 100644 --- a/internal/framework/resources/registered_domain/create.go +++ b/internal/framework/resources/registered_domain/create.go @@ -116,6 +116,14 @@ func (r *RegisteredDomainResource) Create(ctx context.Context, req resource.Crea } } + if !data.TransferLockEnabled.IsNull() && data.TransferLockEnabled.ValueBool() { + diags := r.setTransferLock(ctx, data) + if diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } + } + domainResponse, err := r.config.Client.Domains.GetDomain(ctx, r.config.AccountID, data.Name.ValueString()) if err != nil { @@ -136,7 +144,17 @@ func (r *RegisteredDomainResource) Create(ctx context.Context, req resource.Crea return } - diags := r.updateModelFromAPIResponse(ctx, data, registerDomainResponse.Data, domainResponse.Data, dnssecResponse.Data) + transferLockResponse, err := r.config.Client.Registrar.GetDomainTransferLock(ctx, r.config.AccountID, data.Name.ValueString()) + + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("failed to read DNSimple Domain transfer lock status: %s", data.Name.ValueString()), + err.Error(), + ) + return + } + + diags := r.updateModelFromAPIResponse(ctx, data, registerDomainResponse.Data, domainResponse.Data, dnssecResponse.Data, transferLockResponse.Data) if diags != nil && diags.HasError() { resp.Diagnostics.Append(diags...) return diff --git a/internal/framework/resources/registered_domain/read.go b/internal/framework/resources/registered_domain/read.go index 304b8bee..8425d7f1 100644 --- a/internal/framework/resources/registered_domain/read.go +++ b/internal/framework/resources/registered_domain/read.go @@ -60,10 +60,20 @@ func (r *RegisteredDomainResource) Read(ctx context.Context, req resource.ReadRe return } + transferLockResponse, err := r.config.Client.Registrar.GetDomainTransferLock(ctx, r.config.AccountID, data.Name.ValueString()) + + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("failed to read DNSimple Domain transfer lock status: %s", data.Name.ValueString()), + err.Error(), + ) + return + } + if domainRegistrationResponse == nil { - diags = r.updateModelFromAPIResponse(ctx, data, nil, domainResponse.Data, dnssecResponse.Data) + diags = r.updateModelFromAPIResponse(ctx, data, nil, domainResponse.Data, dnssecResponse.Data, transferLockResponse.Data) } else { - diags = r.updateModelFromAPIResponse(ctx, data, domainRegistrationResponse.Data, domainResponse.Data, dnssecResponse.Data) + diags = r.updateModelFromAPIResponse(ctx, data, domainRegistrationResponse.Data, domainResponse.Data, dnssecResponse.Data, transferLockResponse.Data) } if diags != nil && diags.HasError() { diff --git a/internal/framework/resources/registered_domain/resource_test.go b/internal/framework/resources/registered_domain/resource_test.go index 0ce6a391..0a77649e 100644 --- a/internal/framework/resources/registered_domain/resource_test.go +++ b/internal/framework/resources/registered_domain/resource_test.go @@ -121,7 +121,7 @@ func TestAccRegisteredDomainResource_WithOptions(t *testing.T) { CheckDestroy: testAccCheckRegisteredDomainResourceDestroy, Steps: []resource.TestStep{ { - Config: testAccRegisteredDomainResourceConfig_WithOptions(domainName, contactID, false, true, true), + Config: testAccRegisteredDomainResourceConfig_WithOptions(domainName, contactID, false, true, true, true), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "name", domainName), resource.TestCheckResourceAttr(resourceName, "state", "registered"), @@ -129,11 +129,12 @@ func TestAccRegisteredDomainResource_WithOptions(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "auto_renew_enabled", "false"), resource.TestCheckResourceAttr(resourceName, "whois_privacy_enabled", "true"), resource.TestCheckResourceAttr(resourceName, "dnssec_enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "transfer_lock_enabled", "true"), resource.TestCheckResourceAttrSet(resourceName, "expires_at"), ), }, { - Config: testAccRegisteredDomainResourceConfig_WithOptions(domainName, contactID, true, false, false), + Config: testAccRegisteredDomainResourceConfig_WithOptions(domainName, contactID, true, false, false, false), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "name", domainName), resource.TestCheckResourceAttr(resourceName, "state", "registered"), @@ -141,6 +142,7 @@ func TestAccRegisteredDomainResource_WithOptions(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "auto_renew_enabled", "true"), resource.TestCheckResourceAttr(resourceName, "whois_privacy_enabled", "false"), resource.TestCheckResourceAttr(resourceName, "dnssec_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "transfer_lock_enabled", "false"), resource.TestCheckResourceAttrSet(resourceName, "expires_at"), ), }, @@ -274,7 +276,7 @@ resource "dnsimple_registered_domain" "test" { }`, domainName, contactId) } -func testAccRegisteredDomainResourceConfig_WithOptions(domainName string, contactId int, withAutoRenew, withWhoisPrivacy, withDNSSEC bool) string { +func testAccRegisteredDomainResourceConfig_WithOptions(domainName string, contactId int, withAutoRenew, withWhoisPrivacy, withDNSSEC bool, withTransferLock bool) string { return fmt.Sprintf(` resource "dnsimple_registered_domain" "test" { name = %[1]q @@ -283,5 +285,6 @@ resource "dnsimple_registered_domain" "test" { auto_renew_enabled = %[3]t whois_privacy_enabled = %[4]t dnssec_enabled = %[5]t -}`, domainName, contactId, withAutoRenew, withWhoisPrivacy, withDNSSEC) + transfer_lock_enabled = %[6]t +}`, domainName, contactId, withAutoRenew, withWhoisPrivacy, withDNSSEC, withTransferLock) } diff --git a/internal/framework/resources/registered_domain/schema.go b/internal/framework/resources/registered_domain/schema.go index 387a92c4..b1db1af6 100644 --- a/internal/framework/resources/registered_domain/schema.go +++ b/internal/framework/resources/registered_domain/schema.go @@ -40,6 +40,7 @@ type RegisteredDomainResourceModel struct { AutoRenewEnabled types.Bool `tfsdk:"auto_renew_enabled"` WhoisPrivacyEnabled types.Bool `tfsdk:"whois_privacy_enabled"` DNSSECEnabled types.Bool `tfsdk:"dnssec_enabled"` + TransferLockEnabled types.Bool `tfsdk:"transfer_lock_enabled"` ContactId types.Int64 `tfsdk:"contact_id"` ExpiresAt types.String `tfsdk:"expires_at"` ExtendedAttributes types.Map `tfsdk:"extended_attributes"` @@ -88,6 +89,10 @@ func (r *RegisteredDomainResource) Schema(_ context.Context, _ resource.SchemaRe Optional: true, Computed: true, }, + "transfer_lock_enabled": schema.BoolAttribute{ + Optional: true, + Computed: true, + }, "contact_id": schema.Int64Attribute{ Required: true, }, diff --git a/internal/framework/resources/registered_domain/update.go b/internal/framework/resources/registered_domain/update.go index f23595b5..55b610d6 100644 --- a/internal/framework/resources/registered_domain/update.go +++ b/internal/framework/resources/registered_domain/update.go @@ -125,6 +125,15 @@ func (r *RegisteredDomainResource) Update(ctx context.Context, req resource.Upda } } + if planData.TransferLockEnabled.ValueBool() != stateData.TransferLockEnabled.ValueBool() { + + diags := r.setTransferLock(ctx, planData) + if diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } + } + domainResponse, err := r.config.Client.Domains.GetDomain(ctx, r.config.AccountID, planData.Name.ValueString()) if err != nil { @@ -145,10 +154,20 @@ func (r *RegisteredDomainResource) Update(ctx context.Context, req resource.Upda return } + transferLockResponse, err := r.config.Client.Registrar.GetDomainTransferLock(ctx, r.config.AccountID, planData.Name.ValueString()) + + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("failed to read DNSimple Domain transfer lock status: %s", planData.Name.ValueString()), + err.Error(), + ) + return + } + if domainRegistrationResponse == nil { - diags = r.updateModelFromAPIResponse(ctx, planData, nil, domainResponse.Data, dnssecResponse.Data) + diags = r.updateModelFromAPIResponse(ctx, planData, nil, domainResponse.Data, dnssecResponse.Data, transferLockResponse.Data) } else { - diags = r.updateModelFromAPIResponse(ctx, planData, domainRegistrationResponse.Data, domainResponse.Data, dnssecResponse.Data) + diags = r.updateModelFromAPIResponse(ctx, planData, domainRegistrationResponse.Data, domainResponse.Data, dnssecResponse.Data, transferLockResponse.Data) } resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() {