137 lines
5.3 KiB
Python
137 lines
5.3 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 kuryr.lib import constants as kl_const
|
|
from openstack import exceptions as os_exc
|
|
from oslo_log import log as logging
|
|
|
|
from kuryr_kubernetes import clients
|
|
from kuryr_kubernetes import config
|
|
from kuryr_kubernetes import constants
|
|
from kuryr_kubernetes.controller.drivers import base
|
|
from kuryr_kubernetes.controller.drivers import utils
|
|
from kuryr_kubernetes import exceptions as k_exc
|
|
from kuryr_kubernetes import os_vif_util as ovu
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class NeutronPodVIFDriver(base.PodVIFDriver):
|
|
"""Manages normal Neutron ports to provide VIFs for Kubernetes Pods."""
|
|
|
|
def request_vif(self, pod, project_id, subnets, security_groups):
|
|
os_net = clients.get_network_client()
|
|
|
|
rq = self._get_port_request(pod, project_id, subnets, security_groups)
|
|
port = os_net.create_port(**rq)
|
|
|
|
self._check_port_binding([port])
|
|
utils.tag_neutron_resources([port])
|
|
return ovu.neutron_to_osvif_vif(port.binding_vif_type, port, subnets)
|
|
|
|
def request_vifs(self, pod, project_id, subnets, security_groups,
|
|
num_ports):
|
|
os_net = clients.get_network_client()
|
|
|
|
rq = self._get_port_request(pod, project_id, subnets, security_groups,
|
|
unbound=True)
|
|
|
|
bulk_port_rq = {'ports': [rq] * num_ports}
|
|
try:
|
|
ports = list(os_net.create_ports(bulk_port_rq))
|
|
except os_exc.SDKException:
|
|
LOG.exception("Error creating bulk ports: %s", bulk_port_rq)
|
|
raise
|
|
|
|
vif_plugin = ports[0].binding_vif_type
|
|
|
|
# NOTE(ltomasbo): Due to the bug (1696051) on neutron bulk port
|
|
# creation request returning the port objects without binding
|
|
# information, an additional port show is performed to get the binding
|
|
# information
|
|
if vif_plugin == 'unbound':
|
|
port_info = os_net.get_port(ports[0].id)
|
|
vif_plugin = port_info.binding_vif_type
|
|
|
|
self._check_port_binding(ports)
|
|
utils.tag_neutron_resources(ports)
|
|
vifs = []
|
|
for port in ports:
|
|
vif = ovu.neutron_to_osvif_vif(vif_plugin, port, subnets)
|
|
vifs.append(vif)
|
|
return vifs
|
|
|
|
def release_vif(self, pod, vif, project_id=None, security_groups=None):
|
|
clients.get_network_client().delete_port(vif.id)
|
|
|
|
def activate_vif(self, vif):
|
|
if vif.active:
|
|
return
|
|
|
|
os_net = clients.get_network_client()
|
|
try:
|
|
port = os_net.get_port(vif.id)
|
|
except os_exc.SDKException:
|
|
LOG.debug("Unable to obtain port information, retrying.")
|
|
raise k_exc.ResourceNotReady(vif)
|
|
|
|
if port['status'] != kl_const.PORT_STATUS_ACTIVE:
|
|
raise k_exc.ResourceNotReady(vif)
|
|
|
|
vif.active = True
|
|
|
|
def update_vif_sgs(self, pod, security_groups):
|
|
os_net = clients.get_network_client()
|
|
vifs = utils.get_vifs(pod)
|
|
if vifs:
|
|
# NOTE(ltomasbo): It just updates the default_vif security group
|
|
port_id = vifs[constants.DEFAULT_IFNAME].id
|
|
os_net.update_port(port_id, security_groups=list(security_groups))
|
|
|
|
def _get_port_request(self, pod, project_id, subnets, security_groups,
|
|
unbound=False):
|
|
port_req_body = {'project_id': project_id,
|
|
'network_id': utils.get_network_id(subnets),
|
|
'fixed_ips': ovu.osvif_to_neutron_fixed_ips(subnets),
|
|
'device_owner': kl_const.DEVICE_OWNER,
|
|
'admin_state_up': True,
|
|
'binding_host_id': utils.get_host_id(pod)}
|
|
|
|
# if unbound argument is set to true, it means the port requested
|
|
# should not be bound and not associated to the pod. Thus the port dict
|
|
# is filled with a generic name (constants.KURYR_PORT_NAME) if
|
|
# port_debug is enabled, and without device_id
|
|
if unbound and config.CONF.kubernetes.port_debug:
|
|
port_req_body['name'] = constants.KURYR_PORT_NAME
|
|
else:
|
|
# only set the name if port_debug is enabled
|
|
if config.CONF.kubernetes.port_debug:
|
|
port_req_body['name'] = utils.get_port_name(pod)
|
|
port_req_body['device_id'] = utils.get_device_id(pod)
|
|
|
|
if security_groups:
|
|
port_req_body['security_groups'] = security_groups
|
|
|
|
return port_req_body
|
|
|
|
def _check_port_binding(self, ports):
|
|
if ports[0].binding_vif_type == "binding_failed":
|
|
for port in ports:
|
|
clients.get_network_client().delete_port(port.id)
|
|
LOG.error("Binding failed error for ports: %s."
|
|
" Please check Neutron for errors.", ports)
|
|
raise k_exc.ResourceNotReady(ports)
|