2b3e2f5aac
In our client, for OpenStack client, we created a workaround for missing bulk port create (at that time). Turns out, that running out of the OpenStack resources, there could be SDKException thrown, which is fine, although due to the mistake, message wasn't informative at all. This patch is fixing this. Closes-Bug: 1901666 Change-Id: Iba0744840231088018ec37cb6e3d98e1df6916fa
181 lines
6.4 KiB
Python
181 lines
6.4 KiB
Python
# 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.
|
|
|
|
from functools import partial
|
|
import ipaddress
|
|
import os
|
|
|
|
from kuryr.lib import utils
|
|
from openstack import connection
|
|
from openstack import exceptions as os_exc
|
|
from openstack.load_balancer.v2 import listener as os_listener
|
|
from openstack.network.v2 import port as os_port
|
|
from openstack.network.v2 import trunk as os_trunk
|
|
from openstack import resource as os_resource
|
|
from openstack import utils as os_utils
|
|
|
|
from kuryr_kubernetes import config
|
|
from kuryr_kubernetes import k8s_client
|
|
from kuryr_kubernetes.pod_resources import client as pr_client
|
|
|
|
_clients = {}
|
|
_NEUTRON_CLIENT = 'neutron-client'
|
|
_KUBERNETES_CLIENT = 'kubernetes-client'
|
|
_OPENSTACKSDK = 'openstacksdk'
|
|
_POD_RESOURCES_CLIENT = 'pod-resources-client'
|
|
|
|
|
|
def get_network_client():
|
|
return _clients[_OPENSTACKSDK].network
|
|
|
|
|
|
def get_openstacksdk():
|
|
return _clients[_OPENSTACKSDK]
|
|
|
|
|
|
def get_loadbalancer_client():
|
|
return get_openstacksdk().load_balancer
|
|
|
|
|
|
def get_kubernetes_client():
|
|
return _clients[_KUBERNETES_CLIENT]
|
|
|
|
|
|
def get_pod_resources_client():
|
|
return _clients[_POD_RESOURCES_CLIENT]
|
|
|
|
|
|
def get_compute_client():
|
|
return _clients[_OPENSTACKSDK].compute
|
|
|
|
|
|
def setup_clients():
|
|
setup_kubernetes_client()
|
|
setup_openstacksdk()
|
|
|
|
|
|
def setup_kubernetes_client():
|
|
if config.CONF.kubernetes.api_root:
|
|
api_root = config.CONF.kubernetes.api_root
|
|
else:
|
|
# NOTE(dulek): This is for containerized deployments, i.e. running in
|
|
# K8s Pods.
|
|
host = os.environ['KUBERNETES_SERVICE_HOST']
|
|
port = os.environ['KUBERNETES_SERVICE_PORT_HTTPS']
|
|
try:
|
|
addr = ipaddress.ip_address(host)
|
|
if addr.version == 6:
|
|
host = '[%s]' % host
|
|
except ValueError:
|
|
# It's not an IP addres but a hostname, it's fine, move along.
|
|
pass
|
|
api_root = "https://%s:%s" % (host, port)
|
|
_clients[_KUBERNETES_CLIENT] = k8s_client.K8sClient(api_root)
|
|
|
|
|
|
def _create_ports(self, payload):
|
|
"""bulk create ports using openstacksdk module"""
|
|
# TODO(gryf): this function should be removed while we update openstacksdk
|
|
# version to 0.42.
|
|
key_map = {'binding_host_id': 'binding:host_id',
|
|
'binding_profile': 'binding:profile',
|
|
'binding_vif_details': 'binding:vif_details',
|
|
'binding_vif_type': 'binding:vif_type',
|
|
'binding_vnic_type': 'binding:vnic_type'}
|
|
|
|
for port in payload['ports']:
|
|
for key, mapping in key_map.items():
|
|
if key in port:
|
|
port[mapping] = port.pop(key)
|
|
|
|
response = self.post(os_port.Port.base_path, json=payload)
|
|
|
|
if not response.ok:
|
|
raise os_exc.SDKException('Error when bulk creating ports: %s' %
|
|
response.text)
|
|
return (os_port.Port(**item) for item in response.json()['ports'])
|
|
|
|
|
|
def _add_trunk_subports(self, trunk, subports):
|
|
"""Set sub_ports on trunk
|
|
|
|
The original method on openstacksdk doesn't care about any errors. This is
|
|
a replacement that does.
|
|
"""
|
|
trunk = self._get_resource(os_trunk.Trunk, trunk)
|
|
url = os_utils.urljoin('/trunks', trunk.id, 'add_subports')
|
|
response = self.put(url, json={'sub_ports': subports})
|
|
os_exc.raise_from_response(response)
|
|
trunk._body.attributes.update({'sub_ports': subports})
|
|
return trunk
|
|
|
|
|
|
def _delete_trunk_subports(self, trunk, subports):
|
|
"""Remove sub_ports from trunk
|
|
|
|
The original method on openstacksdk doesn't care about any errors. This is
|
|
a replacement that does.
|
|
"""
|
|
trunk = self._get_resource(os_trunk.Trunk, trunk)
|
|
url = os_utils.urljoin('/trunks', trunk.id, 'remove_subports')
|
|
response = self.put(url, json={'sub_ports': subports})
|
|
os_exc.raise_from_response(response)
|
|
trunk._body.attributes.update({'sub_ports': subports})
|
|
return trunk
|
|
|
|
|
|
def handle_neutron_errors(method, *args, **kwargs):
|
|
"""Handle errors on openstacksdk router methods"""
|
|
result = method(*args, **kwargs)
|
|
if 'NeutronError' in result:
|
|
error = result['NeutronError']
|
|
if error['type'] in ('RouterNotFound',
|
|
'RouterInterfaceNotFoundForSubnet',
|
|
'SubnetNotFound'):
|
|
raise os_exc.NotFoundException(message=error['message'])
|
|
else:
|
|
raise os_exc.SDKException(error['type'] + ": " + error['message'])
|
|
|
|
return result
|
|
|
|
|
|
def setup_openstacksdk():
|
|
auth_plugin = utils.get_auth_plugin('neutron')
|
|
session = utils.get_keystone_session('neutron', auth_plugin)
|
|
# TODO(mdulko): To use Neutron's ability to do compare-and-swap updates we
|
|
# need to manually add support for inserting If-Match header
|
|
# into requests. At the moment we only need it for ports.
|
|
# Remove when lower-constraints openstacksdk supports this.
|
|
os_port.Port.if_match = os_resource.Header('If-Match')
|
|
# TODO(maysams): We need to manually insert allowed_cidrs option
|
|
# as it's only supported from 0.41.0 version. Remove it once
|
|
# lower-constraints supports it.
|
|
os_listener.Listener.allowed_cidrs = os_resource.Body('allowed_cidrs',
|
|
type=list)
|
|
conn = connection.Connection(
|
|
session=session,
|
|
region_name=getattr(config.CONF.neutron, 'region_name', None))
|
|
conn.network.create_ports = partial(_create_ports, conn.network)
|
|
conn.network.add_trunk_subports = partial(_add_trunk_subports,
|
|
conn.network)
|
|
conn.network.delete_trunk_subports = partial(_delete_trunk_subports,
|
|
conn.network)
|
|
_clients[_OPENSTACKSDK] = conn
|
|
|
|
|
|
def setup_pod_resources_client():
|
|
root_dir = config.CONF.sriov.kubelet_root_dir
|
|
_clients[_POD_RESOURCES_CLIENT] = pr_client.PodResourcesClient(root_dir)
|