From d68a6c7ab1850965fd5068f614ee4c68fdb2ff57 Mon Sep 17 00:00:00 2001 From: Arthur Amstutz Date: Tue, 9 Apr 2024 07:33:13 +0000 Subject: [PATCH] fix: Use correct types for API response of resource/datasource ovh_ip_firewall_rule --- ovh/data_ip_firewall_rule.go | 2 +- ovh/data_ip_firewall_rule_gen.go | 25 +++- ovh/data_ip_firewall_rule_test.go | 7 +- ovh/resource_ip_firewall_rule.go | 10 +- ovh/resource_ip_firewall_rule_gen.go | 120 ++++++++++++++++-- ovh/resource_ip_firewall_rule_test.go | 11 +- website/docs/r/ip_firewall_rule.html.markdown | 4 +- 7 files changed, 155 insertions(+), 24 deletions(-) diff --git a/ovh/data_ip_firewall_rule.go b/ovh/data_ip_firewall_rule.go index a40a7bab6..c68a955c4 100644 --- a/ovh/data_ip_firewall_rule.go +++ b/ovh/data_ip_firewall_rule.go @@ -44,7 +44,7 @@ func (d *ipFirewallRuleDataSource) Schema(ctx context.Context, req datasource.Sc } func (d *ipFirewallRuleDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data IpFirewallRuleModel + var data IpFirewallRuleDataResponseModel // Read Terraform configuration data into the model resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) diff --git a/ovh/data_ip_firewall_rule_gen.go b/ovh/data_ip_firewall_rule_gen.go index 8e5a3be28..42fb7836a 100644 --- a/ovh/data_ip_firewall_rule_gen.go +++ b/ovh/data_ip_firewall_rule_gen.go @@ -38,8 +38,8 @@ func IpFirewallRuleDataSourceSchema(ctx context.Context) schema.Schema { Description: "Destination ip for your rule", MarkdownDescription: "Destination ip for your rule", }, - "destination_port": schema.Int64Attribute{ - CustomType: ovhtypes.TfInt64Type{}, + "destination_port": schema.StringAttribute{ + CustomType: ovhtypes.TfStringType{}, Computed: true, Description: "Destination port for your rule. Only with TCP/UDP protocol", MarkdownDescription: "Destination port for your rule. Only with TCP/UDP protocol", @@ -119,8 +119,8 @@ func IpFirewallRuleDataSourceSchema(ctx context.Context) schema.Schema { Description: "IPv4 CIDR notation (e.g., 192.0.2.0/24)", MarkdownDescription: "IPv4 CIDR notation (e.g., 192.0.2.0/24)", }, - "source_port": schema.Int64Attribute{ - CustomType: ovhtypes.TfInt64Type{}, + "source_port": schema.StringAttribute{ + CustomType: ovhtypes.TfStringType{}, Computed: true, Description: "Source port for your rule. Only with TCP/UDP protocol", MarkdownDescription: "Source port for your rule. Only with TCP/UDP protocol", @@ -146,3 +146,20 @@ func IpFirewallRuleDataSourceSchema(ctx context.Context) schema.Schema { }, } } + +type IpFirewallRuleDataResponseModel struct { + Action ovhtypes.TfStringValue `tfsdk:"action" json:"action"` + CreationDate ovhtypes.TfStringValue `tfsdk:"creation_date" json:"creationDate"` + Destination ovhtypes.TfStringValue `tfsdk:"destination" json:"destination"` + DestinationPort ovhtypes.TfStringValue `tfsdk:"destination_port" json:"destinationPort"` + Fragments ovhtypes.TfBoolValue `tfsdk:"fragments" json:"fragments"` + Ip ovhtypes.TfStringValue `tfsdk:"ip" json:"ip"` + IpOnFirewall ovhtypes.TfStringValue `tfsdk:"ip_on_firewall" json:"ipOnFirewall"` + Protocol ovhtypes.TfStringValue `tfsdk:"protocol" json:"protocol"` + Rule ovhtypes.TfStringValue `tfsdk:"rule" json:"rule"` + Sequence ovhtypes.TfInt64Value `tfsdk:"sequence" json:"sequence"` + Source ovhtypes.TfStringValue `tfsdk:"source" json:"source"` + SourcePort ovhtypes.TfStringValue `tfsdk:"source_port" json:"sourcePort"` + State ovhtypes.TfStringValue `tfsdk:"state" json:"state"` + TcpOption ovhtypes.TfStringValue `tfsdk:"tcp_option" json:"tcpOption"` +} diff --git a/ovh/data_ip_firewall_rule_test.go b/ovh/data_ip_firewall_rule_test.go index 843ae0e17..3caebeb21 100644 --- a/ovh/data_ip_firewall_rule_test.go +++ b/ovh/data_ip_firewall_rule_test.go @@ -29,7 +29,8 @@ func TestAccIPFirewallRule_data(t *testing.T) { protocol = "tcp" sequence = 0 tcp_option = "established" - fragments = true + destination_port = 22 + source_port = 44 } data "ovh_ip_firewall_rule" "rule_data" { @@ -56,6 +57,10 @@ func TestAccIPFirewallRule_data(t *testing.T) { "data.ovh_ip_firewall_rule.rule_data", "source", "any"), resource.TestCheckResourceAttr( "data.ovh_ip_firewall_rule.rule_data", "tcp_option", "established"), + resource.TestCheckResourceAttr( + "data.ovh_ip_firewall_rule.rule_data", "destination_port", "eq 22"), + resource.TestCheckResourceAttr( + "data.ovh_ip_firewall_rule.rule_data", "source_port", "eq 44"), ), }, }, diff --git a/ovh/resource_ip_firewall_rule.go b/ovh/resource_ip_firewall_rule.go index 039e48d6b..783d04e7d 100644 --- a/ovh/resource_ip_firewall_rule.go +++ b/ovh/resource_ip_firewall_rule.go @@ -48,7 +48,10 @@ func (d *ipFirewallRuleResource) Schema(ctx context.Context, req resource.Schema } func (r *ipFirewallRuleResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var data, responseData IpFirewallRuleModel + var ( + data IpFirewallRuleModel + responseData IpFirewallRuleResponseModel + ) // Read Terraform plan data into the model resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) @@ -100,7 +103,10 @@ func (r *ipFirewallRuleResource) Create(ctx context.Context, req resource.Create } func (r *ipFirewallRuleResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var data, responseData IpFirewallRuleModel + var ( + data IpFirewallRuleModel + responseData IpFirewallRuleResponseModel + ) // Read Terraform prior state data into the model resp.Diagnostics.Append(req.State.Get(ctx, &data)...) diff --git a/ovh/resource_ip_firewall_rule_gen.go b/ovh/resource_ip_firewall_rule_gen.go index 93d94eee2..fc7a41112 100644 --- a/ovh/resource_ip_firewall_rule_gen.go +++ b/ovh/resource_ip_firewall_rule_gen.go @@ -55,6 +55,11 @@ func IpFirewallRuleResourceSchema(ctx context.Context) schema.Schema { int64planmodifier.RequiresReplace(), }, }, + "destination_port_desc": schema.StringAttribute{ + CustomType: ovhtypes.TfStringType{}, + Computed: true, + Description: "Destination port range for your rule. Only with TCP/UDP protocol", + }, "fragments": schema.BoolAttribute{ CustomType: ovhtypes.TfBoolType{}, Optional: true, @@ -160,6 +165,11 @@ func IpFirewallRuleResourceSchema(ctx context.Context) schema.Schema { int64planmodifier.RequiresReplace(), }, }, + "source_port_desc": schema.StringAttribute{ + CustomType: ovhtypes.TfStringType{}, + Computed: true, + Description: "Source port for your rule. Only with TCP/UDP protocol", + }, "state": schema.StringAttribute{ CustomType: ovhtypes.TfStringType{}, Computed: true, @@ -187,20 +197,44 @@ func IpFirewallRuleResourceSchema(ctx context.Context) schema.Schema { } type IpFirewallRuleModel struct { - Action ovhtypes.TfStringValue `tfsdk:"action" json:"action"` - CreationDate ovhtypes.TfStringValue `tfsdk:"creation_date" json:"creationDate"` - Destination ovhtypes.TfStringValue `tfsdk:"destination" json:"destination"` - DestinationPort ovhtypes.TfInt64Value `tfsdk:"destination_port" json:"destinationPort"` - Fragments ovhtypes.TfBoolValue `tfsdk:"fragments" json:"fragments"` - Ip ovhtypes.TfStringValue `tfsdk:"ip" json:"ip"` - IpOnFirewall ovhtypes.TfStringValue `tfsdk:"ip_on_firewall" json:"ipOnFirewall"` - Protocol ovhtypes.TfStringValue `tfsdk:"protocol" json:"protocol"` - Rule ovhtypes.TfStringValue `tfsdk:"rule" json:"rule"` - Sequence ovhtypes.TfInt64Value `tfsdk:"sequence" json:"sequence"` - Source ovhtypes.TfStringValue `tfsdk:"source" json:"source"` - SourcePort ovhtypes.TfInt64Value `tfsdk:"source_port" json:"sourcePort"` - State ovhtypes.TfStringValue `tfsdk:"state" json:"state"` - TcpOption ovhtypes.TfStringValue `tfsdk:"tcp_option" json:"tcpOption"` + Action ovhtypes.TfStringValue `tfsdk:"action" json:"action"` + CreationDate ovhtypes.TfStringValue `tfsdk:"creation_date" json:"creationDate"` + Destination ovhtypes.TfStringValue `tfsdk:"destination" json:"destination"` + DestinationPort ovhtypes.TfInt64Value `tfsdk:"destination_port" json:"destinationPort"` + DestinationPortDesc ovhtypes.TfStringValue `tfsdk:"destination_port_desc" json:"-"` + Fragments ovhtypes.TfBoolValue `tfsdk:"fragments" json:"fragments"` + Ip ovhtypes.TfStringValue `tfsdk:"ip" json:"ip"` + IpOnFirewall ovhtypes.TfStringValue `tfsdk:"ip_on_firewall" json:"ipOnFirewall"` + Protocol ovhtypes.TfStringValue `tfsdk:"protocol" json:"protocol"` + Rule ovhtypes.TfStringValue `tfsdk:"rule" json:"rule"` + Sequence ovhtypes.TfInt64Value `tfsdk:"sequence" json:"sequence"` + Source ovhtypes.TfStringValue `tfsdk:"source" json:"source"` + SourcePort ovhtypes.TfInt64Value `tfsdk:"source_port" json:"sourcePort"` + SourcePortDesc ovhtypes.TfStringValue `tfsdk:"source_port_desc" json:"-"` + State ovhtypes.TfStringValue `tfsdk:"state" json:"state"` + TcpOption ovhtypes.TfStringValue `tfsdk:"tcp_option" json:"tcpOption"` +} + +// IpFirewallRuleResponseModel is used to read the API response body. We need +// a separate model to write and read because some properties don't have the +// same type everywhere. +type IpFirewallRuleResponseModel struct { + Action ovhtypes.TfStringValue `tfsdk:"action" json:"action"` + CreationDate ovhtypes.TfStringValue `tfsdk:"creation_date" json:"creationDate"` + Destination ovhtypes.TfStringValue `tfsdk:"destination" json:"destination"` + DestinationPort ovhtypes.TfInt64Value `tfsdk:"destination_port" json:"-"` + DestinationPortDesc ovhtypes.TfStringValue `tfsdk:"destination_port_desc" json:"destinationPort"` + Fragments ovhtypes.TfBoolValue `tfsdk:"fragments" json:"fragments"` + Ip ovhtypes.TfStringValue `tfsdk:"ip" json:"ip"` + IpOnFirewall ovhtypes.TfStringValue `tfsdk:"ip_on_firewall" json:"ipOnFirewall"` + Protocol ovhtypes.TfStringValue `tfsdk:"protocol" json:"protocol"` + Rule ovhtypes.TfStringValue `tfsdk:"rule" json:"rule"` + Sequence ovhtypes.TfInt64Value `tfsdk:"sequence" json:"sequence"` + Source ovhtypes.TfStringValue `tfsdk:"source" json:"source"` + SourcePort ovhtypes.TfInt64Value `tfsdk:"source_port" json:"-"` + SourcePortDesc ovhtypes.TfStringValue `tfsdk:"source_port_desc" json:"sourcePort"` + State ovhtypes.TfStringValue `tfsdk:"state" json:"state"` + TcpOption ovhtypes.TfStringValue `tfsdk:"tcp_option" json:"tcpOption"` } func (v *IpFirewallRuleModel) MergeWith(other *IpFirewallRuleModel) { @@ -261,6 +295,64 @@ func (v *IpFirewallRuleModel) MergeWith(other *IpFirewallRuleModel) { } } +func (v *IpFirewallRuleResponseModel) MergeWith(other *IpFirewallRuleModel) { + if (v.Action.IsUnknown() || v.Action.IsNull()) && !other.Action.IsUnknown() { + v.Action = other.Action + } + + if (v.CreationDate.IsUnknown() || v.CreationDate.IsNull()) && !other.CreationDate.IsUnknown() { + v.CreationDate = other.CreationDate + } + + if (v.Destination.IsUnknown() || v.Destination.IsNull()) && !other.Destination.IsUnknown() { + v.Destination = other.Destination + } + + if (v.DestinationPort.IsUnknown() || v.DestinationPort.IsNull()) && !other.DestinationPort.IsUnknown() { + v.DestinationPort = other.DestinationPort + } + + if (v.Fragments.IsUnknown() || v.Fragments.IsNull()) && !other.Fragments.IsUnknown() { + v.Fragments = other.Fragments + } + + if (v.Ip.IsUnknown() || v.Ip.IsNull()) && !other.Ip.IsUnknown() { + v.Ip = other.Ip + } + + if (v.IpOnFirewall.IsUnknown() || v.IpOnFirewall.IsNull()) && !other.IpOnFirewall.IsUnknown() { + v.IpOnFirewall = other.IpOnFirewall + } + + if (v.Protocol.IsUnknown() || v.Protocol.IsNull()) && !other.Protocol.IsUnknown() { + v.Protocol = other.Protocol + } + + if (v.Rule.IsUnknown() || v.Rule.IsNull()) && !other.Rule.IsUnknown() { + v.Rule = other.Rule + } + + if (v.Sequence.IsUnknown() || v.Sequence.IsNull()) && !other.Sequence.IsUnknown() { + v.Sequence = other.Sequence + } + + if (v.Source.IsUnknown() || v.Source.IsNull()) && !other.Source.IsUnknown() { + v.Source = other.Source + } + + if (v.SourcePort.IsUnknown() || v.SourcePort.IsNull()) && !other.SourcePort.IsUnknown() { + v.SourcePort = other.SourcePort + } + + if (v.State.IsUnknown() || v.State.IsNull()) && !other.State.IsUnknown() { + v.State = other.State + } + + if (v.TcpOption.IsUnknown() || v.TcpOption.IsNull()) && !other.TcpOption.IsUnknown() { + v.TcpOption = other.TcpOption + } +} + // IpFirewallRuleWritableModel is an additional model used to create the rules. // Field `tcpOption` has a different type compared to struct IpFirewallRuleModel because // the field type is different in the API's request and response bodies. diff --git a/ovh/resource_ip_firewall_rule_test.go b/ovh/resource_ip_firewall_rule_test.go index a84d004e0..f52918b5d 100644 --- a/ovh/resource_ip_firewall_rule_test.go +++ b/ovh/resource_ip_firewall_rule_test.go @@ -29,7 +29,8 @@ func TestAccIPFirewallRule_basic(t *testing.T) { protocol = "tcp" sequence = 0 tcp_option = "established" - fragments = true + destination_port = 22 + source_port = 44 } `, ip, ip) @@ -50,6 +51,14 @@ func TestAccIPFirewallRule_basic(t *testing.T) { "ovh_ip_firewall_rule.rule", "source", "any"), resource.TestCheckResourceAttr( "ovh_ip_firewall_rule.rule", "tcp_option", "established"), + resource.TestCheckResourceAttr( + "ovh_ip_firewall_rule.rule", "destination_port", "22"), + resource.TestCheckResourceAttr( + "ovh_ip_firewall_rule.rule", "destination_port_desc", "eq 22"), + resource.TestCheckResourceAttr( + "ovh_ip_firewall_rule.rule", "source_port", "44"), + resource.TestCheckResourceAttr( + "ovh_ip_firewall_rule.rule", "source_port_desc", "eq 44"), ), }, }, diff --git a/website/docs/r/ip_firewall_rule.html.markdown b/website/docs/r/ip_firewall_rule.html.markdown index b8118fb70..5b80d9384 100644 --- a/website/docs/r/ip_firewall_rule.html.markdown +++ b/website/docs/r/ip_firewall_rule.html.markdown @@ -2,7 +2,7 @@ subcategory : "Additional IP" --- -# ovh_ip_firewall +# ovh_ip_firewall_rule Use this resource to manage a rule on an IP firewall. @@ -39,10 +39,12 @@ resource "ovh_ip_firewall_rule" "myfirewallrule" { * `creation_date` - Creation date of the rule * `destination` - Destination IP for your rule * `destination_port` - Destination port for your rule. Only with TCP/UDP protocol +* `destination_port_desc` - String description of field `destination_port` * `fragments` - Fragments option * `protocol` - Possible values for protocol (ah|esp|gre|icmp|ipv4|tcp|udp) * `rule` - Description of the rule * `sequence` - Rule position in the rules array * `source` - IPv4 CIDR notation (e.g., 192.0.2.0/24) * `source_port` - Source port for your rule. Only with TCP/UDP protocol +* `source_port_desc` - String description of field `source_port` * `tcp_option` - TCP option on your rule (syn|established) \ No newline at end of file