kuryr-kubernetes/kuryr_kubernetes/controller/drivers/public_ip.py
Antoni Segura Puimedon b9be59ed0b Make ext subnet config optional
It is common for Neutron deployment's policy to forbid GETs to the
public subnet, only allowing GETs for the public net. Since the only
required field of those two for creating a FIP is the public net, let's
change public net to be the only required config option and have the
subnet stick around as optional.

Change-Id: I31c3c51ad2dc12f8f560cbab01c86d04aabb754e
Closes-Bug: 1749921
Signed-off-by: Antoni Segura Puimedon <antonisp@celebdor.com>
(cherry picked from commit 20bc89ff87)
2018-02-20 15:29:54 +00:00

151 lines
4.8 KiB
Python

# Copyright (c) 2017 RedHat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import abc
from kuryr_kubernetes import clients
from neutronclient.common import exceptions as n_exc
from oslo_log import log as logging
import six
LOG = logging.getLogger(__name__)
@six.add_metaclass(abc.ABCMeta)
class BasePubIpDriver(object):
"""Base class for public IP functionality."""
@abc.abstractmethod
def is_ip_available(self, ip_addr):
"""check availability of ip address
:param ip_address:
:returns res_id in case ip is available returns resources id else None
"""
raise NotImplementedError()
@abc.abstractmethod
def allocate_ip(self, pub_net_id, project_id, pub_subnet_id=None,
description=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)
:returns res_id , ip_addr
:res_id - resource id
:ip_addr - ip aaddress
"""
raise NotImplementedError()
@abc.abstractmethod
def free_ip(self, res_id):
"""free ip by resource ID
:param res_id: resource_id
:returns True/False
"""
raise NotImplementedError()
@abc.abstractmethod
def associate(self, res_id, vip_port_id):
"""Associate VIP port id with resource_id
:param res_id: id represents pub ip resource
:param vip_port_id: VIP port id
"""
raise NotImplementedError()
@abc.abstractmethod
def disassociate(self, res_id):
"""Clear association between res_id to any vip port
:param res_id: id represents pub ip resource
"""
class FipPubIpDriver(BasePubIpDriver):
"""Floating IP implementation for public IP capability ."""
def is_ip_available(self, ip_addr):
if ip_addr:
neutron = clients.get_neutron_client()
floating_ips_list = neutron.list_floatingips(
floating_ip_address=ip_addr)
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']
# floating IP not available
LOG.error("Floating IP=%s not available", ip_addr)
else:
LOG.error("Invalid parameter ip_addr=%s", ip_addr)
return None
def allocate_ip(self, pub_net_id, project_id, pub_subnet_id=None,
description=None):
neutron = clients.get_neutron_client()
request = {'floatingip': {
'tenant_id': project_id,
'project_id': project_id,
'floating_network_id': pub_net_id}}
if pub_subnet_id is not None:
request['floatingip']['subnet_id'] = pub_subnet_id
if description is not None:
request['floatingip']['description'] = description
try:
response = neutron.create_floatingip(request)
except n_exc.NeutronClientException as ex:
LOG.error("Failed to create floating IP - netid=%s ", pub_net_id)
raise ex
return response['floatingip']['id'], response[
'floatingip']['floating_ip_address']
def free_ip(self, res_id):
neutron = clients.get_neutron_client()
try:
neutron.delete_floatingip(res_id)
except n_exc.NeutronClientException:
LOG.error("Failed to delete floating_ip_id =%s !",
res_id)
return False
return True
def _update(self, res_id, vip_port_id):
response = None
neutron = clients.get_neutron_client()
try:
response = neutron.update_floatingip(
res_id, {'floatingip': {'port_id': vip_port_id, }})
except n_exc.NeutronClientException as ex:
LOG.error("Failed to update_floatingip ,floating_ip_id=%s,"
"response=%s!", res_id, response)
raise ex
def associate(self, res_id, vip_port_id):
self._update(res_id, vip_port_id)
def disassociate(self, res_id):
self._update(res_id, None)