Allocate service FIP after LB was provisioned
This patch changes the FIP allocation to be only after all LB components were provisioned. With this approach, the FIP allocation is performed just before Kuryr annotates endpoints details, this should reduce the probability for orphan FIPs in case of kuryr-controller restart. In addition it updates FIP allocation to check if FIP already allocated for LB vip before allocating new FIP. Change-Id: Idb734f81a1f4fc60155b0700de275d0b01f52a30 Closes-Bug: 1806647
This commit is contained in:
parent
8080e68174
commit
300dc36b06
|
@ -681,12 +681,14 @@ class ServicePubIpDriver(DriverBase):
|
|||
ALIAS = 'service_public_ip'
|
||||
|
||||
@abc.abstractmethod
|
||||
def acquire_service_pub_ip_info(self, spec_type, spec_lb_ip, project_id):
|
||||
def acquire_service_pub_ip_info(self, spec_type, spec_lb_ip, project_id,
|
||||
port_id_to_be_associated=None):
|
||||
"""Get k8s service loadbalancer IP info based on service spec
|
||||
|
||||
:param spec_type: service.spec.type field
|
||||
:param spec_lb_ip: service spec LoadBlaceIP field
|
||||
:param project_id: openstack project id
|
||||
:param port_id_to_be_associated: port id to associate
|
||||
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
|
|
@ -39,14 +39,16 @@ class FloatingIpServicePubIPDriver(base.ServicePubIpDriver):
|
|||
super(FloatingIpServicePubIPDriver, self).__init__()
|
||||
self._drv_pub_ip = public_ip.FipPubIpDriver()
|
||||
|
||||
def acquire_service_pub_ip_info(self, spec_type, spec_lb_ip, project_id):
|
||||
def acquire_service_pub_ip_info(self, spec_type, spec_lb_ip, project_id,
|
||||
port_id_to_be_associated=None):
|
||||
|
||||
if spec_type != 'LoadBalancer':
|
||||
return None
|
||||
|
||||
if spec_lb_ip:
|
||||
user_specified_ip = spec_lb_ip.format()
|
||||
res_id = self._drv_pub_ip.is_ip_available(user_specified_ip)
|
||||
res_id = self._drv_pub_ip.is_ip_available(user_specified_ip,
|
||||
port_id_to_be_associated)
|
||||
if res_id:
|
||||
service_pub_ip_info = (obj_lbaas.LBaaSPubIp(
|
||||
ip_id=res_id,
|
||||
|
@ -69,9 +71,10 @@ class FloatingIpServicePubIPDriver(base.ServicePubIpDriver):
|
|||
cfg.OptGroup('neutron_defaults'))
|
||||
|
||||
res_id, alloc_ip_addr = (
|
||||
self._drv_pub_ip.allocate_ip(public_network_id, project_id,
|
||||
pub_subnet_id=public_subnet_id,
|
||||
description='kuryr_lb'))
|
||||
self._drv_pub_ip.allocate_ip(
|
||||
public_network_id, project_id, pub_subnet_id=public_subnet_id,
|
||||
description='kuryr_lb',
|
||||
port_id_to_be_associated=port_id_to_be_associated))
|
||||
service_pub_ip_info = obj_lbaas.LBaaSPubIp(ip_id=res_id,
|
||||
ip_addr=alloc_ip_addr,
|
||||
alloc_method='pool')
|
||||
|
|
|
@ -26,10 +26,11 @@ class BasePubIpDriver(object):
|
|||
"""Base class for public IP functionality."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def is_ip_available(self, ip_addr):
|
||||
def is_ip_available(self, ip_addr, port_id_to_be_associated):
|
||||
"""check availability of ip address
|
||||
|
||||
:param ip_address:
|
||||
:param port_id_to_be_associated
|
||||
:returns res_id in case ip is available returns resources id else None
|
||||
|
||||
"""
|
||||
|
@ -37,13 +38,14 @@ class BasePubIpDriver(object):
|
|||
|
||||
@abc.abstractmethod
|
||||
def allocate_ip(self, pub_net_id, project_id, pub_subnet_id=None,
|
||||
description=None):
|
||||
description=None, port_id_to_be_associated=None):
|
||||
"""allocate ip address from public network id
|
||||
|
||||
:param pub_net_id: public network id
|
||||
:param project_id:
|
||||
:param pub_subnet_id: public subnet id (Optional)
|
||||
:param description: string describing request (Optional)
|
||||
:param port_id_to_be_associated: (optional)
|
||||
:returns res_id , ip_addr
|
||||
:res_id - resource id
|
||||
:ip_addr - ip aaddress
|
||||
|
@ -84,7 +86,7 @@ class BasePubIpDriver(object):
|
|||
class FipPubIpDriver(BasePubIpDriver):
|
||||
"""Floating IP implementation for public IP capability ."""
|
||||
|
||||
def is_ip_available(self, ip_addr):
|
||||
def is_ip_available(self, ip_addr, port_id_to_be_associated=None):
|
||||
if ip_addr:
|
||||
neutron = clients.get_neutron_client()
|
||||
floating_ips_list = neutron.list_floatingips(
|
||||
|
@ -92,9 +94,11 @@ class FipPubIpDriver(BasePubIpDriver):
|
|||
for entry in floating_ips_list['floatingips']:
|
||||
if not entry:
|
||||
continue
|
||||
if (entry['floating_ip_address'] == ip_addr and
|
||||
not entry['port_id']):
|
||||
return entry['id']
|
||||
if (entry['floating_ip_address'] == ip_addr):
|
||||
if not entry['port_id'] or (
|
||||
port_id_to_be_associated is not None
|
||||
and entry['port_id'] == port_id_to_be_associated):
|
||||
return entry['id']
|
||||
# floating IP not available
|
||||
LOG.error("Floating IP=%s not available", ip_addr)
|
||||
else:
|
||||
|
@ -102,8 +106,21 @@ class FipPubIpDriver(BasePubIpDriver):
|
|||
return None
|
||||
|
||||
def allocate_ip(self, pub_net_id, project_id, pub_subnet_id=None,
|
||||
description=None):
|
||||
description=None, port_id_to_be_associated=None):
|
||||
neutron = clients.get_neutron_client()
|
||||
|
||||
if port_id_to_be_associated is not None:
|
||||
floating_ips_list = neutron.list_floatingips(
|
||||
port_id=port_id_to_be_associated)
|
||||
for entry in floating_ips_list['floatingips']:
|
||||
if not entry:
|
||||
continue
|
||||
if (entry['floating_ip_address']):
|
||||
LOG.debug('FIP %s already allocated to port %s',
|
||||
entry['floating_ip_address'],
|
||||
port_id_to_be_associated)
|
||||
return entry['id'], entry['floating_ip_address']
|
||||
|
||||
request = {'floatingip': {
|
||||
'tenant_id': project_id,
|
||||
'project_id': project_id,
|
||||
|
|
|
@ -248,14 +248,23 @@ class LoadBalancerHandler(k8s_base.ResourceEventHandler):
|
|||
if not lbaas_state:
|
||||
lbaas_state = obj_lbaas.LBaaSState()
|
||||
|
||||
prev_service_pub_ip_info = lbaas_state.service_pub_ip_info
|
||||
if self._sync_lbaas_members(endpoints, lbaas_state, lbaas_spec):
|
||||
# For LoadBalancer service type, update k8s-service status with
|
||||
# floating IP address if needed.
|
||||
if (prev_service_pub_ip_info != lbaas_state.service_pub_ip_info
|
||||
and lbaas_state.service_pub_ip_info is not None):
|
||||
self._update_lb_status(
|
||||
endpoints, lbaas_state.service_pub_ip_info.ip_addr)
|
||||
# Note(yboaron) For LoadBalancer services, we should allocate FIP,
|
||||
# associate it to LB VIP and update K8S service status
|
||||
if lbaas_state.service_pub_ip_info is None:
|
||||
service_pub_ip_info = (
|
||||
self._drv_service_pub_ip.acquire_service_pub_ip_info(
|
||||
lbaas_spec.type,
|
||||
lbaas_spec.lb_ip,
|
||||
lbaas_spec.project_id,
|
||||
lbaas_state.loadbalancer.port_id))
|
||||
if service_pub_ip_info:
|
||||
self._drv_service_pub_ip.associate_pub_ip(
|
||||
service_pub_ip_info, lbaas_state.loadbalancer.port_id)
|
||||
lbaas_state.service_pub_ip_info = service_pub_ip_info
|
||||
self._update_lb_status(
|
||||
endpoints,
|
||||
lbaas_state.service_pub_ip_info.ip_addr)
|
||||
# REVISIT(ivc): since _sync_lbaas_members is responsible for
|
||||
# creating all lbaas components (i.e. load balancer, listeners,
|
||||
# pools, members), it is currently possible for it to fail (due
|
||||
|
@ -588,18 +597,6 @@ class LoadBalancerHandler(k8s_base.ResourceEventHandler):
|
|||
security_groups_ids=lbaas_spec.security_groups_ids,
|
||||
service_type=lbaas_spec.type,
|
||||
provider=self._lb_provider)
|
||||
if lbaas_state.service_pub_ip_info is None:
|
||||
service_pub_ip_info = (
|
||||
self._drv_service_pub_ip.acquire_service_pub_ip_info(
|
||||
lbaas_spec.type,
|
||||
lbaas_spec.lb_ip,
|
||||
lbaas_spec.project_id))
|
||||
if service_pub_ip_info:
|
||||
# if loadbalancerIP should be defined for lbaas,
|
||||
# associate it to lbaas VIP
|
||||
self._drv_service_pub_ip.associate_pub_ip(
|
||||
service_pub_ip_info, lb.port_id)
|
||||
lbaas_state.service_pub_ip_info = service_pub_ip_info
|
||||
changed = True
|
||||
elif lbaas_state.service_pub_ip_info:
|
||||
self._drv_service_pub_ip.release_pub_ip(
|
||||
|
|
|
@ -498,15 +498,27 @@ class TestLoadBalancerHandler(test_base.TestCase):
|
|||
|
||||
def test_on_present(self):
|
||||
lbaas_spec = mock.sentinel.lbaas_spec
|
||||
lbaas_spec.type = 'DummyType'
|
||||
lbaas_spec.lb_ip = "1.2.3.4"
|
||||
lbaas_spec.project_id = 12345678
|
||||
|
||||
lbaas_state = mock.sentinel.lbaas_state
|
||||
lbaas_state.service_pub_ip_info = None
|
||||
loadbalancer = mock.Mock()
|
||||
loadbalancer.port_id = 12345678
|
||||
lbaas_state.loadbalancer = loadbalancer
|
||||
endpoints = mock.sentinel.endpoints
|
||||
|
||||
m_drv_service_pub_ip = mock.Mock()
|
||||
m_drv_service_pub_ip.acquire_service_pub_ip_info.return_value = None
|
||||
m_drv_service_pub_ip.associate_pub_ip.return_value = True
|
||||
|
||||
m_handler = mock.Mock(spec=h_lbaas.LoadBalancerHandler)
|
||||
m_handler._get_lbaas_spec.return_value = lbaas_spec
|
||||
m_handler._should_ignore.return_value = False
|
||||
m_handler._get_lbaas_state.return_value = lbaas_state
|
||||
m_handler._sync_lbaas_members.return_value = True
|
||||
m_handler._drv_service_pub_ip = m_drv_service_pub_ip
|
||||
|
||||
h_lbaas.LoadBalancerHandler.on_present(m_handler, endpoints)
|
||||
|
||||
|
@ -520,6 +532,22 @@ class TestLoadBalancerHandler(test_base.TestCase):
|
|||
m_handler._update_lb_status.assert_not_called()
|
||||
|
||||
def _fake_sync_lbaas_members(self, endpoints, lbaas_state, lbaas_spec):
|
||||
loadbalancer = mock.Mock()
|
||||
loadbalancer.port_id = 12345678
|
||||
lbaas_state.loadbalancer = loadbalancer
|
||||
lbaas_state.service_pub_ip_info = None
|
||||
return True
|
||||
|
||||
def test_on_present_loadbalancer_service(self):
|
||||
lbaas_spec = mock.sentinel.lbaas_spec
|
||||
lbaas_spec.type = 'LoadBalancer'
|
||||
lbaas_spec.lb_ip = "1.2.3.4"
|
||||
lbaas_spec.project_id = 12345678
|
||||
|
||||
lbaas_state = mock.sentinel.lbaas_state
|
||||
lbaas_state.service_pub_ip_info = None
|
||||
endpoints = mock.sentinel.endpoints
|
||||
|
||||
floating_ip = {'floating_ip_address': '1.2.3.5',
|
||||
'id': 'ec29d641-fec4-4f67-928a-124a76b3a888'}
|
||||
|
||||
|
@ -527,20 +555,17 @@ class TestLoadBalancerHandler(test_base.TestCase):
|
|||
ip_id=floating_ip['id'],
|
||||
ip_addr=floating_ip['floating_ip_address'], alloc_method='kk')
|
||||
|
||||
lbaas_state.service_pub_ip_info = service_pub_ip_info
|
||||
return True
|
||||
|
||||
def test_on_present_loadbalancer_service(self):
|
||||
lbaas_spec = mock.sentinel.lbaas_spec
|
||||
lbaas_state = mock.sentinel.lbaas_state
|
||||
lbaas_state.service_pub_ip_info = None
|
||||
endpoints = mock.sentinel.endpoints
|
||||
m_drv_service_pub_ip = mock.Mock()
|
||||
m_drv_service_pub_ip.acquire_service_pub_ip_info.return_value = (
|
||||
service_pub_ip_info)
|
||||
m_drv_service_pub_ip.associate_pub_ip.return_value = True
|
||||
|
||||
m_handler = mock.Mock(spec=h_lbaas.LoadBalancerHandler)
|
||||
m_handler._get_lbaas_spec.return_value = lbaas_spec
|
||||
m_handler._should_ignore.return_value = False
|
||||
m_handler._get_lbaas_state.return_value = lbaas_state
|
||||
m_handler._sync_lbaas_members = self._fake_sync_lbaas_members
|
||||
m_handler._drv_service_pub_ip = m_drv_service_pub_ip
|
||||
|
||||
h_lbaas.LoadBalancerHandler.on_present(m_handler, endpoints)
|
||||
|
||||
|
@ -553,8 +578,18 @@ class TestLoadBalancerHandler(test_base.TestCase):
|
|||
|
||||
def test_on_present_rollback(self):
|
||||
lbaas_spec = mock.sentinel.lbaas_spec
|
||||
lbaas_spec.type = 'ClusterIp'
|
||||
lbaas_spec.lb_ip = '1.2.3.4'
|
||||
lbaas_spec.project_id = '12345678'
|
||||
lbaas_state = mock.sentinel.lbaas_state
|
||||
lbaas_state.service_pub_ip_info = None
|
||||
loadbalancer = mock.Mock()
|
||||
loadbalancer.port_id = 12345678
|
||||
lbaas_state.loadbalancer = loadbalancer
|
||||
m_drv_service_pub_ip = mock.Mock()
|
||||
m_drv_service_pub_ip.acquire_service_pub_ip_info.return_value = None
|
||||
m_drv_service_pub_ip.associate_pub_ip.return_value = True
|
||||
|
||||
endpoints = mock.sentinel.endpoints
|
||||
|
||||
m_handler = mock.Mock(spec=h_lbaas.LoadBalancerHandler)
|
||||
|
@ -564,7 +599,7 @@ class TestLoadBalancerHandler(test_base.TestCase):
|
|||
m_handler._sync_lbaas_members.return_value = True
|
||||
m_handler._set_lbaas_state.side_effect = (
|
||||
k_exc.K8sResourceNotFound('ep'))
|
||||
|
||||
m_handler._drv_service_pub_ip = m_drv_service_pub_ip
|
||||
h_lbaas.LoadBalancerHandler.on_present(m_handler, endpoints)
|
||||
|
||||
m_handler._get_lbaas_spec.assert_called_once_with(endpoints)
|
||||
|
|
Loading…
Reference in New Issue