diff --git a/stackit/internal/services/iaas/securitygrouprule/resource.go b/stackit/internal/services/iaas/securitygrouprule/resource.go index 1f73d3ed7..0517e045e 100644 --- a/stackit/internal/services/iaas/securitygrouprule/resource.go +++ b/stackit/internal/services/iaas/securitygrouprule/resource.go @@ -672,7 +672,11 @@ func mapFields(securityGroupRuleResp *iaas.SecurityGroupRule, model *Model, regi func mapIcmpParameters(securityGroupRuleResp *iaas.SecurityGroupRule, m *Model) error { if securityGroupRuleResp.IcmpParameters == nil { - m.IcmpParameters = types.ObjectNull(icmpParametersTypes) + // workaround: when the icmp parameters code and type are set to the 0, the API responds with null for icmp parameters. + // To prevent a state drift, we set icmp parameters only to null, when it's also in the model as null defined. + if utils.IsUndefined(m.IcmpParameters) { + m.IcmpParameters = types.ObjectNull(icmpParametersTypes) + } return nil } @@ -691,7 +695,11 @@ func mapIcmpParameters(securityGroupRuleResp *iaas.SecurityGroupRule, m *Model) func mapPortRange(securityGroupRuleResp *iaas.SecurityGroupRule, m *Model) error { if securityGroupRuleResp.PortRange == nil { - m.PortRange = types.ObjectNull(portRangeTypes) + // workaround: when the port range is set to the whole range 1-65535, the API responds with null for port range. + // To prevent a state drift, we set port range only to null, when it's also in the model as null defined. + if utils.IsUndefined(m.PortRange) { + m.PortRange = types.ObjectNull(portRangeTypes) + } return nil } diff --git a/stackit/internal/services/iaas/securitygrouprule/resource_test.go b/stackit/internal/services/iaas/securitygrouprule/resource_test.go index b8464e21d..26f8adc7b 100644 --- a/stackit/internal/services/iaas/securitygrouprule/resource_test.go +++ b/stackit/internal/services/iaas/securitygrouprule/resource_test.go @@ -201,6 +201,84 @@ func TestMapFields(t *testing.T) { }, isValid: true, }, + { + description: "port range in model defined, but in response null", + args: args{ + state: Model{ + ProjectId: types.StringValue("pid"), + SecurityGroupId: types.StringValue("sgid"), + SecurityGroupRuleId: types.StringValue("sgrid"), + Region: types.StringValue("eu01"), + PortRange: fixtureModelPortRange, + }, + input: &iaas.SecurityGroupRule{ + Id: new("sgrid"), + Description: new("desc"), + Direction: new("ingress"), + Ethertype: new("ether"), + IpRange: new("iprange"), + RemoteSecurityGroupId: new("remote"), + PortRange: nil, + Protocol: &fixtureProtocol, + }, + region: "eu02", + }, + expected: Model{ + Id: types.StringValue("pid,eu02,sgid,sgrid"), + ProjectId: types.StringValue("pid"), + SecurityGroupId: types.StringValue("sgid"), + SecurityGroupRuleId: types.StringValue("sgrid"), + Direction: types.StringValue("ingress"), + Description: types.StringValue("desc"), + EtherType: types.StringValue("ether"), + IpRange: types.StringValue("iprange"), + RemoteSecurityGroupId: types.StringValue("remote"), + IcmpParameters: types.ObjectNull(icmpParametersTypes), + PortRange: fixtureModelPortRange, + Protocol: fixtureModelProtocol, + Region: types.StringValue("eu02"), + }, + isValid: true, + }, + { + description: "icmp parameters in model defined, but in response null", + args: args{ + state: Model{ + ProjectId: types.StringValue("pid"), + SecurityGroupId: types.StringValue("sgid"), + SecurityGroupRuleId: types.StringValue("sgrid"), + Region: types.StringValue("eu01"), + IcmpParameters: fixtureModelIcmpParameters, + }, + input: &iaas.SecurityGroupRule{ + Id: new("sgrid"), + Description: new("desc"), + Direction: new("ingress"), + Ethertype: new("ether"), + IpRange: new("iprange"), + RemoteSecurityGroupId: new("remote"), + IcmpParameters: nil, + Protocol: &fixtureProtocol, + }, + region: "eu02", + }, + expected: Model{ + Id: types.StringValue("pid,eu02,sgid,sgrid"), + ProjectId: types.StringValue("pid"), + SecurityGroupId: types.StringValue("sgid"), + SecurityGroupRuleId: types.StringValue("sgrid"), + Direction: types.StringValue("ingress"), + Description: types.StringValue("desc"), + EtherType: types.StringValue("ether"), + IpRange: types.StringValue("iprange"), + RemoteSecurityGroupId: types.StringValue("remote"), + IcmpParameters: fixtureModelIcmpParameters, + PortRange: types.ObjectNull(portRangeTypes), + Protocol: fixtureModelProtocol, + Region: types.StringValue("eu02"), + }, + isValid: true, + }, { description: "response_nil_fail", },