Skip to content

Commit

Permalink
Merge pull request #604 from ovh/dev/aamstutz/ip-mitigation
Browse files Browse the repository at this point in the history
feat: Add resource/datasource ovh_ip_mitigation
  • Loading branch information
amstuta authored Apr 4, 2024
2 parents 7a7c5ac + 9465bfb commit 39e1199
Show file tree
Hide file tree
Showing 10 changed files with 604 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .cds/terraform-provider-ovh.yml
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ workflow:
environment: acctests
one_at_a_time: true
parameters:
testargs: -run 'TestAccIPFirewall'
testargs: -run 'TestAccIPFirewall|TestAccIPMitigation'
pipeline: terraform-provider-ovh-testacc
when:
- success
Expand Down
68 changes: 68 additions & 0 deletions ovh/data_ip_mitigation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package ovh

import (
"context"
"fmt"
"net/url"

"github.com/hashicorp/terraform-plugin-framework/datasource"
)

var _ datasource.DataSourceWithConfigure = (*ipMitigationDataSource)(nil)

func NewIpMitigationDataSource() datasource.DataSource {
return &ipMitigationDataSource{}
}

type ipMitigationDataSource struct {
config *Config
}

func (d *ipMitigationDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_ip_mitigation"
}

func (d *ipMitigationDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

config, ok := req.ProviderData.(*Config)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *Config, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)
return
}

d.config = config
}

func (d *ipMitigationDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = IpMitigationDataSourceSchema(ctx)
}

func (d *ipMitigationDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data IpMitigationModel

// Read Terraform configuration data into the model
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)

if resp.Diagnostics.HasError() {
return
}

// Read API call logic
endpoint := "/ip/" + url.PathEscape(data.Ip.ValueString()) + "/mitigation/" + url.PathEscape(data.IpOnMitigation.ValueString())
if err := d.config.OVHClient.Get(endpoint, &data); err != nil {
resp.Diagnostics.AddError(
fmt.Sprintf("Error calling Get %s", endpoint),
err.Error(),
)
return
}

// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
47 changes: 47 additions & 0 deletions ovh/data_ip_mitigation_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 47 additions & 0 deletions ovh/data_ip_mitigation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package ovh

import (
"fmt"
"os"
"testing"

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

const testAccIPMitigationDataSourceConfig = `
resource "ovh_ip_mitigation" "mitigation" {
ip = "%s"
ip_on_mitigation = "%s"
}
data "ovh_ip_mitigation" "mitigation_data" {
ip = ovh_ip_mitigation.mitigation.ip
ip_on_mitigation = ovh_ip_mitigation.mitigation.ip_on_mitigation
}
`

func TestAccIPMitigationData_basic(t *testing.T) {
ip := os.Getenv("OVH_IP_TEST")

config := fmt.Sprintf(testAccIPMitigationDataSourceConfig, ip, ip)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheckIp(t) },
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.ovh_ip_mitigation.mitigation_data", "ip_on_mitigation", ip),
resource.TestCheckResourceAttr(
"data.ovh_ip_mitigation.mitigation_data", "state", "ok"),
resource.TestCheckResourceAttr(
"data.ovh_ip_mitigation.mitigation_data", "auto", "false"),
resource.TestCheckResourceAttr(
"data.ovh_ip_mitigation.mitigation_data", "permanent", "true"),
),
},
},
})
}
2 changes: 2 additions & 0 deletions ovh/provider_new.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ func (p *OvhProvider) DataSources(_ context.Context) []func() datasource.DataSou
NewDomainZoneDnssecDataSource,
NewIpFirewallDataSource,
NewIpFirewallRuleDataSource,
NewIpMitigationDataSource,
}
}

Expand All @@ -156,6 +157,7 @@ func (p *OvhProvider) Resources(_ context.Context) []func() resource.Resource {
NewIpFirewallResource,
NewIpFirewallRuleResource,
NewIploadbalancingUdpFrontendResource,
NewIpMitigationResource,
NewVpsResource,
}
}
Expand Down
204 changes: 204 additions & 0 deletions ovh/resource_ip_mitigation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
package ovh

import (
"context"
"errors"
"fmt"
"net/url"
"time"

"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/ovh/go-ovh/ovh"
)

var _ resource.ResourceWithConfigure = (*ipMitigationResource)(nil)

