Merge "Allocate service FIP after LB was provisioned"
This commit is contained in:
commit
cdbb19e0f8
|
@ -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