Fix duplicate SG creation for listener peer port

In cases where the listener protcol port is same as the peer port
and allowed_cidr set to 0.0.0.0/0 explicitly, the listener is not
provisioned due to duplicate security group creation for peer port
with None as remote_ip_prefix. Neutron SG defaults remote_ip_prefix
to 0.0.0.0/0 if not specified or None and hence the error SG rule
already exists.

Remove the duplicate entry from the updated_ports.

Story: #2009117
Change-Id: I9dbdb71e9b94bbcc75766a8687a996d5358f3381
This commit is contained in:
Hemanth Nakkina 2021-08-13 11:54:59 +05:30
parent b89c929c12
commit 151a943210
3 changed files with 51 additions and 5 deletions

View File

@ -152,6 +152,7 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
security_group_id=sec_grp_id) security_group_id=sec_grp_id)
updated_ports = [] updated_ports = []
listener_peer_ports = []
for listener in load_balancer.listeners: for listener in load_balancer.listeners:
if (listener.provisioning_status in [constants.PENDING_DELETE, if (listener.provisioning_status in [constants.PENDING_DELETE,
constants.DELETED]): constants.DELETED]):
@ -171,11 +172,17 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
port = (listener.protocol_port, protocol, None) port = (listener.protocol_port, protocol, None)
updated_ports.append(port) updated_ports.append(port)
# As the peer port will hold the tcp connection for keepalived and listener_peer_ports.append(listener.peer_port)
# haproxy session synchronization, so here the security group rule
# should be just related with tcp protocol only. # As the peer port will hold the tcp connection for keepalived and
updated_ports.append( # haproxy session synchronization, so here the security group rule
(listener.peer_port, constants.PROTOCOL_TCP.lower(), None)) # should be just related with tcp protocol only. To avoid adding
# duplicate rules, peer_port info should be added if updated_ports
# does not have the peer_port entry with allowed_cidr 0.0.0.0/0
tcp_lower = constants.PROTOCOL_TCP.lower()
for peer_port in listener_peer_ports:
if (peer_port, tcp_lower, "0.0.0.0/0") not in updated_ports:
updated_ports.append((peer_port, tcp_lower, None))
# Just going to use port_range_max for now because we can assume that # Just going to use port_range_max for now because we can assume that
# port_range_max and min will be the same since this driver is # port_range_max and min will be the same since this driver is

View File

@ -1047,6 +1047,36 @@ class TestAllowedAddressPairsDriver(base.TestCase):
mock.call(expected_create_rule_udp)], mock.call(expected_create_rule_udp)],
any_order=True) any_order=True)
def test_update_vip_when_protocol_and_peer_ports_overlap(self):
lc_1 = data_models.ListenerCidr('l1', '0.0.0.0/0')
listeners = [data_models.Listener(protocol_port=80, peer_port=1024,
protocol=constants.PROTOCOL_TCP),
data_models.Listener(protocol_port=443, peer_port=1025,
protocol=constants.PROTOCOL_TCP),
data_models.Listener(protocol_port=1025, peer_port=1026,
protocol=constants.PROTOCOL_TCP,
allowed_cidrs=[lc_1])]
vip = data_models.Vip(ip_address='10.0.0.2')
lb = data_models.LoadBalancer(id='1', listeners=listeners, vip=vip)
list_sec_grps = self.driver.neutron_client.list_security_groups
list_sec_grps.return_value = {'security_groups': [{'id': 'secgrp-1'}]}
fake_rules = {
'security_group_rules': [
{'id': 'rule-80', 'port_range_max': 80, 'protocol': 'tcp'},
{'id': 'rule-22', 'port_range_max': 22, 'protocol': 'tcp'}
]
}
list_rules = self.driver.neutron_client.list_security_group_rules
list_rules.return_value = fake_rules
delete_rule = self.driver.neutron_client.delete_security_group_rule
create_rule = self.driver.neutron_client.create_security_group_rule
self.driver.update_vip(lb)
delete_rule.assert_called_once_with('rule-22')
# Create SG rule calls should be 4, each for port 1024/1025/1026/443
# No duplicate SG creation for overlap port 1025
self.assertEqual(4, create_rule.call_count)
def test_update_vip_when_listener_deleted(self): def test_update_vip_when_listener_deleted(self):
listeners = [data_models.Listener(protocol_port=80, listeners = [data_models.Listener(protocol_port=80,
protocol=constants.PROTOCOL_TCP), protocol=constants.PROTOCOL_TCP),

View File

@ -0,0 +1,9 @@
---
fixes:
- |
Fixes loadbalancer creation failure when one of the listener port matches
with the octavia generated peer ports and the allowed_cidr is explicitly
set to 0.0.0.0/0 on the listener. This is due to creation of two security
group rules with remote_ip_prefix as None and remote_ip_prefix as 0.0.0.0/0
which neutron rejects the second request with security group rule already
exists.