Waiting for Neutron port to become ACTIVE
This patch set adds two config options similar to those used in Nova, namely vif_plugging_is_fatal and vif_plugging_timeout to make it possible to ask Kuryr to wait until the port status becomes Active during libnetwork join operations. Closes-Bug: #1578016 Change-Id: I106d2c8c289c7fca2a465c72f1dbd53acc539f39
This commit is contained in:
parent
16bfca4ce0
commit
4dc7caf89c
@ -61,6 +61,13 @@ neutron_opts = [
|
||||
cfg.StrOpt('default_subnetpool_v6',
|
||||
default='kuryr6',
|
||||
help=_('Name of default subnetpool version 6')),
|
||||
cfg.BoolOpt('vif_plugging_is_fatal',
|
||||
default=False,
|
||||
help=_("Whether a plugging operation is failed if the port "
|
||||
"to plug does not become active")),
|
||||
cfg.IntOpt('vif_plugging_timeout',
|
||||
default=0,
|
||||
help=_("Seconds to wait for port to become active")),
|
||||
]
|
||||
keystone_opts = [
|
||||
cfg.StrOpt('auth_uri',
|
||||
|
@ -25,6 +25,9 @@ ROUTE_TYPE = {
|
||||
"CONNECTED": 1
|
||||
}
|
||||
|
||||
PORT_STATUS_ACTIVE = 'ACTIVE'
|
||||
PORT_STATUS_DOWN = 'DOWN'
|
||||
|
||||
DEVICE_OWNER = 'kuryr:container'
|
||||
NIC_NAME_LEN = 14
|
||||
VETH_PREFIX = 'tap'
|
||||
|
@ -63,6 +63,15 @@ class NoResourceException(KuryrException):
|
||||
"""
|
||||
|
||||
|
||||
class InactiveResourceException(KuryrException):
|
||||
"""Exception represents the resource for the given query is not active.
|
||||
|
||||
This exception is thrown when you query the Neutron resource associated
|
||||
with the given query and you get the status of the resource as something
|
||||
other than ACTIVE.
|
||||
"""
|
||||
|
||||
|
||||
class VethCreationFailure(KuryrException):
|
||||
"""Exception represents the veth pair creation is failed.
|
||||
|
||||
|
@ -15,11 +15,13 @@ import os_client_config
|
||||
import flask
|
||||
import jsonschema
|
||||
import netaddr
|
||||
import time
|
||||
|
||||
from neutronclient.common import exceptions as n_exceptions
|
||||
from neutronclient.neutron import client
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
from oslo_utils import excutils
|
||||
|
||||
from kuryr import app
|
||||
@ -31,6 +33,8 @@ from kuryr._i18n import _LE, _LI, _LW
|
||||
from kuryr import schemata
|
||||
from kuryr import utils
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
MANDATORY_NEUTRON_EXTENSION = "subnet_allocation"
|
||||
TAG_NEUTRON_EXTENSION = "tag"
|
||||
@ -110,6 +114,8 @@ def neutron_client():
|
||||
if not hasattr(app, 'neutron'):
|
||||
app.neutron = get_neutron_client()
|
||||
app.enable_dhcp = cfg.CONF.neutron_client.enable_dhcp
|
||||
app.vif_plug_is_fatal = cfg.CONF.neutron_client.vif_plugging_is_fatal
|
||||
app.vif_plug_timeout = cfg.CONF.neutron_client.vif_plugging_timeout
|
||||
app.neutron.format = 'json'
|
||||
|
||||
|
||||
@ -367,6 +373,27 @@ def _get_networks_by_identifier(identifier):
|
||||
return _get_networks_by_attrs(name=identifier)
|
||||
|
||||
|
||||
def _port_active(neutron_port_id, vif_plug_timeout):
|
||||
port_active = False
|
||||
tries = 0
|
||||
while True:
|
||||
try:
|
||||
port = app.neutron.show_port(neutron_port_id)
|
||||
except n_exceptions.NeutronClientException as ex:
|
||||
app.logger.error(_LE('Could not get the port %s to check '
|
||||
'its status'), ex)
|
||||
else:
|
||||
if port['port']['status'] == const.PORT_STATUS_ACTIVE:
|
||||
port_active = True
|
||||
if port_active or (tries >= vif_plug_timeout):
|
||||
break
|
||||
LOG.debug('Waiting for port %s to become ACTIVE', neutron_port_id)
|
||||
tries += 1
|
||||
time.sleep(1)
|
||||
|
||||
return port_active
|
||||
|
||||
|
||||
@app.route('/Plugin.Activate', methods=['POST'])
|
||||
def plugin_activate():
|
||||
"""Returns the list of the implemented drivers.
|
||||
@ -825,6 +852,14 @@ def network_driver_join():
|
||||
app.logger.error(_LE(
|
||||
'Could not bind the Neutron port to the veth endpoint.'))
|
||||
|
||||
if app.vif_plug_is_fatal:
|
||||
port_active = _port_active(neutron_port['id'],
|
||||
app.vif_plug_timeout)
|
||||
if not port_active:
|
||||
raise exceptions.InactiveResourceException(
|
||||
"Neutron port {0} did not become active on time."
|
||||
.format(neutron_port_name))
|
||||
|
||||
join_response = {
|
||||
"InterfaceName": {
|
||||
"SrcName": peer_name,
|
||||
|
@ -169,6 +169,7 @@ class TestKuryrBase(TestCase):
|
||||
@staticmethod
|
||||
def _get_fake_port(docker_endpoint_id, neutron_network_id,
|
||||
neutron_port_id,
|
||||
neutron_port_status=const.PORT_STATUS_DOWN,
|
||||
neutron_subnet_v4_id=None,
|
||||
neutron_subnet_v6_id=None,
|
||||
neutron_subnet_v4_address="192.168.1.2",
|
||||
@ -177,7 +178,7 @@ class TestKuryrBase(TestCase):
|
||||
# http://developer.openstack.org/api-ref-networking-v2.html#createPort # noqa
|
||||
fake_port = {
|
||||
'port': {
|
||||
"status": "DOWN",
|
||||
"status": neutron_port_status,
|
||||
"name": utils.get_neutron_port_name(docker_endpoint_id),
|
||||
"allowed_address_pairs": [],
|
||||
"admin_state_up": True,
|
||||
@ -206,11 +207,11 @@ class TestKuryrBase(TestCase):
|
||||
|
||||
@classmethod
|
||||
def _get_fake_ports(cls, docker_endpoint_id, neutron_network_id,
|
||||
fake_neutron_port_id,
|
||||
fake_neutron_port_id, neutron_port_status,
|
||||
fake_neutron_subnet_v4_id, fake_neutron_subnet_v6_id):
|
||||
fake_port = cls._get_fake_port(
|
||||
docker_endpoint_id, neutron_network_id,
|
||||
fake_neutron_port_id,
|
||||
fake_neutron_port_id, neutron_port_status,
|
||||
fake_neutron_subnet_v4_id, fake_neutron_subnet_v6_id)
|
||||
fake_port = fake_port['port']
|
||||
fake_ports = {
|
||||
|
@ -79,7 +79,7 @@ class TestKuryrJoinFailures(base.TestKuryrFailures):
|
||||
fake_neutron_v6_subnet_id = str(uuid.uuid4())
|
||||
fake_neutron_ports_response = self._get_fake_ports(
|
||||
fake_docker_endpoint_id, fake_neutron_network_id,
|
||||
fake_neutron_port_id,
|
||||
fake_neutron_port_id, const.PORT_STATUS_ACTIVE,
|
||||
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id)
|
||||
app.neutron.list_ports(name=neutron_port_name).AndReturn(
|
||||
fake_neutron_ports_response)
|
||||
|
@ -420,7 +420,7 @@ class TestKuryr(base.TestKuryrBase):
|
||||
fake_port_id = str(uuid.uuid4())
|
||||
fake_port = self._get_fake_port(
|
||||
docker_endpoint_id, fake_neutron_net_id,
|
||||
fake_port_id,
|
||||
fake_port_id, constants.PORT_STATUS_ACTIVE,
|
||||
subnet_v4_id, subnet_v6_id)
|
||||
fake_fixed_ips = ['subnet_id=%s' % subnet_v4_id,
|
||||
'ip_address=192.168.1.2',
|
||||
@ -477,7 +477,13 @@ class TestKuryr(base.TestKuryrBase):
|
||||
decoded_json = jsonutils.loads(response.data)
|
||||
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
|
||||
|
||||
def test_network_driver_join(self):
|
||||
@ddt.data(
|
||||
(False), (True))
|
||||
def test_network_driver_join(self, vif_plug_is_fatal):
|
||||
if vif_plug_is_fatal:
|
||||
self.mox.StubOutWithMock(app, "vif_plug_is_fatal")
|
||||
app.vif_plug_is_fatal = True
|
||||
|
||||
fake_docker_net_id = utils.get_hash()
|
||||
fake_docker_endpoint_id = utils.get_hash()
|
||||
fake_container_id = utils.get_hash()
|
||||
@ -492,7 +498,7 @@ class TestKuryr(base.TestKuryrBase):
|
||||
fake_neutron_v6_subnet_id = str(uuid.uuid4())
|
||||
fake_neutron_ports_response = self._get_fake_ports(
|
||||
fake_docker_endpoint_id, fake_neutron_net_id,
|
||||
fake_neutron_port_id,
|
||||
fake_neutron_port_id, constants.PORT_STATUS_DOWN,
|
||||
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id)
|
||||
app.neutron.list_ports(name=neutron_port_name).AndReturn(
|
||||
fake_neutron_ports_response)
|
||||
@ -507,6 +513,16 @@ class TestKuryr(base.TestKuryrBase):
|
||||
fake_neutron_subnets = fake_neutron_subnets_response['subnets']
|
||||
_, fake_peer_name, _ = self._mock_out_binding(
|
||||
fake_docker_endpoint_id, fake_neutron_port, fake_neutron_subnets)
|
||||
|
||||
if vif_plug_is_fatal:
|
||||
self.mox.StubOutWithMock(app.neutron, 'show_port')
|
||||
fake_neutron_ports_response_2 = self._get_fake_port(
|
||||
fake_docker_endpoint_id, fake_neutron_net_id,
|
||||
fake_neutron_port_id, constants.PORT_STATUS_ACTIVE,
|
||||
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id)
|
||||
app.neutron.show_port(fake_neutron_port_id).AndReturn(
|
||||
fake_neutron_ports_response_2)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
fake_subnets_dict_by_id = {subnet['id']: subnet
|
||||
@ -554,7 +570,7 @@ class TestKuryr(base.TestKuryrBase):
|
||||
fake_neutron_v6_subnet_id = str(uuid.uuid4())
|
||||
fake_neutron_ports_response = self._get_fake_ports(
|
||||
fake_docker_endpoint_id, fake_neutron_net_id,
|
||||
fake_neutron_port_id,
|
||||
fake_neutron_port_id, constants.PORT_STATUS_ACTIVE,
|
||||
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id)
|
||||
app.neutron.list_ports(name=neutron_port_name).AndReturn(
|
||||
fake_neutron_ports_response)
|
||||
@ -570,6 +586,7 @@ class TestKuryr(base.TestKuryrBase):
|
||||
content_type='application/json',
|
||||
data=jsonutils.dumps(leave_request))
|
||||
|
||||
self.mox.ReplayAll()
|
||||
self.assertEqual(200, response.status_code)
|
||||
decoded_json = jsonutils.loads(response.data)
|
||||
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
|
||||
|
@ -196,7 +196,7 @@ class TestKuryrIpam(base.TestKuryrBase):
|
||||
fake_neutron_port_id = str(uuid.uuid4())
|
||||
fake_port = base.TestKuryrBase._get_fake_port(
|
||||
docker_endpoint_id, neutron_network_id,
|
||||
fake_neutron_port_id,
|
||||
fake_neutron_port_id, const.PORT_STATUS_ACTIVE,
|
||||
subnet_v4_id,
|
||||
neutron_subnet_v4_address="10.0.0.5")
|
||||
port_request = {
|
||||
@ -361,7 +361,7 @@ class TestKuryrIpam(base.TestKuryrBase):
|
||||
fake_neutron_port_id = str(uuid.uuid4())
|
||||
fake_port = base.TestKuryrBase._get_fake_port(
|
||||
docker_endpoint_id, neutron_network_id,
|
||||
fake_neutron_port_id,
|
||||
fake_neutron_port_id, const.PORT_STATUS_ACTIVE,
|
||||
subnet_v4_id,
|
||||
neutron_subnet_v4_address=fake_ip4)
|
||||
port_request = {
|
||||
|
@ -19,6 +19,7 @@ from werkzeug import exceptions as w_exceptions
|
||||
|
||||
from kuryr import app
|
||||
from kuryr import binding
|
||||
from kuryr.common import constants as const
|
||||
from kuryr.common import exceptions
|
||||
from kuryr.tests.unit import base
|
||||
from kuryr import utils
|
||||
@ -68,7 +69,7 @@ class TestKuryrLeaveFailures(base.TestKuryrFailures):
|
||||
fake_neutron_v6_subnet_id = str(uuid.uuid4())
|
||||
fake_neutron_ports_response = self._get_fake_ports(
|
||||
fake_docker_endpoint_id, fake_neutron_network_id,
|
||||
fake_neutron_port_id,
|
||||
fake_neutron_port_id, const.PORT_STATUS_ACTIVE,
|
||||
fake_neutron_v4_subnet_id, fake_neutron_v6_subnet_id)
|
||||
app.neutron.list_ports(name=neutron_port_name).AndReturn(
|
||||
fake_neutron_ports_response)
|
||||
|
Loading…
x
Reference in New Issue
Block a user