func NewIpMitigationResource() resource.Resource {
return &ipMitigationResource{}
}

type ipMitigationResource struct {
config *Config
}

func (r *ipMitigationResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_ip_mitigation"
}

func (d *ipMitigationResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

config, ok := req.ProviderData.(*Config)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
fmt.Sprintf("Expected *Config, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)
return
}

d.config = config
}

func (d *ipMitigationResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = IpMitigationResourceSchema(ctx)
}

func (r *ipMitigationResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data, responseData IpMitigationModel

// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

endpoint := "/ip/" + url.PathEscape(data.Ip.ValueString()) + "/mitigation"
if err := r.config.OVHClient.Post(endpoint, data.ToCreate(), &responseData); err != nil {
resp.Diagnostics.AddError(
fmt.Sprintf("Error calling Post %s", endpoint),
err.Error(),
)
return
}

// Wait for state to be ok
endpoint = "/ip/" + url.PathEscape(data.Ip.ValueString()) + "/mitigation/" + url.PathEscape(data.IpOnMitigation.ValueString())
err := retry.RetryContext(ctx, 10*time.Minute, func() *retry.RetryError {
readErr := r.config.OVHClient.Get(endpoint, &responseData)
if readErr != nil {
return retry.NonRetryableError(readErr)
}

if responseData.State.ValueString() == "ok" {
return nil
}

return retry.RetryableError(errors.New("waiting for resource state to be ok"))
})

if err != nil {
resp.Diagnostics.AddError("error waiting status to be ok", err.Error())
return
}

responseData.MergeWith(&data)

// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &responseData)...)
}

func (r *ipMitigationResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data, responseData IpMitigationModel

// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

endpoint := "/ip/" + url.PathEscape(data.Ip.ValueString()) + "/mitigation/" + url.PathEscape(data.IpOnMitigation.ValueString())
if err := r.config.OVHClient.Get(endpoint, &responseData); err != nil {
resp.Diagnostics.AddError(
fmt.Sprintf("Error calling Get %s", endpoint),
err.Error(),
)
return
}

data.MergeWith(&responseData)

// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *ipMitigationResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data, planData, responseData IpMitigationModel

// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &planData)...)
if resp.Diagnostics.HasError() {
return
}

// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

// Update resource
endpoint := "/ip/" + url.PathEscape(data.Ip.ValueString()) + "/mitigation/" + url.PathEscape(data.IpOnMitigation.ValueString())
if err := r.config.OVHClient.Put(endpoint, planData.ToUpdate(), nil); err != nil {
resp.Diagnostics.AddError(
fmt.Sprintf("Error calling Put %s", endpoint),
err.Error(),
)
return
}

// Read updated resource
err := retry.RetryContext(ctx, 10*time.Minute, func() *retry.RetryError {
readErr := r.config.OVHClient.Get(endpoint, &responseData)
if readErr != nil {
return retry.NonRetryableError(readErr)
}

if responseData.State.ValueString() == "ok" {
return nil
}

return retry.RetryableError(errors.New("waiting for resource state to be ok"))
})

if err != nil {
resp.Diagnostics.AddError("error waiting status to be ok", err.Error())
return
}

responseData.MergeWith(&planData)

// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &responseData)...)
}

func (r *ipMitigationResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data IpMitigationModel

// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)

if resp.Diagnostics.HasError() {
return
}

// Delete API call logic
endpoint := "/ip/" + url.PathEscape(data.Ip.ValueString()) + "/mitigation/" + url.PathEscape(data.IpOnMitigation.ValueString())
if err := r.config.OVHClient.Delete(endpoint, nil); err != nil {
resp.Diagnostics.AddError(
fmt.Sprintf("Error calling Delete %s", endpoint),
err.Error(),
)
}

// Wait for resource to be removed
err := retry.RetryContext(ctx, 10*time.Minute, func() *retry.RetryError {
readErr := r.config.OVHClient.Get(endpoint, nil)
if readErr != nil {
if errOvh, ok := readErr.(*ovh.APIError); ok && errOvh.Code == 404 {
return nil
} else {
return retry.NonRetryableError(readErr)
}
}

return retry.RetryableError(errors.New("waiting for resource to be removed"))
})

if err != nil {
resp.Diagnostics.AddError("error verifying that resource was deleted", err.Error())
}
}
Loading

0 comments on commit 39e1199

Please sign in to comment.