20bc89ff87
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>
151 lines
4.8 KiB
Python
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)
|