Skip to content

Commit 982e2ee

Browse files
committed
Use neutronclient's port binding APIs
Take advantage of the neutronclient bindings for the port binding APIs added in neutronclient 7.1.0 to avoid having to vendor this stuff ourselves. Change-Id: Icc284203fb53658abe304f24a62705217f90b22b Signed-off-by: Stephen Finucane <[email protected]>
1 parent 9cdecc8 commit 982e2ee

File tree

7 files changed

+282
-454
lines changed

7 files changed

+282
-454
lines changed

lower-constraints.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ python-glanceclient==2.8.0
122122
python-ironicclient==3.0.0
123123
python-keystoneclient==3.15.0
124124
python-mimeparse==1.6.0
125-
python-neutronclient==6.7.0
125+
python-neutronclient==7.1.0
126126
python-subunit==1.4.0
127127
pytz==2018.3
128128
PyYAML==5.1

nova/exception.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -816,13 +816,13 @@ class PortBindingFailed(Invalid):
816816

817817

818818
class PortBindingDeletionFailed(NovaException):
819-
msg_fmt = _("Failed to delete binding for port %(port_id)s and host "
820-
"%(host)s.")
819+
msg_fmt = _("Failed to delete binding for port(s) %(port_id)s on host "
820+
"%(host)s; please check neutron logs for more information")
821821

822822

823823
class PortBindingActivationFailed(NovaException):
824-
msg_fmt = _("Failed to activate binding for port %(port_id)s and host "
825-
"%(host)s.")
824+
msg_fmt = _("Failed to activate binding for port %(port_id)s on host "
825+
"%(host)s; please check neutron logs for more information")
826826

827827

828828
class PortUpdateFailed(Invalid):

nova/network/neutron.py

Lines changed: 99 additions & 188 deletions
Large diffs are not rendered by default.

nova/tests/fixtures/neutron.py

Lines changed: 20 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,14 @@
1515
import random
1616

1717
import fixtures
18-
from keystoneauth1 import adapter as ksa_adap
19-
import mock
2018
from neutronclient.common import exceptions as neutron_client_exc
2119
import os_resource_classes as orc
22-
from oslo_serialization import jsonutils
2320
from oslo_utils import uuidutils
2421

2522
from nova import exception
2623
from nova.network import constants as neutron_constants
2724
from nova.network import model as network_model
2825
from nova.tests.fixtures import nova as nova_fixtures
29-
from nova.tests.unit import fake_requests
3026

3127

3228
class _FakeNeutronClient:
@@ -665,25 +661,6 @@ def setUp(self):
665661
lambda *args, **kwargs: network_model.NetworkInfo.hydrate(
666662
self.nw_info))
667663

668-
# Stub out port binding APIs which go through a KSA client Adapter
669-
# rather than python-neutronclient.
670-
self.test.stub_out(
671-
'nova.network.neutron._get_ksa_client',
672-
lambda *args, **kwargs: mock.Mock(
673-
spec=ksa_adap.Adapter))
674-
self.test.stub_out(
675-
'nova.network.neutron.API._create_port_binding',
676-
self.create_port_binding)
677-
self.test.stub_out(
678-
'nova.network.neutron.API._delete_port_binding',
679-
self.delete_port_binding)
680-
self.test.stub_out(
681-
'nova.network.neutron.API._activate_port_binding',
682-
self.activate_port_binding)
683-
self.test.stub_out(
684-
'nova.network.neutron.API._get_port_binding',
685-
self.get_port_binding)
686-
687664
self.test.stub_out(
688665
'nova.network.neutron.get_client', self._get_client)
689666

@@ -692,13 +669,12 @@ def _get_client(self, context, admin=False):
692669
admin = admin or context.is_admin and not context.auth_token
693670
return _FakeNeutronClient(self, admin)
694671

695-
def create_port_binding(self, context, client, port_id, data):
672+
def create_port_binding(self, port_id, body):
696673
if port_id not in self._ports:
697-
return fake_requests.FakeResponse(
698-
404, content='Port %s not found' % port_id)
674+
raise neutron_client_exc.NeutronClientException(status_code=404)
699675

700676
port = self._ports[port_id]
701-
binding = copy.deepcopy(data['binding'])
677+
binding = copy.deepcopy(body['binding'])
702678

703679
# NOTE(stephenfin): We don't allow changing of backend
704680
binding['vif_type'] = port['binding:vif_type']
@@ -713,61 +689,36 @@ def create_port_binding(self, context, client, port_id, data):
713689

714690
self._port_bindings[port_id][binding['host']] = binding
715691

716-
return fake_requests.FakeResponse(
717-
200, content=jsonutils.dumps({'binding': binding}),
718-
)
692+
return {'binding': binding}
719693

720-
def _get_failure_response_if_port_or_binding_not_exists(
721-
self, port_id, host,
722-
):
694+
def _validate_port_binding(self, port_id, host_id):
723695
if port_id not in self._ports:
724-
return fake_requests.FakeResponse(
725-
404, content='Port %s not found' % port_id)
726-
if host not in self._port_bindings[port_id]:
727-
return fake_requests.FakeResponse(
728-
404,
729-
content='Binding for host %s for port %s not found'
730-
% (host, port_id))
731-
732-
def delete_port_binding(self, context, client, port_id, host):
733-
failure = self._get_failure_response_if_port_or_binding_not_exists(
734-
port_id, host)
735-
if failure is not None:
736-
return failure
696+
raise neutron_client_exc.NeutronClientException(status_code=404)
737697

