summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoden R <bodenvmw@gmail.com>2018-04-30 13:25:54 -0600
committerBoden R <bodenvmw@gmail.com>2018-07-12 08:13:05 -0600
commit839e575fa69792c4e304c22c8209e73b0e7366f4 (patch)
treec14531d8548685426c675f9aa69d5e26d4e5f3ce
parentbe4a1dd6dd55c3820d0339a2e0ede8031e13ea5c (diff)
use plugin utils from neutron-lib
The remainder of the neutron.plugins.common.utils were rehomed into neutron-lib with [1][2]. This patch consumes them by using the functions from neutron-lib, and removing the neutron.plugins.common.utils module all together as it's fully rehomed now. NeutronLibImpact [1] https://review.openstack.org/#/c/560950/ [2] https://review.openstack.org/#/c/554546/ Change-Id: Ic0f7b37861f078ce8c5ee92d97e977b8d2b468ad
Notes
Notes (review): Code-Review+1: PaweĊ‚ Suder <pawel@suder.info> Code-Review+2: Slawek Kaplonski <skaplons@redhat.com> Code-Review+1: Nate Johnston <nate.johnston@redhat.com> Code-Review+2: Miguel Lavalle <miguel.lavalle@huawei.com> Workflow+1: Miguel Lavalle <miguel.lavalle@huawei.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Thu, 12 Jul 2018 22:23:09 +0000 Reviewed-on: https://review.openstack.org/565284 Project: openstack/neutron Branch: refs/heads/master
-rw-r--r--neutron/api/rpc/handlers/dhcp_rpc.py2
-rw-r--r--neutron/db/l3_db.py16
-rw-r--r--neutron/db/l3_dvr_db.py9
-rw-r--r--neutron/db/l3_hamode_db.py2
-rw-r--r--neutron/plugins/common/utils.py76
-rw-r--r--neutron/plugins/ml2/drivers/helpers.py2
-rw-r--r--neutron/plugins/ml2/plugin.py2
-rw-r--r--neutron/services/auto_allocate/db.py2
-rw-r--r--neutron/tests/unit/api/rpc/handlers/test_dhcp_rpc.py2
-rw-r--r--neutron/tests/unit/plugins/common/__init__.py0
-rw-r--r--neutron/tests/unit/plugins/common/test_utils.py117
11 files changed, 17 insertions, 213 deletions
diff --git a/neutron/api/rpc/handlers/dhcp_rpc.py b/neutron/api/rpc/handlers/dhcp_rpc.py
index acffd21..88b30ad 100644
--- a/neutron/api/rpc/handlers/dhcp_rpc.py
+++ b/neutron/api/rpc/handlers/dhcp_rpc.py
@@ -23,6 +23,7 @@ from neutron_lib.callbacks import resources
23from neutron_lib import constants 23from neutron_lib import constants
24from neutron_lib import exceptions 24from neutron_lib import exceptions
25from neutron_lib.plugins import directory 25from neutron_lib.plugins import directory
26from neutron_lib.plugins import utils as p_utils
26from oslo_config import cfg 27from oslo_config import cfg
27from oslo_db import exception as db_exc 28from oslo_db import exception as db_exc
28from oslo_log import log as logging 29from oslo_log import log as logging
@@ -36,7 +37,6 @@ from neutron.common import utils
36from neutron.db import api as db_api 37from neutron.db import api as db_api
37from neutron.db import provisioning_blocks 38from neutron.db import provisioning_blocks
38from neutron.extensions import segment as segment_ext 39from neutron.extensions import segment as segment_ext
39from neutron.plugins.common import utils as p_utils
40from neutron.quota import resource_registry 40from neutron.quota import resource_registry
41 41
42 42
diff --git a/neutron/db/l3_db.py b/neutron/db/l3_db.py
index 6622746..3fe4c95 100644
--- a/neutron/db/l3_db.py
+++ b/neutron/db/l3_db.py
@@ -55,7 +55,6 @@ from neutron.extensions import qos_fip
55from neutron.objects import base as base_obj 55from neutron.objects import base as base_obj
56from neutron.objects import ports as port_obj 56from neutron.objects import ports as port_obj
57from neutron.objects import router as l3_obj 57from neutron.objects import router as l3_obj
58from neutron.plugins.common import utils as p_utils
59from neutron import worker as neutron_worker 58from neutron import worker as neutron_worker
60 59
61LOG = logging.getLogger(__name__) 60LOG = logging.getLogger(__name__)
@@ -376,8 +375,8 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
376 'device_owner': DEVICE_OWNER_ROUTER_GW, 375 'device_owner': DEVICE_OWNER_ROUTER_GW,
377 'admin_state_up': True, 376 'admin_state_up': True,
378 'name': ''} 377 'name': ''}
379 gw_port = p_utils.create_port(self._core_plugin, 378 gw_port = plugin_utils.create_port(
380 context.elevated(), {'port': port_data}) 379 self._core_plugin, context.elevated(), {'port': port_data})
381 380
382 if not gw_port['fixed_ips']: 381 if not gw_port['fixed_ips']:
383 LOG.debug('No IPs available for external network %s', 382 LOG.debug('No IPs available for external network %s',
@@ -820,8 +819,8 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
820 'device_id': router.id, 819 'device_id': router.id,
821 'device_owner': owner, 820 'device_owner': owner,
822 'name': ''} 821 'name': ''}
823 return p_utils.create_port(self._core_plugin, context, 822 return plugin_utils.create_port(
824 {'port': port_data}), [subnet], True 823 self._core_plugin, context, {'port': port_data}), [subnet], True
825 824
826 @staticmethod 825 @staticmethod
827 def _make_router_interface_info( 826 def _make_router_interface_info(
@@ -1307,10 +1306,9 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
1307 1306
1308 # 'status' in port dict could not be updated by default, use 1307 # 'status' in port dict could not be updated by default, use
1309 # check_allow_post to stop the verification of system 1308 # check_allow_post to stop the verification of system
1310 external_port = p_utils.create_port(self._core_plugin, 1309 external_port = plugin_utils.create_port(
1311 context.elevated(), 1310 self._core_plugin, context.elevated(),
1312 {'port': port}, 1311 {'port': port}, check_allow_post=False)
1313 check_allow_post=False)
1314 1312
1315 with plugin_utils.delete_port_on_error( 1313 with plugin_utils.delete_port_on_error(
1316 self._core_plugin, context.elevated(), 1314 self._core_plugin, context.elevated(),
diff --git a/neutron/db/l3_dvr_db.py b/neutron/db/l3_dvr_db.py
index 902d8d7..be46f26 100644
--- a/neutron/db/l3_dvr_db.py
+++ b/neutron/db/l3_dvr_db.py
@@ -49,7 +49,6 @@ from neutron.objects import agent as ag_obj
49from neutron.objects import base as base_obj 49from neutron.objects import base as base_obj
50from neutron.objects import l3agent as rb_obj 50from neutron.objects import l3agent as rb_obj
51from neutron.objects import router as l3_obj 51from neutron.objects import router as l3_obj
52from neutron.plugins.common import utils as p_utils
53 52
54 53
55LOG = logging.getLogger(__name__) 54LOG = logging.getLogger(__name__)
@@ -213,8 +212,8 @@ class DVRResourceOperationHandler(object):
213 'device_owner': const.DEVICE_OWNER_ROUTER_SNAT, 212 'device_owner': const.DEVICE_OWNER_ROUTER_SNAT,
214 'admin_state_up': True, 213 'admin_state_up': True,
215 'name': ''} 214 'name': ''}
216 snat_port = p_utils.create_port(self._core_plugin, context, 215 snat_port = plugin_utils.create_port(
217 {'port': port_data}) 216 self._core_plugin, context, {'port': port_data})
218 if not snat_port: 217 if not snat_port:
219 msg = _("Unable to create the SNAT Interface Port") 218 msg = _("Unable to create the SNAT Interface Port")
220 raise n_exc.BadRequest(resource='router', msg=msg) 219 raise n_exc.BadRequest(resource='router', msg=msg)
@@ -896,8 +895,8 @@ class _DVRAgentInterfaceMixin(object):
896 portbindings.HOST_ID: host, 895 portbindings.HOST_ID: host,
897 'admin_state_up': True, 896 'admin_state_up': True,
898 'name': ''} 897 'name': ''}
899 agent_port = p_utils.create_port(self._core_plugin, context, 898 agent_port = plugin_utils.create_port(
900 {'port': port_data}) 899 self._core_plugin, context, {'port': port_data})
901 if agent_port: 900 if agent_port:
902 self._populate_mtu_and_subnets_for_ports(context, 901 self._populate_mtu_and_subnets_for_ports(context,
903 [agent_port]) 902 [agent_port])
diff --git a/neutron/db/l3_hamode_db.py b/neutron/db/l3_hamode_db.py
index 7e21793..2bec742 100644
--- a/neutron/db/l3_hamode_db.py
+++ b/neutron/db/l3_hamode_db.py
@@ -32,6 +32,7 @@ from neutron_lib import exceptions as n_exc
32from neutron_lib.exceptions import l3 as l3_exc 32from neutron_lib.exceptions import l3 as l3_exc
33from neutron_lib.exceptions import l3_ext_ha_mode as l3ha_exc 33from neutron_lib.exceptions import l3_ext_ha_mode as l3ha_exc
34from neutron_lib.objects import exceptions as obj_base 34from neutron_lib.objects import exceptions as obj_base
35from neutron_lib.plugins import utils as p_utils
35from oslo_config import cfg 36from oslo_config import cfg
36from oslo_db import exception as db_exc 37from oslo_db import exception as db_exc
37from oslo_log import helpers as log_helpers 38from oslo_log import helpers as log_helpers
@@ -55,7 +56,6 @@ from neutron.db.models import l3ha as l3ha_model
55from neutron.objects import base 56from neutron.objects import base
56from neutron.objects import l3_hamode 57from neutron.objects import l3_hamode
57from neutron.objects import router as l3_obj 58from neutron.objects import router as l3_obj
58from neutron.plugins.common import utils as p_utils
59 59
60 60
61VR_ID_RANGE = set(range(1, 255)) 61VR_ID_RANGE = set(range(1, 255))
diff --git a/neutron/plugins/common/utils.py b/neutron/plugins/common/utils.py
deleted file mode 100644
index 0801492..0000000
--- a/neutron/plugins/common/utils.py
+++ /dev/null
@@ -1,76 +0,0 @@
1# Copyright 2013 Cisco Systems, Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15"""
16Common utilities and helper functions for OpenStack Networking Plugins.
17These utils are private and for neutron internal use only.
18"""
19
20from neutron_lib.api import attributes as lib_attrs
21from neutron_lib.api.definitions import network as net_def
22from neutron_lib.api.definitions import port as port_def
23from neutron_lib.api.definitions import subnet as subnet_def
24from oslo_config import cfg
25import webob.exc
26
27
28# TODO(boden): remove when consuming I2c0e4ef03425ba0bb2651ae3e68d6c8cde7b8f90
29
30def _fixup_res_dict(context, attr_name, res_dict, check_allow_post=True):
31 attr_info = lib_attrs.RESOURCES[attr_name]
32 attr_ops = lib_attrs.AttributeInfo(attr_info)
33 try:
34 attr_ops.populate_project_id(context, res_dict, True)
35 lib_attrs.populate_project_info(attr_info)
36 attr_ops.verify_attributes(res_dict)
37 except webob.exc.HTTPBadRequest as e:
38 # convert webob exception into ValueError as these functions are
39 # for internal use. webob exception doesn't make sense.
40 raise ValueError(e.detail)
41 attr_ops.fill_post_defaults(res_dict, check_allow_post=check_allow_post)
42 attr_ops.convert_values(res_dict)
43 return res_dict
44
45
46def create_network(core_plugin, context, net, check_allow_post=True):
47 net_data = _fixup_res_dict(context, net_def.COLLECTION_NAME,
48 net.get('network', {}),
49 check_allow_post=check_allow_post)
50 return core_plugin.create_network(context, {'network': net_data})
51
52
53def create_subnet(core_plugin, context, subnet, check_allow_post=True):
54 subnet_data = _fixup_res_dict(context, subnet_def.COLLECTION_NAME,
55 subnet.get('subnet', {}),
56 check_allow_post=check_allow_post)
57 return core_plugin.create_subnet(context, {'subnet': subnet_data})
58
59
60def create_port(core_plugin, context, port, check_allow_post=True):
61 port_data = _fixup_res_dict(context, port_def.COLLECTION_NAME,
62 port.get('port', {}),
63 check_allow_post=check_allow_post)
64 return core_plugin.create_port(context, {'port': port_data})
65
66
67# TODO(boden): consume with I73f5e8ad7a1a83392094db846d18964d811b8bb2
68def get_deployment_physnet_mtu():
69 """Retrieves global physical network MTU setting.
70
71 Plugins should use this function to retrieve the MTU set by the operator
72 that is equal to or less than the MTU of their nodes' physical interfaces.
73 Note that it is the responsibility of the plugin to deduct the value of
74 any encapsulation overhead required before advertising it to VMs.
75 """
76 return cfg.CONF.global_physnet_mtu
diff --git a/neutron/plugins/ml2/drivers/helpers.py b/neutron/plugins/ml2/drivers/helpers.py
index 6561844..310523c 100644
--- a/neutron/plugins/ml2/drivers/helpers.py
+++ b/neutron/plugins/ml2/drivers/helpers.py
@@ -17,6 +17,7 @@ import random
17 17
18from neutron_lib import context as neutron_ctx 18from neutron_lib import context as neutron_ctx
19from neutron_lib.plugins.ml2 import api 19from neutron_lib.plugins.ml2 import api
20from neutron_lib.plugins import utils as p_utils
20from neutron_lib.utils import helpers 21from neutron_lib.utils import helpers
21from oslo_config import cfg 22from oslo_config import cfg
22from oslo_db import exception as db_exc 23from oslo_db import exception as db_exc
@@ -25,7 +26,6 @@ from oslo_log import log
25from neutron.common import exceptions as exc 26from neutron.common import exceptions as exc
26from neutron.db import api as db_api 27from neutron.db import api as db_api
27from neutron.objects import base as base_obj 28from neutron.objects import base as base_obj
28from neutron.plugins.common import utils as p_utils
29 29
30 30
31LOG = log.getLogger(__name__) 31LOG = log.getLogger(__name__)
diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py
index e3c5054..f1e3f6e 100644
--- a/neutron/plugins/ml2/plugin.py
+++ b/neutron/plugins/ml2/plugin.py
@@ -41,6 +41,7 @@ from neutron_lib.exceptions import port_security as psec_exc
41from neutron_lib.plugins import constants as plugin_constants 41from neutron_lib.plugins import constants as plugin_constants
42from neutron_lib.plugins import directory 42from neutron_lib.plugins import directory
43from neutron_lib.plugins.ml2 import api 43from neutron_lib.plugins.ml2 import api
44from neutron_lib.plugins import utils as p_utils
44from neutron_lib.services.qos import constants as qos_consts 45from neutron_lib.services.qos import constants as qos_consts
45from oslo_config import cfg 46from oslo_config import cfg
46from oslo_db import exception as os_db_exception 47from oslo_db import exception as os_db_exception
@@ -86,7 +87,6 @@ from neutron.db import subnet_service_type_mixin
86from neutron.db import vlantransparent_db 87from neutron.db import vlantransparent_db
87from neutron.extensions import providernet as provider 88from neutron.extensions import providernet as provider
88from neutron.extensions import vlantransparent 89from neutron.extensions import vlantransparent
89from neutron.plugins.common import utils as p_utils
90from neutron.plugins.ml2.common import exceptions as ml2_exc 90from neutron.plugins.ml2.common import exceptions as ml2_exc
91from neutron.plugins.ml2 import db 91from neutron.plugins.ml2 import db
92from neutron.plugins.ml2 import driver_context 92from neutron.plugins.ml2 import driver_context
diff --git a/neutron/services/auto_allocate/db.py b/neutron/services/auto_allocate/db.py
index c63585e..f1267cc 100644
--- a/neutron/services/auto_allocate/db.py
+++ b/neutron/services/auto_allocate/db.py
@@ -25,6 +25,7 @@ from neutron_lib import exceptions as n_exc
25from neutron_lib.objects import exceptions as obj_exc 25from neutron_lib.objects import exceptions as obj_exc
26from neutron_lib.plugins import constants 26from neutron_lib.plugins import constants
27from neutron_lib.plugins import directory 27from neutron_lib.plugins import directory
28from neutron_lib.plugins import utils as p_utils
28from oslo_log import log as logging 29from oslo_log import log as logging
29 30
30from neutron._i18n import _ 31from neutron._i18n import _
@@ -35,7 +36,6 @@ from neutron.db import common_db_mixin
35from neutron.objects import auto_allocate as auto_allocate_obj 36from neutron.objects import auto_allocate as auto_allocate_obj
36from neutron.objects import base as base_obj 37from neutron.objects import base as base_obj
37from neutron.objects import network as net_obj 38from neutron.objects import network as net_obj
38from neutron.plugins.common import utils as p_utils
39from neutron.services.auto_allocate import exceptions 39from neutron.services.auto_allocate import exceptions
40 40
41LOG = logging.getLogger(__name__) 41LOG = logging.getLogger(__name__)
diff --git a/neutron/tests/unit/api/rpc/handlers/test_dhcp_rpc.py b/neutron/tests/unit/api/rpc/handlers/test_dhcp_rpc.py
index 946cd5a..15f9e6a 100644
--- a/neutron/tests/unit/api/rpc/handlers/test_dhcp_rpc.py
+++ b/neutron/tests/unit/api/rpc/handlers/test_dhcp_rpc.py
@@ -41,7 +41,7 @@ class TestDhcpRpcCallback(base.BaseTestCase):
41 set_dirty_p = mock.patch('neutron.quota.resource_registry.' 41 set_dirty_p = mock.patch('neutron.quota.resource_registry.'
42 'set_resources_dirty') 42 'set_resources_dirty')
43 self.mock_set_dirty = set_dirty_p.start() 43 self.mock_set_dirty = set_dirty_p.start()
44 self.utils_p = mock.patch('neutron.plugins.common.utils.create_port') 44 self.utils_p = mock.patch('neutron_lib.plugins.utils.create_port')
45 self.utils = self.utils_p.start() 45 self.utils = self.utils_p.start()
46 self.segment_plugin = mock.MagicMock() 46 self.segment_plugin = mock.MagicMock()
47 directory.add_plugin('segments', self.segment_plugin) 47 directory.add_plugin('segments', self.segment_plugin)
diff --git a/neutron/tests/unit/plugins/common/__init__.py b/neutron/tests/unit/plugins/common/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/neutron/tests/unit/plugins/common/__init__.py
+++ /dev/null
diff --git a/neutron/tests/unit/plugins/common/test_utils.py b/neutron/tests/unit/plugins/common/test_utils.py
deleted file mode 100644
index 5148b3e..0000000
--- a/neutron/tests/unit/plugins/common/test_utils.py
+++ /dev/null
@@ -1,117 +0,0 @@
1# Copyright (c) 2015 IBM Corp.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15import hashlib
16
17import mock
18from neutron_lib import constants
19from neutron_lib import exceptions
20from neutron_lib.plugins import utils
21import testtools
22
23from neutron.db import l3_db
24from neutron.tests import base
25
26LONG_NAME1 = "A_REALLY_LONG_INTERFACE_NAME1"
27LONG_NAME2 = "A_REALLY_LONG_INTERFACE_NAME2"
28SHORT_NAME = "SHORT"
29MOCKED_HASH = "mockedhash"
30
31
32class MockSHA(object):
33 def hexdigest(self):
34 return MOCKED_HASH
35
36
37class TestUtils(base.BaseTestCase):
38
39 @mock.patch.object(hashlib, 'sha1', return_value=MockSHA())
40 def test_get_interface_name(self, mock_sha1):
41 prefix = "pre-"
42 prefix_long = "long_prefix"
43 prefix_exceeds_max_dev_len = "much_too_long_prefix"
44 hash_used = MOCKED_HASH[0:6]
45
46 self.assertEqual("A_REALLY_" + hash_used,
47 utils.get_interface_name(LONG_NAME1))
48 self.assertEqual("SHORT",
49 utils.get_interface_name(SHORT_NAME))
50 self.assertEqual("pre-A_REA" + hash_used,
51 utils.get_interface_name(LONG_NAME1, prefix=prefix))
52 self.assertEqual("pre-SHORT",
53 utils.get_interface_name(SHORT_NAME, prefix=prefix))
54 # len(prefix) > max_device_len - len(hash_used)
55 self.assertRaises(ValueError, utils.get_interface_name, SHORT_NAME,
56 prefix_long)
57 # len(prefix) > max_device_len
58 self.assertRaises(ValueError, utils.get_interface_name, SHORT_NAME,
59 prefix=prefix_exceeds_max_dev_len)
60
61 def test_get_interface_uniqueness(self):
62 prefix = "prefix-"
63 if_prefix1 = utils.get_interface_name(LONG_NAME1, prefix=prefix)
64 if_prefix2 = utils.get_interface_name(LONG_NAME2, prefix=prefix)
65 self.assertNotEqual(if_prefix1, if_prefix2)
66
67 @mock.patch.object(hashlib, 'sha1', return_value=MockSHA())
68 def test_get_interface_max_len(self, mock_sha1):
69 self.assertEqual(constants.DEVICE_NAME_MAX_LEN,
70 len(utils.get_interface_name(LONG_NAME1)))
71 self.assertEqual(10, len(utils.get_interface_name(LONG_NAME1,
72 max_len=10)))
73 self.assertEqual(12, len(utils.get_interface_name(LONG_NAME1,
74 prefix="pre-",
75 max_len=12)))
76
77 def test_delete_port_on_error(self):
78 core_plugin, context = mock.Mock(), mock.Mock()
79 port_id = 'pid'
80 with testtools.ExpectedException(ValueError):
81 with utils.delete_port_on_error(core_plugin, context, port_id):
82 raise ValueError()
83 core_plugin.delete_port.assert_called_once_with(context, port_id,
84 l3_port_check=False)
85
86 def test_delete_port_on_error_fail_port_delete(self):
87 core_plugin, context = mock.Mock(), mock.Mock()
88 core_plugin.delete_port.side_effect = TypeError()
89 port_id = 'pid'
90 with testtools.ExpectedException(ValueError):
91 with utils.delete_port_on_error(core_plugin, context, port_id):
92 raise ValueError()
93 core_plugin.delete_port.assert_called_once_with(context, port_id,
94 l3_port_check=False)
95
96 def test_delete_port_on_error_port_does_not_exist(self):
97 core_plugin, context = mock.Mock(), mock.Mock()
98 port_id = 'pid'
99 core_plugin.delete_port.side_effect = exceptions.PortNotFound(
100 port_id=port_id)
101 with testtools.ExpectedException(exceptions.PortNotFound):
102 with utils.delete_port_on_error(core_plugin, context, port_id):
103 raise exceptions.PortNotFound(port_id=port_id)
104 core_plugin.delete_port.assert_called_once_with(context, port_id,
105 l3_port_check=False)
106
107 @mock.patch.object(l3_db.L3_NAT_dbonly_mixin, '_check_router_port')
108 def test_update_port_on_error(self, mock_check):
109 core_plugin, context = mock.Mock(), mock.Mock()
110 port = mock_check.return_value = {'device_owner': 'xxxxxxxx'}
111 revert_value = {'device_id': '', 'device_owner': port['device_owner']}
112 with testtools.ExpectedException(ValueError):
113 with utils.update_port_on_error(core_plugin,
114 context, 1, revert_value):
115 raise ValueError()
116 core_plugin.update_port.assert_called_once_with(
117 context, 1, {'port': revert_value})