ded6b6debc
Since we already migrated fully to Python3, it's time to also remove bits needed for Python2. One of those libs is six. Change-Id: Ib984d7b4b3c1048ed091c78986c634689a8ace8c
179 lines
6.3 KiB
Python
179 lines
6.3 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 openstack import exceptions as os_exc
|
|
from oslo_log import log as logging
|
|
|
|
from kuryr_kubernetes import clients
|
|
from kuryr_kubernetes.controller.drivers import utils
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class BasePubIpDriver(object, metaclass=abc.ABCMeta):
|
|
"""Base class for public IP functionality."""
|
|
|
|
@abc.abstractmethod
|
|
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
|
|
|
|
"""
|
|
raise NotImplementedError()
|
|
|
|
@abc.abstractmethod
|
|
def allocate_ip(self, pub_net_id, project_id, pub_subnet_id=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
|
|
|
|
|
|
"""
|
|
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, port_id_to_be_associated=None):
|
|
if ip_addr:
|
|
os_net = clients.get_network_client()
|
|
floating_ips_list = os_net.ips(floating_ip_address=ip_addr)
|
|
for entry in floating_ips_list:
|
|
if not entry:
|
|
continue
|
|
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:
|
|
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, port_id_to_be_associated=None):
|
|
os_net = clients.get_network_client()
|
|
|
|
if port_id_to_be_associated is not None:
|
|
floating_ips_list = os_net.ips(
|
|
port_id=port_id_to_be_associated)
|
|
for entry in floating_ips_list:
|
|
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']
|
|
|
|
try:
|
|
fip = os_net.create_ip(floating_network_id=pub_net_id,
|
|
project_id=project_id,
|
|
subnet_id=pub_subnet_id,
|
|
description=description)
|
|
except os_exc.SDKException:
|
|
LOG.exception("Failed to create floating IP - netid=%s ",
|
|
pub_net_id)
|
|
raise
|
|
utils.tag_neutron_resources([fip])
|
|
return fip.id, fip.floating_ip_address
|
|
|
|
def free_ip(self, res_id):
|
|
os_net = clients.get_network_client()
|
|
try:
|
|
os_net.delete_ip(res_id)
|
|
except os_exc.SDKException:
|
|
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
|
|
os_net = clients.get_network_client()
|
|
try:
|
|
response = os_net.update_ip(res_id, port_id=vip_port_id)
|
|
except os_exc.ConflictException:
|
|
LOG.warning("Conflict when assigning floating IP with id %s. "
|
|
"Checking if it's already assigned correctly.", res_id)
|
|
try:
|
|
fip = os_net.get_ip(res_id)
|
|
except os_exc.NotFoundException:
|
|
LOG.exception("Failed to get FIP %s - it doesn't exist.",
|
|
res_id)
|
|
raise
|
|
|
|
if fip.port_id == vip_port_id:
|
|
LOG.debug('FIP %s already assigned to %s', res_id,
|
|
vip_port_id)
|
|
else:
|
|
LOG.exception('Failed to assign FIP %s to VIP port %s. It is '
|
|
'probably already bound', res_id, vip_port_id)
|
|
raise
|
|
except os_exc.SDKException:
|
|
# NOTE(gryf): the response will be None, since in case of
|
|
# exception, there will be no value assigned to response variable.
|
|
LOG.error("Failed to update_ip, floating_ip_id=%s,"
|
|
"response=%s!", res_id, response)
|
|
raise
|
|
|
|
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)
|