2016-11-15 20:21:27 +03:00
|
|
|
# Copyright (c) 2016 Mirantis, 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
|
|
|
|
|
2017-03-28 09:47:09 +08:00
|
|
|
from kuryr.lib._i18n import _
|
2016-11-15 20:21:27 +03:00
|
|
|
from stevedore import driver as stv_driver
|
|
|
|
|
|
|
|
from kuryr_kubernetes import config
|
|
|
|
|
|
|
|
_DRIVER_NAMESPACE_BASE = 'kuryr_kubernetes.controller.drivers'
|
|
|
|
_DRIVER_MANAGERS = {}
|
2018-06-15 14:11:34 +08:00
|
|
|
_MULTI_VIF_DRIVERS = []
|
2016-11-15 20:21:27 +03:00
|
|
|
|
|
|
|
|
|
|
|
class DriverBase(object):
|
|
|
|
"""Base class for controller drivers.
|
|
|
|
|
|
|
|
Subclasses must define an *ALIAS* attribute that is used to find a driver
|
|
|
|
implementation by `get_instance` class method which utilises
|
|
|
|
`stevedore.driver.DriverManager` with the namespace set to
|
|
|
|
'kuryr_kubernetes.controller.drivers.*ALIAS*' and the name of
|
|
|
|
the driver determined from the '[kubernetes]/*ALIAS*_driver' configuration
|
|
|
|
parameter.
|
|
|
|
|
|
|
|
Usage example:
|
|
|
|
|
2020-02-28 12:00:19 +01:00
|
|
|
class SomeDriverInterface(DriverBase, metaclass=abc.ABCMeta):
|
2016-11-15 20:21:27 +03:00
|
|
|
ALIAS = 'driver_alias'
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def some_method(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
driver = SomeDriverInterface.get_instance()
|
|
|
|
driver.some_method()
|
|
|
|
"""
|
|
|
|
|
|
|
|
@classmethod
|
2018-08-27 17:09:38 +09:00
|
|
|
def get_instance(cls, specific_driver=None, scope='default'):
|
|
|
|
"""Get an implementing driver instance.
|
|
|
|
|
|
|
|
:param specific_driver: Loads a specific driver instead of using conf.
|
|
|
|
Uses separate manager entry so that loading of
|
|
|
|
default/other drivers is not affected.
|
|
|
|
:param scope: Loads the driver in the given scope (if independent
|
|
|
|
instances of a driver are required)
|
|
|
|
"""
|
2016-11-15 20:21:27 +03:00
|
|
|
|
|
|
|
alias = cls.ALIAS
|
2018-08-27 17:09:38 +09:00
|
|
|
|
|
|
|
if specific_driver:
|
|
|
|
driver_key = '{}:{}:{}'.format(alias, specific_driver, scope)
|
|
|
|
else:
|
|
|
|
driver_key = '{}:_from_cfg:{}'.format(alias, scope)
|
|
|
|
|
2016-11-15 20:21:27 +03:00
|
|
|
try:
|
2018-08-27 17:09:38 +09:00
|
|
|
manager = _DRIVER_MANAGERS[driver_key]
|
2016-11-15 20:21:27 +03:00
|
|
|
except KeyError:
|
2018-08-27 17:09:38 +09:00
|
|
|
driver_name = (specific_driver or
|
|
|
|
config.CONF.kubernetes[alias + '_driver'])
|
|
|
|
|
2016-11-15 20:21:27 +03:00
|
|
|
manager = stv_driver.DriverManager(
|
|
|
|
namespace="%s.%s" % (_DRIVER_NAMESPACE_BASE, alias),
|
2018-08-27 17:09:38 +09:00
|
|
|
name=driver_name,
|
2016-11-15 20:21:27 +03:00
|
|
|
invoke_on_load=True)
|
2018-08-27 17:09:38 +09:00
|
|
|
_DRIVER_MANAGERS[driver_key] = manager
|
2016-11-15 20:21:27 +03:00
|
|
|
|
|
|
|
driver = manager.driver
|
|
|
|
if not isinstance(driver, cls):
|
2017-03-28 09:47:09 +08:00
|
|
|
raise TypeError(_("Invalid %(alias)r driver type: %(driver)s, "
|
|
|
|
"must be a subclass of %(type)s") % {
|
2017-06-08 15:30:40 +03:00
|
|
|
'alias': alias,
|
|
|
|
'driver': driver.__class__.__name__,
|
|
|
|
'type': cls})
|
2016-11-15 20:21:27 +03:00
|
|
|
return driver
|
|
|
|
|
2018-04-25 09:31:10 +00:00
|
|
|
def __str__(self):
|
|
|
|
return self.__class__.__name__
|
|
|
|
|
2016-11-15 20:21:27 +03:00
|
|
|
|
2020-02-28 12:00:19 +01:00
|
|
|
class PodProjectDriver(DriverBase, metaclass=abc.ABCMeta):
|
2016-11-15 20:21:27 +03:00
|
|
|
"""Provides an OpenStack project ID for Kubernetes Pod ports."""
|
|
|
|
|
|
|
|
ALIAS = 'pod_project'
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def get_project(self, pod):
|
|
|
|
"""Get an OpenStack project ID for Kubernetes Pod ports.
|
|
|
|
|
|
|
|
:param pod: dict containing Kubernetes Pod object
|
|
|
|
:return: project ID
|
|
|
|
"""
|
|
|
|
|
|
|
|
raise NotImplementedError()
|
2016-11-16 15:19:11 +03:00
|
|
|
|
|
|
|
|
2020-02-28 12:00:19 +01:00
|
|
|
class ServiceProjectDriver(DriverBase, metaclass=abc.ABCMeta):
|
2017-01-31 23:19:32 +03:00
|
|
|
"""Provides an OpenStack project ID for Kubernetes Services."""
|
|
|
|
|
|
|
|
ALIAS = 'service_project'
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def get_project(self, service):
|
|
|
|
"""Get an OpenStack project ID for Kubernetes Service.
|
|
|
|
|
|
|
|
:param service: dict containing Kubernetes Service object
|
|
|
|
:return: project ID
|
|
|
|
"""
|
|
|
|
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
|
2020-02-28 12:00:19 +01:00
|
|
|
class NamespaceProjectDriver(DriverBase, metaclass=abc.ABCMeta):
|
2018-07-10 17:19:53 +02:00
|
|
|
"""Provides an OpenStack project ID for Kubernetes Namespace."""
|
|
|
|
|
|
|
|
ALIAS = 'namespace_project'
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def get_project(self, namespace):
|
|
|
|
"""Get an OpenStack project ID for Kubernetes Namespace.
|
|
|
|
|
|
|
|
:param service: dict containing Kubernetes Namespace object
|
|
|
|
:return: project ID
|
|
|
|
"""
|
|
|
|
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
|
2020-02-28 12:00:19 +01:00
|
|
|
class PodSubnetsDriver(DriverBase, metaclass=abc.ABCMeta):
|
2016-11-16 15:19:11 +03:00
|
|
|
"""Provides subnets for Kubernetes Pods."""
|
|
|
|
|
|
|
|
ALIAS = 'pod_subnets'
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def get_subnets(self, pod, project_id):
|
|
|
|
"""Get subnets for Pod.
|
|
|
|
|
|
|
|
:param pod: dict containing Kubernetes Pod object
|
|
|
|
:param project_id: OpenStack project ID
|
|
|
|
:return: dict containing the mapping 'subnet_id' -> 'network' for all
|
|
|
|
the subnets we want to create ports on, where 'network' is an
|
|
|
|
`os_vif.network.Network` object containing a single
|
|
|
|
`os_vif.subnet.Subnet` object corresponding to the 'subnet_id'
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
2016-11-18 13:43:46 +03:00
|
|
|
|
2018-06-29 14:38:18 +02:00
|
|
|
def create_namespace_network(self, namespace, project_id):
|
2018-04-18 11:03:27 +00:00
|
|
|
"""Create network resources for a namespace.
|
|
|
|
|
|
|
|
:param namespace: string with the namespace name
|
2018-06-29 14:38:18 +02:00
|
|
|
:param project_id: OpenStack project ID
|
|
|
|
:return: dict with the keys and values for the CRD spec, such as
|
|
|
|
routerId or subnetId
|
2018-04-18 11:03:27 +00:00
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2018-04-18 11:31:48 +00:00
|
|
|
def delete_namespace_subnet(self, kuryr_net_crd):
|
|
|
|
"""Delete network resources associated to a namespace.
|
|
|
|
|
2020-02-10 08:46:03 +01:00
|
|
|
:param kuryr_net_crd: kuryrnetwork CRD obj dict that contains Neutron's
|
2018-04-18 11:31:48 +00:00
|
|
|
network resources associated to a namespace
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2018-06-29 14:38:18 +02:00
|
|
|
def rollback_network_resources(self, crd_spec, namespace):
|
2018-04-18 11:03:27 +00:00
|
|
|
"""Rollback created network resources for a namespace.
|
|
|
|
|
2018-06-29 14:38:18 +02:00
|
|
|
:param crd_spec: dict with the keys and values for the CRD spec, such
|
|
|
|
as routerId or subnetId
|
2018-04-18 11:03:27 +00:00
|
|
|
:param namespace: name of the Kubernetes namespace object
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2019-07-18 16:11:54 +02:00
|
|
|
def cleanup_namespace_networks(self, namespace):
|
|
|
|
"""Clean up network leftover on the namespace.
|
|
|
|
|
|
|
|
Due to Kuryr controller restarts it may happen that some network
|
|
|
|
resources are leftover. This method ensures they are deleted upon
|
|
|
|
retries.
|
|
|
|
|
|
|
|
:param namespace: name of the Kubernetes namespace object
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2016-11-18 13:43:46 +03:00
|
|
|
|
2020-02-28 12:00:19 +01:00
|
|
|
class ServiceSubnetsDriver(DriverBase, metaclass=abc.ABCMeta):
|
2017-01-31 23:19:32 +03:00
|
|
|
"""Provides subnets for Kubernetes Services."""
|
|
|
|
|
|
|
|
ALIAS = 'service_subnets'
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def get_subnets(self, service, project_id):
|
|
|
|
"""Get subnets for Service.
|
|
|
|
|
|
|
|
:param service: dict containing Kubernetes Pod object
|
|
|
|
:param project_id: OpenStack project ID
|
|
|
|
:return: dict containing the mapping 'subnet_id' -> 'network' for all
|
|
|
|
the subnets we want to create ports on, where 'network' is an
|
|
|
|
`os_vif.network.Network` object containing a single
|
|
|
|
`os_vif.subnet.Subnet` object corresponding to the 'subnet_id'
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
|
2020-02-28 12:00:19 +01:00
|
|
|
class PodSecurityGroupsDriver(DriverBase, metaclass=abc.ABCMeta):
|
2016-11-18 13:43:46 +03:00
|
|
|
"""Provides security groups for Kubernetes Pods."""
|
|
|
|
|
|
|
|
ALIAS = 'pod_security_groups'
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def get_security_groups(self, pod, project_id):
|
|
|
|
"""Get a list of security groups' IDs for Pod.
|
|
|
|
|
|
|
|
:param pod: dict containing Kubernetes Pod object
|
|
|
|
:param project_id: OpenStack project ID
|
|
|
|
:return: list containing security groups' IDs
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
2016-11-21 04:18:05 +03:00
|
|
|
|
2018-12-17 12:53:51 +00:00
|
|
|
def create_sg_rules(self, pod):
|
|
|
|
"""Create security group rules for a pod.
|
|
|
|
|
|
|
|
:param pod: dict containing Kubernetes Pod object
|
2019-02-28 22:46:22 +00:00
|
|
|
:return: a list containing podSelectors of CRDs
|
|
|
|
that had security group rules created
|
2018-12-17 12:53:51 +00:00
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
def delete_sg_rules(self, pod):
|
|
|
|
"""Delete security group rules for a pod
|
|
|
|
|
|
|
|
:param pod: dict containing Kubernetes Pod object
|
2019-02-28 22:46:22 +00:00
|
|
|
:return: a list containing podSelectors of CRDs
|
|
|
|
that had security group rules deleted
|
2018-12-17 12:53:51 +00:00
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
def update_sg_rules(self, pod):
|
|
|
|
"""Update security group rules for a pod
|
|
|
|
|
|
|
|
:param pod: dict containing Kubernetes Pod object
|
2019-02-28 22:46:22 +00:00
|
|
|
:return: a list containing podSelectors of CRDs
|
|
|
|
that had security group rules updated
|
2018-12-17 12:53:51 +00:00
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2018-12-30 22:10:51 +00:00
|
|
|
def delete_namespace_sg_rules(self, namespace):
|
|
|
|
"""Delete security group rule associated to a namespace.
|
|
|
|
|
|
|
|
:param namespace: dict containing K8S Namespace object
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
def create_namespace_sg_rules(self, namespace):
|
|
|
|
"""Create security group rule associated to a namespace.
|
|
|
|
|
|
|
|
:param namespace: dict containing K8S Namespace object
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
def update_namespace_sg_rules(self, namespace):
|
|
|
|
"""Update security group rule associated to a namespace.
|
|
|
|
|
|
|
|
:param namespace: dict containing K8S Namespace object
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2016-11-21 04:18:05 +03:00
|
|
|
|
2020-02-28 12:00:19 +01:00
|
|
|
class ServiceSecurityGroupsDriver(DriverBase, metaclass=abc.ABCMeta):
|
2017-01-31 23:19:32 +03:00
|
|
|
"""Provides security groups for Kubernetes Services."""
|
|
|
|
|
|
|
|
ALIAS = 'service_security_groups'
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def get_security_groups(self, service, project_id):
|
|
|
|
"""Get a list of security groups' IDs for Service.
|
|
|
|
|
|
|
|
:param service: dict containing Kubernetes Service object
|
|
|
|
:param project_id: OpenStack project ID
|
|
|
|
:return: list containing security groups' IDs
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
|
2020-02-28 12:00:19 +01:00
|
|
|
class PodVIFDriver(DriverBase, metaclass=abc.ABCMeta):
|
2016-11-21 04:18:05 +03:00
|
|
|
"""Manages Neutron ports to provide VIFs for Kubernetes Pods."""
|
|
|
|
|
|
|
|
ALIAS = 'pod_vif'
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def request_vif(self, pod, project_id, subnets, security_groups):
|
|
|
|
"""Links Neutron port to pod and returns it as VIF object.
|
|
|
|
|
|
|
|
Implementing drivers must ensure the Neutron port satisfying the
|
|
|
|
requested parameters is present and is valid for specified `pod`. It
|
|
|
|
is up to the implementing drivers to either create new ports on each
|
|
|
|
request or reuse available ports when possible.
|
|
|
|
|
|
|
|
Implementing drivers may return a VIF object with its `active` field
|
|
|
|
set to 'False' to indicate that Neutron port requires additional
|
|
|
|
actions to enable network connectivity after VIF is plugged (e.g.
|
|
|
|
setting up OpenFlow and/or iptables rules by OpenVSwitch agent). In
|
|
|
|
that case the Controller will call driver's `activate_vif` method
|
|
|
|
and the CNI plugin will block until it receives activation
|
|
|
|
confirmation from the Controller.
|
|
|
|
|
|
|
|
:param pod: dict containing Kubernetes Pod object
|
|
|
|
:param project_id: OpenStack project ID
|
|
|
|
:param subnets: dict containing subnet mapping as returned by
|
|
|
|
`PodSubnetsDriver.get_subnets`. If multiple entries
|
|
|
|
are present in that mapping, it is guaranteed that
|
|
|
|
all entries have the same value of `Network.id`.
|
|
|
|
:param security_groups: list containing security groups' IDs as
|
|
|
|
returned by
|
|
|
|
`PodSecurityGroupsDriver.get_security_groups`
|
|
|
|
:return: VIF object
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2017-02-22 12:00:48 +01:00
|
|
|
def request_vifs(self, pod, project_id, subnets, security_groups,
|
2021-12-13 21:53:52 +00:00
|
|
|
num_ports, semaphore):
|
2017-02-22 12:00:48 +01:00
|
|
|
"""Creates Neutron ports for pods and returns them as VIF objects list.
|
|
|
|
|
|
|
|
It follows the same pattern as request_vif but creating the specified
|
|
|
|
amount of ports and vif objects at num_ports parameter.
|
|
|
|
|
|
|
|
The port creation request is generic as it not going to be used by the
|
|
|
|
pod -- at least not all of them. Additionally, in order to save Neutron
|
|
|
|
calls, the ports creation is handled in a bulk request.
|
|
|
|
|
|
|
|
:param pod: dict containing Kubernetes Pod object
|
|
|
|
:param project_id: OpenStack project ID
|
|
|
|
:param subnets: dict containing subnet mapping as returned by
|
|
|
|
`PodSubnetsDriver.get_subnets`. If multiple entries
|
|
|
|
are present in that mapping, it is guaranteed that
|
|
|
|
all entries have the same value of `Network.id`.
|
|
|
|
:param security_groups: list containing security groups' IDs as
|
|
|
|
returned by
|
|
|
|
`PodSecurityGroupsDriver.get_security_groups`
|
|
|
|
:param num_ports: number of ports to be created
|
2021-12-13 21:53:52 +00:00
|
|
|
:param semaphore: a eventlet Semaphore to limit the number of create
|
|
|
|
Port in bulk running in parallel
|
2017-02-22 12:00:48 +01:00
|
|
|
:return: VIF objects list
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2016-11-21 04:18:05 +03:00
|
|
|
@abc.abstractmethod
|
2022-08-23 11:54:04 +02:00
|
|
|
def release_vif(self, pod, vif, project_id=None):
|
2016-11-21 04:18:05 +03:00
|
|
|
"""Unlinks Neutron port corresponding to VIF object from pod.
|
|
|
|
|
|
|
|
Implementing drivers must ensure the port is either deleted or made
|
|
|
|
available for reuse by `PodVIFDriver.request_vif`.
|
|
|
|
|
|
|
|
:param pod: dict containing Kubernetes Pod object
|
|
|
|
:param vif: VIF object as returned by `PodVIFDriver.request_vif`
|
2017-02-22 11:10:05 +01:00
|
|
|
:param project_id: OpenStack project ID
|
2016-11-21 04:18:05 +03:00
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2022-08-23 11:54:04 +02:00
|
|
|
def release_vifs(self, pods, vifs, project_id=None):
|
2017-02-22 12:00:48 +01:00
|
|
|
"""Unlinks Neutron ports corresponding to VIF objects.
|
|
|
|
|
|
|
|
It follows the same pattern as release_vif but releasing num_ports
|
|
|
|
ports. Ideally it will also make use of bulk request to save Neutron
|
|
|
|
calls in the release/recycle process.
|
|
|
|
:param pods: list of dict containing Kubernetes Pod objects
|
|
|
|
:param vifs: list of VIF objects as returned by
|
|
|
|
`PodVIFDriver.request_vif`
|
|
|
|
:param project_id: (optional) OpenStack project ID
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2016-11-21 04:18:05 +03:00
|
|
|
@abc.abstractmethod
|
2021-06-07 09:41:36 +02:00
|
|
|
def activate_vif(self, vif, **kwargs):
|
2016-11-21 04:18:05 +03:00
|
|
|
"""Updates VIF to become active.
|
|
|
|
|
|
|
|
Implementing drivers should update the specified `vif` object's
|
|
|
|
`active` field to 'True' but must ensure that the corresponding
|
|
|
|
Neutron port is fully configured (i.e. the container using the `vif`
|
|
|
|
can access the requested network resources).
|
|
|
|
|
|
|
|
Implementing drivers may raise `ResourceNotReady` exception to
|
|
|
|
indicate that port activation should be retried later which will
|
|
|
|
cause `activate_vif` to be called again with the same arguments.
|
|
|
|
|
|
|
|
This method may be called before, after or while the VIF is being
|
|
|
|
plugged by the CNI plugin.
|
|
|
|
|
|
|
|
:param vif: VIF object as returned by `PodVIFDriver.request_vif`
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
2017-02-14 03:33:02 +03:00
|
|
|
|
2018-11-07 18:46:07 +01:00
|
|
|
@abc.abstractmethod
|
|
|
|
def update_vif_sgs(self, pod, security_groups):
|
|
|
|
"""Update VIF security groups.
|
|
|
|
|
|
|
|
Implementing drivers should update the port associated to the pod
|
|
|
|
with the specified security groups.
|
|
|
|
|
|
|
|
:param pod: dict containing Kubernetes Pod object
|
|
|
|
:param security_groups: list containing security groups' IDs as
|
|
|
|
returned by
|
|
|
|
`PodSecurityGroupsDriver.get_security_groups`
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2017-02-14 03:33:02 +03:00
|
|
|
|
2020-02-28 12:00:19 +01:00
|
|
|
class MultiVIFDriver(DriverBase, metaclass=abc.ABCMeta):
|
2018-06-15 14:11:34 +08:00
|
|
|
"""Manages additional ports of Kubernetes Pods."""
|
|
|
|
|
|
|
|
ALIAS = 'multi_vif'
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def request_additional_vifs(
|
|
|
|
self, pod, project_id, security_groups):
|
|
|
|
"""Links Neutron ports to pod and returns them as a list of VIF objects.
|
|
|
|
|
|
|
|
Implementing drivers must be able to parse the additional interface
|
|
|
|
definition from pod. The format of the definition is up to the
|
|
|
|
implementation of each driver. Then implementing drivers must invoke
|
|
|
|
the VIF drivers to either create new Neutron ports on each request or
|
|
|
|
reuse available ports when possible.
|
|
|
|
|
|
|
|
:param pod: dict containing Kubernetes Pod object
|
|
|
|
:param project_id: OpenStack project ID
|
|
|
|
:param security_groups: list containing security groups' IDs as
|
|
|
|
returned by
|
|
|
|
`PodSecurityGroupsDriver.get_security_groups`
|
|
|
|
:return: VIF object list
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_enabled_drivers(cls):
|
|
|
|
if _MULTI_VIF_DRIVERS:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
drivers = config.CONF.kubernetes['multi_vif_drivers']
|
|
|
|
for driver in drivers:
|
|
|
|
_MULTI_VIF_DRIVERS.append(cls.get_instance(driver))
|
|
|
|
return _MULTI_VIF_DRIVERS
|
|
|
|
|
|
|
|
|
2017-02-14 03:33:02 +03:00
|
|
|
class LBaaSDriver(DriverBase):
|
2018-01-22 16:43:00 +02:00
|
|
|
"""Base class for Openstack loadbalancer services."""
|
2017-02-14 03:33:02 +03:00
|
|
|
|
2017-03-28 18:43:26 +03:00
|
|
|
ALIAS = 'endpoints_lbaas'
|
2017-02-14 03:33:02 +03:00
|
|
|
|
|
|
|
@abc.abstractmethod
|
2018-05-04 00:55:34 +03:00
|
|
|
def get_service_loadbalancer_name(self, namespace, svc_name):
|
|
|
|
"""Generate name of a load balancer that represents K8S service.
|
|
|
|
|
|
|
|
In case a load balancer represents K8S service/ep, the handler
|
|
|
|
should call first this API to get the load balancer name and use the
|
|
|
|
return value of this function as 'name' parameter for the
|
|
|
|
'ensure_loadbalancer' function
|
|
|
|
|
|
|
|
:param namespace: K8S service namespace
|
|
|
|
:param svc_name: K8S service name
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def ensure_loadbalancer(self, name, project_id, subnet_id, ip,
|
2018-09-16 14:57:28 +03:00
|
|
|
security_groups_ids, service_type, provider):
|
2017-02-14 03:33:02 +03:00
|
|
|
"""Get or create load balancer.
|
|
|
|
|
2018-05-04 00:55:34 +03:00
|
|
|
:param name: LoadBlancer name
|
2017-02-14 03:33:02 +03:00
|
|
|
:param project_id: OpenStack project ID
|
|
|
|
:param subnet_id: Neutron subnet ID to host load balancer
|
|
|
|
:param ip: IP of the load balancer
|
|
|
|
:param security_groups_ids: security groups that should be allowed
|
|
|
|
access to the load balancer
|
2018-02-21 18:57:14 +01:00
|
|
|
:param service_type: K8s service type (ClusterIP or LoadBalancer)
|
2018-09-16 14:57:28 +03:00
|
|
|
:param provider: load balancer backend service
|
2017-02-14 03:33:02 +03:00
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
2018-05-04 00:55:34 +03:00
|
|
|
def release_loadbalancer(self, loadbalancer):
|
2017-02-14 03:33:02 +03:00
|
|
|
"""Release load balancer.
|
|
|
|
|
|
|
|
Should return without errors if load balancer does not exist (e.g.
|
|
|
|
already deleted).
|
|
|
|
|
|
|
|
:param loadbalancer: `LBaaSLoadBalancer` object
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
2018-05-04 00:55:34 +03:00
|
|
|
def ensure_listener(self, loadbalancer, protocol, port):
|
2017-02-14 03:33:02 +03:00
|
|
|
"""Get or create listener.
|
|
|
|
|
|
|
|
:param loadbalancer: `LBaaSLoadBalancer` object
|
|
|
|
:param protocol: listener's protocol (only TCP is supported for now)
|
|
|
|
:param port: listener's port
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
2018-05-04 00:55:34 +03:00
|
|
|
def release_listener(self, loadbalancer, listener):
|
2017-02-14 03:33:02 +03:00
|
|
|
"""Release listener.
|
|
|
|
|
|
|
|
Should return without errors if listener or load balancer does not
|
|
|
|
exist (e.g. already deleted).
|
|
|
|
|
|
|
|
:param loadbalancer: `LBaaSLoadBalancer` object
|
|
|
|
:param listener: `LBaaSListener` object
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
2018-05-04 00:55:34 +03:00
|
|
|
def ensure_pool(self, loadbalancer, listener):
|
|
|
|
"""Get or create pool attached to Listener.
|
2017-02-14 03:33:02 +03:00
|
|
|
|
|
|
|
:param loadbalancer: `LBaaSLoadBalancer` object
|
|
|
|
:param listener: `LBaaSListener` object
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
2018-05-04 00:55:34 +03:00
|
|
|
def ensure_pool_attached_to_lb(self, loadbalancer, namespace,
|
|
|
|
svc_name, protocol):
|
|
|
|
"""Get or create pool attached to LoadBalancer.
|
|
|
|
|
|
|
|
:param loadbalancer: `LBaaSLoadBalancer` object
|
|
|
|
:param namespace: K8S service's namespace
|
|
|
|
:param svc_name: K8S service's name
|
|
|
|
:param protocol: pool's protocol
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def get_loadbalancer_pool_name(self, loadbalancer, namespace, svc_name):
|
|
|
|
"""Get name of a load balancer's pool attached to LB.
|
|
|
|
|
|
|
|
The pool's name should be unique per K8S service
|
|
|
|
|
|
|
|
:param loadbalancer: `LBaaSLoadBalancer` object
|
|
|
|
:param namespace: K8S service's namespace
|
|
|
|
:param svc_name: K8S service's name
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def release_pool(self, loadbalancer, pool):
|
2017-02-14 03:33:02 +03:00
|
|
|
"""Release pool.
|
|
|
|
|
|
|
|
Should return without errors if pool or load balancer does not exist
|
|
|
|
(e.g. already deleted).
|
|
|
|
|
|
|
|
:param loadbalancer: `LBaaSLoadBalancer` object
|
|
|
|
:param pool: `LBaaSPool` object
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
2018-05-04 00:55:34 +03:00
|
|
|
def ensure_member(self, loadbalancer, pool,
|
|
|
|
subnet_id, ip, port, target_ref_namespace,
|
|
|
|
target_ref_name):
|
2017-02-14 03:33:02 +03:00
|
|
|
"""Get or create member.
|
|
|
|
|
|
|
|
:param loadbalancer: `LBaaSLoadBalancer` object
|
|
|
|
:param pool: `LBaaSPool` object
|
|
|
|
:param subnet_id: Neutron subnet ID of the target
|
|
|
|
:param ip: target's IP (e.g. Pod's IP)
|
|
|
|
:param port: target port
|
2018-05-04 00:55:34 +03:00
|
|
|
:param target_ref_namespace: Kubernetes EP target_ref namespace
|
|
|
|
:param target_ref_name: Kubernetes EP target_ref name
|
2017-02-14 03:33:02 +03:00
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
2018-05-04 00:55:34 +03:00
|
|
|
def release_member(self, loadbalancer, member):
|
2017-02-14 03:33:02 +03:00
|
|
|
"""Release member.
|
|
|
|
|
|
|
|
Should return without errors if memberor load balancer does not exist
|
|
|
|
(e.g. already deleted).
|
|
|
|
|
|
|
|
:param loadbalancer: `LBaaSLoadBalancer` object
|
|
|
|
:param member: `LBaaSMember` object
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
2017-02-22 10:18:37 +01:00
|
|
|
|
2019-01-10 13:07:03 +00:00
|
|
|
@abc.abstractmethod
|
|
|
|
def update_lbaas_sg(self, service, sgs):
|
|
|
|
"""Update security group rules associated to the loadbalancer
|
|
|
|
|
|
|
|
:param service: k8s service object
|
|
|
|
:param sgs: list of security group ids to use for updating the rules
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2019-11-22 11:53:16 +00:00
|
|
|
@abc.abstractmethod
|
|
|
|
def add_tags(self, resource, req):
|
|
|
|
"""Add tags to a request if the resource supports it"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2017-02-22 10:18:37 +01:00
|
|
|
|
2020-02-28 12:00:19 +01:00
|
|
|
class VIFPoolDriver(PodVIFDriver, metaclass=abc.ABCMeta):
|
2017-02-22 10:18:37 +01:00
|
|
|
"""Manages Pool of Neutron ports to provide VIFs for Kubernetes Pods."""
|
|
|
|
|
|
|
|
ALIAS = 'vif_pool'
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def set_vif_driver(self, driver):
|
|
|
|
"""Sets the driver the Pool should use to manage resources
|
|
|
|
|
|
|
|
The driver will be used for acquiring, releasing and updating the
|
|
|
|
vif resources.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
2017-08-27 12:27:18 +03:00
|
|
|
|
2019-10-04 13:11:56 +02:00
|
|
|
@abc.abstractmethod
|
|
|
|
def remove_sg_from_pools(self, sg_id, net_id):
|
|
|
|
"""Remove the SG from the ports associated to the pools.
|
|
|
|
|
|
|
|
This method ensure that ports on net_id that belongs to pools and have
|
|
|
|
the referenced SG are updated to clean up their SGs and put back on
|
|
|
|
the default pool for that network.
|
|
|
|
|
|
|
|
:param sg_id: Security Group ID that needs to be removed from pool
|
|
|
|
ports
|
|
|
|
:param net_id: Network ID associated to the pools to clean up, and
|
|
|
|
where the ports must belong to.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2017-08-27 12:27:18 +03:00
|
|
|
|
2020-02-28 12:00:19 +01:00
|
|
|
class ServicePubIpDriver(DriverBase, metaclass=abc.ABCMeta):
|
2017-08-27 12:27:18 +03:00
|
|
|
"""Manages loadbalancerIP/public ip for neutron lbaas."""
|
|
|
|
|
|
|
|
ALIAS = 'service_public_ip'
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
2018-12-04 13:47:37 +02:00
|
|
|
def acquire_service_pub_ip_info(self, spec_type, spec_lb_ip, project_id,
|
|
|
|
port_id_to_be_associated=None):
|
2017-08-27 12:27:18 +03:00
|
|
|
"""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
|
2018-12-04 13:47:37 +02:00
|
|
|
:param port_id_to_be_associated: port id to associate
|
2017-08-27 12:27:18 +03:00
|
|
|
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def release_pub_ip(self, service_pub_ip_info):
|
|
|
|
"""Release (if needed) based on service_pub_ip_info content
|
|
|
|
|
|
|
|
:param service_pub_ip_info: service loadbalancer IP info
|
2017-10-17 18:16:21 +03:00
|
|
|
:returns True/False
|
2017-08-27 12:27:18 +03:00
|
|
|
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def associate_pub_ip(self, service_pub_ip_info, vip_port_id):
|
|
|
|
"""Associate loadbalancer IP to lbaas VIP port ID
|
|
|
|
|
|
|
|
:param service_pub_ip_info: service loadbalancer IP info
|
|
|
|
:param vip_port_id: Lbaas VIP port id
|
|
|
|
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def disassociate_pub_ip(self, service_pub_ip_info):
|
|
|
|
"""Disassociate loadbalancer IP and lbaas VIP port ID
|
|
|
|
|
|
|
|
:param service_pub_ip_info: service loadbalancer IP info
|
|
|
|
|
|
|
|
"""
|
2018-06-08 08:28:34 +00:00
|
|
|
|
|
|
|
|
2020-02-28 12:00:19 +01:00
|
|
|
class NetworkPolicyDriver(DriverBase, metaclass=abc.ABCMeta):
|
2018-06-08 08:28:34 +00:00
|
|
|
"""Provide network-policy for pods"""
|
|
|
|
|
|
|
|
ALIAS = 'network_policy'
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
2020-03-11 11:27:09 +01:00
|
|
|
def ensure_network_policy(self, policy):
|
2018-06-08 08:28:34 +00:00
|
|
|
"""Policy created or updated
|
|
|
|
|
|
|
|
:param policy: dict containing Kubernetes NP object
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
2018-11-07 18:46:07 +01:00
|
|
|
def release_network_policy(self, kuryrnetpolicy):
|
2018-06-08 08:28:34 +00:00
|
|
|
"""Delete a network policy
|
|
|
|
|
2020-03-11 11:27:09 +01:00
|
|
|
:param kuryrnetpolicy: dict containing NetworkPolicy object
|
2018-11-07 18:46:07 +01:00
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def affected_pods(self, policy, selector=None):
|
|
|
|
"""Return affected pods by the policy
|
|
|
|
|
|
|
|
This method returns the list of pod objects affected by the policy, or
|
|
|
|
by the selector if it is specified.
|
|
|
|
|
|
|
|
:param policy: dict containing Kubernetes NP object
|
|
|
|
:param selector: (optional) specifc pod selector
|
|
|
|
:returns: list of Pods objects affected by the policy or the selector
|
2019-01-03 07:22:04 -05:00
|
|
|
if it is passed
|
2018-11-07 18:46:07 +01:00
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def namespaced_pods(self, policy):
|
|
|
|
"""Return pods on the policy namespace
|
|
|
|
|
|
|
|
This method returns the pods on the network policy namespace
|
|
|
|
|
|
|
|
:param policy: dict containing Kubernetes NP object
|
|
|
|
:returns: list of Pods objects on the policy namespace
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
2018-06-08 08:28:34 +00:00
|
|
|
|
2020-02-28 12:00:19 +01:00
|
|
|
class NetworkPolicyProjectDriver(DriverBase, metaclass=abc.ABCMeta):
|
2018-06-08 08:28:34 +00:00
|
|
|
"""Get an OpenStack project id for K8s network policies"""
|
|
|
|
|
2018-07-09 04:39:05 -04:00
|
|
|
ALIAS = 'network_policy_project'
|
2018-06-08 08:28:34 +00:00
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def get_project(self, policy):
|
|
|
|
"""Get an OpenStack project id for K8s pod ports.
|
|
|
|
|
|
|
|
:param policy: dict containing Kubernetes NP object
|
|
|
|
:returns: OpenStack project_id
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
2020-12-23 17:39:11 +01:00
|
|
|
|
|
|
|
|
|
|
|
class NodesSubnetsDriver(DriverBase, metaclass=abc.ABCMeta):
|
|
|
|
"""Keeps list of subnet_ids of the OpenShift Nodes."""
|
|
|
|
|
|
|
|
ALIAS = 'nodes_subnets'
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def get_nodes_subnets(self, raise_on_empty=False):
|
|
|
|
"""Gets list of subnet_ids of OpenShift Nodes.
|
|
|
|
|
|
|
|
:param raise_on_empty: whether it should raise if list is empty.
|
|
|
|
:return: list of subnets
|
|
|
|
"""
|
|
|
|
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def add_node(self, node):
|
|
|
|
"""Handles node addition.
|
|
|
|
|
|
|
|
:param node: Node object
|
|
|
|
"""
|
|
|
|
pass
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def delete_node(self, node):
|
|
|
|
"""Handles node removal
|
|
|
|
|
|
|
|
:param node: Node object
|
|
|
|
"""
|
|
|
|
pass
|