Skip to content

Commit 153f101

Browse files
author
Arthur Amstutz
committed
feat: Add resource/datasource ovh_ip_firewall
1 parent 253e195 commit 153f101

9 files changed

+545
-0
lines changed

ovh/data_ip_firewall.go

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package ovh
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/url"
7+
8+
"github.com/hashicorp/terraform-plugin-framework/datasource"
9+
)
10+
11+
var _ datasource.DataSourceWithConfigure = (*ipFirewallDataSource)(nil)
12+
13+
func NewIpFirewallDataSource() datasource.DataSource {
14+
return &ipFirewallDataSource{}
15+
}
16+
17+
type ipFirewallDataSource struct {
18+
config *Config
19+
}
20+
21+
func (d *ipFirewallDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
22+
resp.TypeName = req.ProviderTypeName + "_ip_firewall"
23+
}
24+
25+
func (d *ipFirewallDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
26+
if req.ProviderData == nil {
27+
return
28+
}
29+
30+
config, ok := req.ProviderData.(*Config)
31+
if !ok {
32+
resp.Diagnostics.AddError(
33+
"Unexpected Data Source Configure Type",
34+
fmt.Sprintf("Expected *Config, got: %T. Please report this issue to the provider developers.", req.ProviderData),
35+
)
36+
return
37+
}
38+
39+
d.config = config
40+
}
41+
42+
func (d *ipFirewallDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
43+
resp.Schema = IpFirewallDataSourceSchema(ctx)
44+
}
45+
46+
func (d *ipFirewallDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
47+
var data IpFirewallModel
48+
49+
// Read Terraform configuration data into the model
50+
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
51+
52+
if resp.Diagnostics.HasError() {
53+
return
54+
}
55+
56+
// Read API call logic
57+
endpoint := "/ip/" + url.PathEscape(data.Ip.ValueString()) + "/firewall/" + url.PathEscape(data.IpOnFirewall.ValueString())
58+
if err := d.config.OVHClient.Get(endpoint, &data); err != nil {
59+
resp.Diagnostics.AddError(
60+
fmt.Sprintf("Error calling Get %s", endpoint),
61+
err.Error(),
62+
)
63+
return
64+
}
65+
66+
// Save data into Terraform state
67+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
68+
}

ovh/data_ip_firewall_gen.go

+39
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ovh/data_ip_firewall_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package ovh
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"testing"
7+
8+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
9+
)
10+
11+
func TestAccIPFirewall_data(t *testing.T) {
12+
ip := os.Getenv("OVH_IP_TEST")
13+
testAccIPFirewallConfig := fmt.Sprintf(`
14+
resource "ovh_ip_firewall" "firewall" {
15+
ip = "%s"
16+
ip_on_firewall = "%s"
17+
}
18+
19+
data "ovh_ip_firewall" "firewall_data" {
20+
ip = ovh_ip_firewall.firewall.ip
21+
ip_on_firewall = ovh_ip_firewall.firewall.ip_on_firewall
22+
}
23+
`, ip, ip)
24+
25+
resource.Test(t, resource.TestCase{
26+
PreCheck: func() { testAccPreCheckIp(t) },
27+
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
28+
Steps: []resource.TestStep{
29+
{
30+
Config: testAccIPFirewallConfig,
31+
Check: resource.ComposeTestCheckFunc(
32+
resource.TestCheckResourceAttr(
33+
"data.ovh_ip_firewall.firewall_data", "ip_on_firewall", ip),
34+
resource.TestCheckResourceAttr(
35+
"data.ovh_ip_firewall.firewall_data", "state", "ok"),
36+
resource.TestCheckResourceAttr(
37+
"data.ovh_ip_firewall.firewall_data", "enabled", "false"),
38+
),
39+
},
40+
},
41+
})
42+
}

ovh/provider_new.go

+2
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ func (p *OvhProvider) DataSources(_ context.Context) []func() datasource.DataSou
141141
NewCloudProjectDatabaseIPRestrictionsDataSource,
142142
NewDedicatedServerSpecificationsHardwareDataSource,
143143
NewDomainZoneDnssecDataSource,
144+
NewIpFirewallDataSource,
144145
}
145146
}
146147

@@ -149,6 +150,7 @@ func (p *OvhProvider) Resources(_ context.Context) []func() resource.Resource {
149150
return []func() resource.Resource{
150151
NewCloudProjectAlertingResource,
151152
NewDomainZoneDnssecResource,
153+
NewIpFirewallResource,
152154
NewIploadbalancingUdpFrontendResource,
153155
}
154156
}

ovh/resource_ip_firewall.go