738-
del self._port_bindings[port_id][host]
698+
if host_id not in self._port_bindings[port_id]:
699+
raise neutron_client_exc.NeutronClientException(status_code=404)
739700

740-
return fake_requests.FakeResponse(204)
701+
def delete_port_binding(self, port_id, host_id):
702+
self._validate_port_binding(port_id, host_id)
703+
del self._port_bindings[port_id][host_id]
741704

742-
def _activate_port_binding(self, port_id, host):
705+
def _activate_port_binding(self, port_id, host_id):
743706
# It makes sure that only one binding is active for a port
744-
for h, binding in self._port_bindings[port_id].items():
745-
if h == host:
707+
for host, binding in self._port_bindings[port_id].items():
708+
if host == host_id:
746709
# NOTE(gibi): neutron returns 409 if this binding is already
747710
# active but nova does not depend on this behaviour yet.
748711
binding['status'] = 'ACTIVE'
749712
else:
750713
binding['status'] = 'INACTIVE'
751714

752-
def activate_port_binding(self, context, client, port_id, host):
753-
failure = self._get_failure_response_if_port_or_binding_not_exists(
754-
port_id, host)
755-
if failure is not None:
756-
return failure
757-
758-
self._activate_port_binding(port_id, host)
759-
760-
return fake_requests.FakeResponse(200)
761-
762-
def get_port_binding(self, context, client, port_id, host):
763-
failure = self._get_failure_response_if_port_or_binding_not_exists(
764-
port_id, host)
765-
if failure is not None:
766-
return failure
715+
def activate_port_binding(self, port_id, host_id):
716+
self._validate_port_binding(port_id, host_id)
717+
self._activate_port_binding(port_id, host_id)
767718

768-
binding = {"binding": self._port_bindings[port_id][host]}
769-
return fake_requests.FakeResponse(
770-
200, content=jsonutils.dumps(binding))
719+
def show_port_binding(self, port_id, host_id):
720+
self._validate_port_binding(port_id, host_id)
721+
return {'binding': self._port_bindings[port_id][host_id]}
771722

772723
def _list_resource(self, resources, retrieve_all, **_params):
773724
# If 'fields' is passed we need to strip that out since it will mess

nova/tests/functional/test_servers.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1313
# License for the specific language governing permissions and limitations
1414
# under the License.
15+
1516
import collections
1617
import copy
1718
import datetime
@@ -8383,32 +8384,35 @@ def test_cross_cell_migrate_server_with_qos_ports(self):
83838384
server = self._create_server_with_ports_and_check_allocation(
83848385
non_qos_normal_port, qos_normal_port, qos_sriov_port)
83858386

8386-
orig_create_binding = neutronapi.API._create_port_binding
8387+
orig_create_binding = self.neutron.create_port_binding
83878388

83888389
hosts = {
8389-
'host1': self.compute1_rp_uuid, 'host2': self.compute2_rp_uuid}
8390+
'host1': self.compute1_rp_uuid, 'host2': self.compute2_rp_uuid,
8391+
}
83908392

83918393
# Add an extra check to our neutron fixture. This check makes sure that
83928394
# the RP sent in the binding corresponds to host of the binding. In a
83938395
# real deployment this is checked by the Neutron server. As bug
83948396
# 1907522 showed we fail this check for cross cell migration with qos
83958397
# ports in a real deployment. So to reproduce that bug we need to have
83968398
# the same check in our test env too.
8397-
def spy_on_create_binding(context, client, port_id, data):
8399+
def spy_on_create_binding(port_id, data):
83988400
host_rp_uuid = hosts[data['binding']['host']]
83998401
device_rp_uuid = data['binding']['profile'].get('allocation')
84008402
if port_id == qos_normal_port['id']:
84018403
if device_rp_uuid != self.ovs_bridge_rp_per_host[host_rp_uuid]:
84028404
raise exception.PortBindingFailed(port_id=port_id)
84038405
elif port_id == qos_sriov_port['id']:
8404-
if (device_rp_uuid not in
8405-
self.sriov_dev_rp_per_host[host_rp_uuid].values()):
8406+
if (
8407+
device_rp_uuid not in
8408+
self.sriov_dev_rp_per_host[host_rp_uuid].values()
8409+
):
84068410
raise exception.PortBindingFailed(port_id=port_id)
84078411

8408-
return orig_create_binding(context, client, port_id, data)
8412+
return orig_create_binding(port_id, data)
84098413

84108414
with mock.patch(
8411-
'nova.network.neutron.API._create_port_binding',
8415+
'nova.tests.fixtures.NeutronFixture.create_port_binding',
84128416
side_effect=spy_on_create_binding, autospec=True
84138417
):
84148418
# We expect the migration to fail as the only available target
@@ -8440,8 +8444,8 @@ def spy_on_create_binding(context, client, port_id, data):
84408444
self._create_networking_rp_tree('host3', self.compute3_rp_uuid)
84418445

84428446
with mock.patch(
8443-
'nova.network.neutron.API._create_port_binding',
8444-
side_effect=spy_on_create_binding, autospec=True
8447+
'nova.tests.fixtures.NeutronFixture.create_port_binding',
8448+
side_effect=spy_on_create_binding, autospec=True
84458449
):
84468450
server = self._migrate_server(server)
84478451
self.assertEqual('host3', server['OS-EXT-SRV-ATTR:host'])

0 commit comments

Comments
 (0)