Skip to content

Commit 8354a75

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Use neutronclient's port binding APIs"
2 parents 9e7cd66 + 982e2ee commit 8354a75

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)