Skip to content

Commit 1fdebaa

Browse files
authored
Make ensureSecurityRule() safely idempotent (#2249)
`ensureSecurityRule()` is used to add a rule to an existing security group. At first it was listing all the rules in the SG and then if the requested rule wasn't present it was adding it. This has some risk - the list of SG rules can be modified in-between by some other thread. This commit changes the logic of that function to just try to create the rule. Neutron API will return 409 Conflict if the rule already exists and if it does OCCM will just ignore the error and move on.
1 parent 98ba5d7 commit 1fdebaa

File tree

2 files changed

+20
-22
lines changed

2 files changed

+20
-22
lines changed

pkg/openstack/loadbalancer.go

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2090,23 +2090,6 @@ func (lbaas *LbaasV2) ensureSecurityRule(
20902090
remoteIPPrefix, secGroupID string,
20912091
portRangeMin, portRangeMax int,
20922092
) error {
2093-
sgListopts := rules.ListOpts{
2094-
Direction: string(direction),
2095-
Protocol: string(protocol),
2096-
PortRangeMax: portRangeMin,
2097-
PortRangeMin: portRangeMax,
2098-
RemoteIPPrefix: remoteIPPrefix,
2099-
SecGroupID: secGroupID,
2100-
}
2101-
sgRules, err := getSecurityGroupRules(lbaas.network, sgListopts)
2102-
if err != nil && !cpoerrors.IsNotFound(err) {
2103-
return fmt.Errorf(
2104-
"failed to find security group rules in %s: %v", secGroupID, err)
2105-
}
2106-
if len(sgRules) != 0 {
2107-
return nil
2108-
}
2109-
21102093
sgRuleCreateOpts := rules.CreateOpts{
21112094
Direction: direction,
21122095
Protocol: protocol,
@@ -2118,11 +2101,12 @@ func (lbaas *LbaasV2) ensureSecurityRule(
21182101
}
21192102

21202103
mc := metrics.NewMetricContext("security_group_rule", "create")
2121-
_, err = rules.Create(lbaas.network, sgRuleCreateOpts).Extract()
2122-
if mc.ObserveRequest(err) != nil {
2123-
return fmt.Errorf(
2124-
"failed to create rule for security group %s: %v",
2125-
secGroupID, err)
2104+
_, err := rules.Create(lbaas.network, sgRuleCreateOpts).Extract()
2105+
if err != nil && cpoerrors.IsConflictError(err) {
2106+
// Conflict means the SG rule already exists, so ignoring that error.
2107+
return mc.ObserveRequest(nil)
2108+
} else if mc.ObserveRequest(err) != nil {
2109+
return fmt.Errorf("failed to create rule for security group %s: %v", secGroupID, err)
21262110
}
21272111
return nil
21282112
}

pkg/util/errors/errors.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,17 @@ func IsInvalidError(err error) bool {
7777

7878
return false
7979
}
80+
81+
func IsConflictError(err error) bool {
82+
if _, ok := err.(gophercloud.ErrDefault409); ok {
83+
return true
84+
}
85+
86+
if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok {
87+
if errCode.Actual == http.StatusConflict {
88+
return true
89+
}
90+
}
91+
92+
return false
93+
}

0 commit comments

Comments
 (0)