+183
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package ovh
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"net/url"
8+
"strings"
9+
"time"
10+
11+
"github.com/hashicorp/terraform-plugin-framework/path"
12+
"github.com/hashicorp/terraform-plugin-framework/resource"
13+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
14+
)
15+
16+
var (
17+
_ resource.ResourceWithConfigure = (*ipFirewallResource)(nil)
18+
_ resource.ResourceWithImportState = (*ipFirewallResource)(nil)
19+
)
20+
21+
func NewIpFirewallResource() resource.Resource {
22+
return &ipFirewallResource{}
23+
}
24+
25+
type ipFirewallResource struct {
26+
config *Config
27+
}
28+
29+
func (r *ipFirewallResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
30+
resp.TypeName = req.ProviderTypeName + "_ip_firewall"
31+
}
32+
33+
func (d *ipFirewallResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
34+
if req.ProviderData == nil {
35+
return
36+
}
37+
38+
config, ok := req.ProviderData.(*Config)
39+
if !ok {
40+
resp.Diagnostics.AddError(
41+
"Unexpected Resource Configure Type",
42+
fmt.Sprintf("Expected *Config, got: %T. Please report this issue to the provider developers.", req.ProviderData),
43+
)
44+
return
45+
}
46+
47+
d.config = config
48+
}
49+
50+
func (d *ipFirewallResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
51+
resp.Schema = IpFirewallResourceSchema(ctx)
52+
}
53+
54+
func (r *ipFirewallResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
55+
splits := strings.Split(req.ID, "/")
56+
if len(splits) < 2 {
57+
resp.Diagnostics.AddError("Given ID is malformed", "ID must be formatted like the following: <ip>/<ipOnFirewall>")
58+
return
59+
}
60+
61+
ip := strings.Join(splits[0:len(splits)-1], "/")
62+
ipOnFirewall := splits[len(splits)-1]
63+
64+
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("ip"), ip)...)
65+
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("ip_on_firewall"), ipOnFirewall)...)
66+
}
67+
68+
func (r *ipFirewallResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
69+
var data, responseData IpFirewallModel
70+
71+
// Read Terraform plan data into the model
72+
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
73+
if resp.Diagnostics.HasError() {
74+
return
75+
}
76+
77+
endpoint := "/ip/" + url.PathEscape(data.Ip.ValueString()) + "/firewall"
78+
if err := r.config.OVHClient.Post(endpoint, data.ToCreate(), &responseData); err != nil {
79+
resp.Diagnostics.AddError(
80+
fmt.Sprintf("Error calling Post %s", endpoint),
81+
err.Error(),
82+
)
83+
return
84+
}
85+
86+
responseData.MergeWith(&data)
87+
88+
// Save data into Terraform state
89+
resp.Diagnostics.Append(resp.State.Set(ctx, &responseData)...)
90+
}
91+
92+
func (r *ipFirewallResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
93+
var data, responseData IpFirewallModel
94+
95+
// Read Terraform prior state data into the model
96+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
97+
if resp.Diagnostics.HasError() {
98+
return
99+
}
100+
101+
endpoint := "/ip/" + url.PathEscape(data.Ip.ValueString()) + "/firewall/" + url.PathEscape(data.IpOnFirewall.ValueString())
102+
103+
if err := r.config.OVHClient.Get(endpoint, &responseData); err != nil {
104+
resp.Diagnostics.AddError(
105+
fmt.Sprintf("Error calling Get %s", endpoint),
106+
err.Error(),
107+
)
108+
return
109+
}
110+
111+
data.MergeWith(&responseData)
112+
113+
// Save updated data into Terraform state
114+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
115+
}
116+
117+
func (r *ipFirewallResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
118+
var data, planData, responseData IpFirewallModel
119+
120+
// Read Terraform plan data into the model
121+
resp.Diagnostics.Append(req.Plan.Get(ctx, &planData)...)
122+
if resp.Diagnostics.HasError() {
123+
return
124+
}
125+
126+
// Read Terraform prior state data into the model
127+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
128+
if resp.Diagnostics.HasError() {
129+
return
130+
}
131+
132+
// Update resource
133+
endpoint := "/ip/" + url.PathEscape(data.Ip.ValueString()) + "/firewall/" + url.PathEscape(data.IpOnFirewall.ValueString())
134+
if err := r.config.OVHClient.Put(endpoint, planData.ToUpdate(), nil); err != nil {
135+
resp.Diagnostics.AddError(
136+
fmt.Sprintf("Error calling Put %s", endpoint),
137+
err.Error(),
138+
)
139+
return
140+
}
141+
142+
// Read updated resource
143+
err := retry.RetryContext(ctx, time.Minute, func() *retry.RetryError {
144+
if err := r.config.OVHClient.Get(endpoint, &responseData); err != nil {
145+
return retry.NonRetryableError(err)
146+
}
147+
148+
if responseData.State.ValueString() == "ok" {
149+
return nil
150+
}
151+
152+
return retry.RetryableError(errors.New("waiting for state to be OK"))
153+
})
154+
if err != nil {
155+
resp.Diagnostics.AddError("Failed to get updated resource", err.Error())
156+
return
157+
}
158+
159+
responseData.MergeWith(&planData)
160+
161+
// Save updated data into Terraform state
162+
resp.Diagnostics.Append(resp.State.Set(ctx, &responseData)...)
163+
}
164+
165+
func (r *ipFirewallResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
166+
var data IpFirewallModel
167+
168+
// Read Terraform prior state data into the model
169+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
170+
171+
if resp.Diagnostics.HasError() {
172+
return
173+
}
174+
175+
// Delete API call logic
176+
endpoint := "/ip/" + url.PathEscape(data.Ip.ValueString()) + "/firewall/" + url.PathEscape(data.IpOnFirewall.ValueString())
177+
if err := r.config.OVHClient.Delete(endpoint, nil); err != nil {
178+
resp.Diagnostics.AddError(
179+
fmt.Sprintf("Error calling Delete %s", endpoint),
180+
err.Error(),
181+
)
182+
}
183+
}

0 commit comments

Comments
 (0)