Remove deprecated network APIs

These were deprecated in Newton:

aaebeb05a0

The 'find network' convenience helper when
booting a server only works with neutron now,
and assumes the 'network' endpoint is in the
service catalog.

The functional tests are changed to use
python-neutronclient for listing and finding
the network to use. At this point, we don't
have any nova-network CI jobs that will work
with novaclient, so the non-voting mitaka
nova-network job is also being removed in change
I63b36fb8acc5c9a273e6adcb271df16d0f71031e.

As noted in the release note, the only remaining
pure nova-network CLI/API that will work is for
listing virtual interfaces, which is only implemented
for nova-network within Nova. The functional tests
for this API are removed since we don't have any
nova-network CI jobs that will test it besides
unit tests. Long-term we'll likely deprecate the
os-virtual-interfaces API as well and replace it with
the os-interface API.

Change-Id: I8c520100a0016eed3959619c71dae037ebd72939
This commit is contained in:
Matt Riedemann 2017-03-20 19:39:35 -04:00
parent b98a033d16
commit 3a03a0e10d
14 changed files with 32 additions and 587 deletions

View File

@ -33,4 +33,4 @@ class TestServersAPI(base.ClientTestBase):
self.fail("Server %s did not go ACTIVE after 60s" % server)
ips = self.client.servers.ips(server)
self.assertIn(self.network.label, ips)
self.assertIn(self.network.name, ips)

View File

@ -21,6 +21,7 @@ from keystoneauth1 import identity
from keystoneauth1 import session as ksession
from keystoneclient import client as keystoneclient
from keystoneclient import discover as keystone_discover
from neutronclient.v2_0 import client as neutronclient
import os_client_config
from oslo_utils import uuidutils
import tempest.lib.cli.base
@ -29,6 +30,7 @@ import testtools
import novaclient
import novaclient.api_versions
import novaclient.client
from novaclient.v2 import networks
import novaclient.v2.shell
BOOT_IS_COMPLETE = ("login as 'cirros' user. default password: "
@ -79,7 +81,7 @@ def pick_network(networks):
network_name = os.environ.get('OS_NOVACLIENT_NETWORK')
if network_name:
for network in networks:
if network.label == network_name:
if network.name == network_name:
return network
raise NoNetworkException()
return networks[0]
@ -224,21 +226,20 @@ class ClientTestBase(testtools.TestCase):
self.image = CACHE["image"]
if "network" not in CACHE:
tested_api_version = self.client.api_version
proxy_api_version = novaclient.api_versions.APIVersion('2.35')
if tested_api_version > proxy_api_version:
self.client.api_version = proxy_api_version
try:
# TODO(mriedem): Get the networks from neutron if using neutron
networks = self.client.networks.list()
# Keep track of whether or not there are multiple networks
# available to the given tenant because if so, a specific
# network ID has to be passed in on server create requests
# otherwise the server POST will fail with a 409.
CACHE['multiple_networks'] = len(networks) > 1
CACHE["network"] = pick_network(networks)
finally:
self.client.api_version = tested_api_version
# Get the networks from neutron.
neutron = neutronclient.Client(session=session)
neutron_networks = neutron.list_networks()['networks']
# Convert the neutron dicts to Network objects.
nets = []
for network in neutron_networks:
nets.append(networks.Network(
networks.NeutronManager, network))
# Keep track of whether or not there are multiple networks
# available to the given tenant because if so, a specific
# network ID has to be passed in on server create requests
# otherwise the server POST will fail with a 409.
CACHE['multiple_networks'] = len(nets) > 1
CACHE["network"] = pick_network(nets)
self.network = CACHE["network"]
self.multiple_networks = CACHE['multiple_networks']
@ -264,15 +265,6 @@ class ClientTestBase(testtools.TestCase):
password=passwd)
self.cinder = cinderclient.Client(auth=auth, session=session)
if "use_neutron" not in CACHE:
# check to see if we're running with neutron or not
for service in self.keystone.services.list():
if service.type == 'network':
CACHE["use_neutron"] = True
break
else:
CACHE["use_neutron"] = False
def _get_novaclient(self, session):
nc = novaclient.client.Client("2", session=session)
@ -500,10 +492,6 @@ class ClientTestBase(testtools.TestCase):
project = self.keystone.tenants.find(name=name)
return project.id
def skip_if_neutron(self):
if CACHE["use_neutron"]:
self.skipTest('nova-network is not available')
def _cleanup_server(self, server_id):
"""Deletes a server and waits for it to be gone."""
self.client.servers.delete(server_id)

View File

@ -67,7 +67,7 @@ class TestServersBootNovaClient(base.ClientTestBase):
"--nic net-name=%(net-name)s" % {"name": uuidutils.generate_uuid(),
"image": self.image.id,
"flavor": self.flavor.id,
"net-name": self.network.label}))
"net-name": self.network.name}))
server_id = self._get_value_from_the_table(server_info, "id")
self.client.servers.delete(server_id)

View File

@ -1,30 +0,0 @@
# Copyright 2015 IBM Corp.
# 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 novaclient.tests.functional import base
class TestVirtualInterfacesNovaClient(base.ClientTestBase):
"""Virtual Interfaces functional tests."""
COMPUTE_API_VERSION = "2.1"
def test_virtual_interface_list(self):
# os-virtual-interfaces does not proxy to neutron
self.skip_if_neutron()
server = self._create_server()
output = self.nova('virtual-interface-list %s' % server.id)
self.assertTrue(len(output.split("\n")) > 5,
"Output table of `virtual-interface-list` for the test"
" server should not be empty.")
return output

View File

@ -1,27 +0,0 @@
# 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 novaclient.tests.functional.v2.legacy import test_virtual_interface
class TestVirtualInterfacesNovaClient(
test_virtual_interface.TestVirtualInterfacesNovaClient):
"""Virtual Interfaces functional tests."""
COMPUTE_API_VERSION = "2.latest"
def test_virtual_interface_list(self):
output = super(TestVirtualInterfacesNovaClient,
self).test_virtual_interface_list()
self.assertEqual(self.network.id,
self._get_column_value_from_single_row_table(
output, "Network ID"))

View File

@ -1,61 +0,0 @@
# 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 novaclient.tests.unit.fixture_data import base
class Fixture(base.Fixture):
base_url = 'os-networks'
def setUp(self):
super(Fixture, self).setUp()
get_os_networks = {
'networks': [
{
"label": "1",
"cidr": "10.0.0.0/24",
'project_id': '4ffc664c198e435e9853f2538fbcd7a7',
'id': '1'
}
]
}
headers = self.json_headers
self.requests_mock.get(self.url(),
json=get_os_networks,
headers=headers)
def post_os_networks(request, context):
return {'network': request.json()}
self.requests_mock.post(self.url(),
json=post_os_networks,
headers=headers)
get_os_networks_1 = {'network': {"label": "1", "cidr": "10.0.0.0/24"}}
self.requests_mock.get(self.url(1),
json=get_os_networks_1,
headers=headers)
self.requests_mock.delete(self.url('networkdelete'),
status_code=202,
headers=headers)
for u in ('add', 'networkdisassociate/action', 'networktest/action',
'1/action', '2/action'):
self.requests_mock.post(self.url(u),
status_code=202,
headers=headers)

View File

@ -1781,27 +1781,6 @@ class FakeSessionClient(base_client.SessionClient):
return (200, {}, {"networks": networks_by_name[name]})
def get_os_networks(self, **kw):
return (200, {}, {'networks': [{"label": "1", "cidr": "10.0.0.0/24",
'project_id':
'4ffc664c198e435e9853f2538fbcd7a7',
'id': '1', 'vlan': '1234'}]})
def delete_os_networks_1(self, **kw):
return (202, {}, None)
def post_os_networks(self, **kw):
return (202, {}, {'network': kw})
def post_os_networks_add(self, **kw):
return (202, {}, None)
def post_os_networks_1_action(self, **kw):
return (202, {}, None)
def post_os_networks_2_action(self, **kw):
return (202, {}, None)
def get_os_availability_zone_detail(self, **kw):
return (200, {}, {
"availabilityZoneInfo": [

View File

@ -1,119 +0,0 @@
#
# 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 novaclient.tests.unit.fixture_data import client
from novaclient.tests.unit.fixture_data import networks as data
from novaclient.tests.unit import utils
from novaclient.tests.unit.v2 import fakes
from novaclient.v2 import networks
class NetworksTest(utils.FixturedTestCase):
client_fixture_class = client.V1
data_fixture_class = data.Fixture
def test_list_networks(self):
fl = self.cs.networks.list()
self.assert_request_id(fl, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called('GET', '/os-networks')
for f in fl:
self.assertIsInstance(f, networks.Network)
def test_get_network(self):
f = self.cs.networks.get(1)
self.assert_request_id(f, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called('GET', '/os-networks/1')
self.assertIsInstance(f, networks.Network)
def test_delete(self):
ret = self.cs.networks.delete('networkdelete')
self.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called('DELETE', '/os-networks/networkdelete')
def test_create(self):
f = self.cs.networks.create(label='foo')
self.assert_request_id(f, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called('POST', '/os-networks',
{'network': {'label': 'foo'}})
self.assertIsInstance(f, networks.Network)
def test_create_allparams(self):
params = {
'label': 'bar',
'bridge': 'br0',
'bridge_interface': 'int0',
'cidr': '192.0.2.0/24',
'cidr_v6': '2001:DB8::/32',
'dns1': '1.1.1.1',
'dns2': '1.1.1.2',
'fixed_cidr': '198.51.100.0/24',
'gateway': '192.0.2.1',
'gateway_v6': '2001:DB8::1',
'multi_host': 'T',
'priority': '1',
'project_id': '1',
'vlan': 5,
'vlan_start': 1,
'vpn_start': 1,
'mtu': 1500,
'enable_dhcp': 'T',
'dhcp_server': '1920.2.2',
'share_address': 'T',
'allowed_start': '192.0.2.10',
'allowed_end': '192.0.2.20',
}
f = self.cs.networks.create(**params)
self.assert_request_id(f, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called('POST', '/os-networks', {'network': params})
self.assertIsInstance(f, networks.Network)
def test_associate_project(self):
f = self.cs.networks.associate_project('networktest')
self.assert_request_id(f, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called('POST', '/os-networks/add',
{'id': 'networktest'})
def test_associate_host(self):
f = self.cs.networks.associate_host('networktest', 'testHost')
self.assert_request_id(f, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called('POST', '/os-networks/networktest/action',
{'associate_host': 'testHost'})
def test_disassociate(self):
f = self.cs.networks.disassociate('networkdisassociate')
self.assert_request_id(f, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called('POST',
'/os-networks/networkdisassociate/action',
{'disassociate': None})
def test_disassociate_host_only(self):
f = self.cs.networks.disassociate('networkdisassociate', True, False)
self.assert_request_id(f, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called('POST',
'/os-networks/networkdisassociate/action',
{'disassociate_host': None})
def test_disassociate_project(self):
f = self.cs.networks.disassociate('networkdisassociate', False, True)
self.assert_request_id(f, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called('POST',
'/os-networks/networkdisassociate/action',
{'disassociate_project': None})
def test_add(self):
f = self.cs.networks.add('networkadd')
self.assert_request_id(f, fakes.FAKE_REQUEST_ID_LIST)
self.assert_called('POST', '/os-networks/add',
{'id': 'networkadd'})

View File

@ -822,61 +822,7 @@ class ShellTest(utils.TestCase):
'--nic net-id=net-id1,net-id=net-id2 some-server' % FAKE_UUID_1)
self.assertRaises(exceptions.CommandError, self.run_command, cmd)
@mock.patch('novaclient.v2.client.Client.has_neutron', return_value=False)
def test_boot_nics_net_name(self, has_neutron):
cmd = ('boot --image %s --flavor 1 '
'--nic net-name=1 some-server' % FAKE_UUID_1)
self.run_command(cmd)
self.assert_called_anytime(
'POST', '/servers',
{
'server': {
'flavorRef': '1',
'name': 'some-server',
'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
'networks': [
{'uuid': '1'},
],
},
},
)
@mock.patch('novaclient.v2.client.Client.has_neutron', return_value=False)
def test_boot_nics_net_name_nova_net_2_36(self, has_neutron):
orig_find_network = novaclient.v2.shell._find_network_id_novanet
def stubbed_find_network(cs, net_name):
# assert that we dropped back to 2.35
self.assertEqual(api_versions.APIVersion('2.35'),
cs.client.api_version)
return orig_find_network(cs, net_name)
cmd = ('boot --image %s --flavor 1 '
'--nic net-name=1 some-server' % FAKE_UUID_1)
with mock.patch.object(novaclient.v2.shell, '_find_network_id_novanet',
side_effect=stubbed_find_network) as find_net:
self.run_command(cmd, api_version='2.36')
find_net.assert_called_once_with(self.shell.cs, '1')
self.assert_called_anytime(
'POST', '/servers',
{
'server': {
'flavorRef': '1',
'name': 'some-server',
'imageRef': FAKE_UUID_1,
'min_count': 1,
'max_count': 1,
'networks': [
{'uuid': '1'},
],
},
},
)
@mock.patch('novaclient.v2.client.Client.has_neutron', return_value=True)
def test_boot_nics_net_name_neutron(self, has_neutron):
def test_boot_nics_net_name_neutron(self):
cmd = ('boot --image %s --flavor 1 '
'--nic net-name=private some-server' % FAKE_UUID_1)
self.run_command(cmd)
@ -896,8 +842,7 @@ class ShellTest(utils.TestCase):
},
)
@mock.patch('novaclient.v2.client.Client.has_neutron', return_value=True)
def test_boot_nics_net_name_neutron_dup(self, has_neutron):
def test_boot_nics_net_name_neutron_dup(self):
cmd = ('boot --image %s --flavor 1 '
'--nic net-name=duplicate some-server' % FAKE_UUID_1)
# this should raise a multiple matches error
@ -906,8 +851,7 @@ class ShellTest(utils.TestCase):
with testtools.ExpectedException(exceptions.CommandError, msg):
self.run_command(cmd)
@mock.patch('novaclient.v2.client.Client.has_neutron', return_value=True)
def test_boot_nics_net_name_neutron_blank(self, has_neutron):
def test_boot_nics_net_name_neutron_blank(self):
cmd = ('boot --image %s --flavor 1 '
'--nic net-name=blank some-server' % FAKE_UUID_1)
# this should raise a multiple matches error
@ -919,25 +863,6 @@ class ShellTest(utils.TestCase):
# out other tests, and they should check the string in the
# CommandError, because it's not really enough to distinguish
# between various errors.
@mock.patch('novaclient.v2.client.Client.has_neutron', return_value=False)
def test_boot_nics_net_name_not_found(self, has_neutron):
cmd = ('boot --image %s --flavor 1 '
'--nic net-name=some-net some-server' % FAKE_UUID_1)
self.assertRaises(exceptions.ResourceNotFound, self.run_command, cmd)
@mock.patch('novaclient.v2.client.Client.has_neutron', return_value=False)
@mock.patch(
'novaclient.tests.unit.v2.fakes.FakeSessionClient.get_os_networks')
def test_boot_nics_net_name_multiple_matches(self, mock_networks_list,
has_neutron):
mock_networks_list.return_value = (200, {}, {
'networks': [{"label": "some-net", 'id': '1'},
{"label": "some-net", 'id': '2'}]})
cmd = ('boot --image %s --flavor 1 '
'--nic net-name=some-net some-server' % FAKE_UUID_1)
self.assertRaises(exceptions.NoUniqueMatch, self.run_command, cmd)
@mock.patch('novaclient.v2.shell._find_network_id', return_value='net-id')
def test_boot_nics_net_name_and_net_id(self, mock_find_network_id):
cmd = ('boot --image %s --flavor 1 '

View File

@ -15,8 +15,6 @@
import logging
from keystoneauth1.exceptions import catalog as key_ex
from novaclient import client
from novaclient import exceptions
from novaclient.i18n import _
@ -155,7 +153,6 @@ class Client(object):
self.certs = certs.CertificateManager(self)
self.volumes = volumes.VolumeManager(self)
self.keypairs = keypairs.KeypairManager(self)
self.networks = networks.NetworkManager(self)
self.neutron = networks.NeutronManager(self)
self.quota_classes = quota_classes.QuotaClassSetManager(self)
self.quotas = quotas.QuotaSetManager(self)
@ -278,23 +275,6 @@ class Client(object):
def reset_timings(self):
self.client.reset_timings()
def has_neutron(self):
"""Check the service catalog to figure out if we have neutron.
This is an intermediary solution for the window of time where
we still have nova-network support in the client, but we
expect most people have neutron. This ensures that if they
have neutron we understand, we talk to it, if they don't, we
fail back to nova proxies.
"""
try:
endpoint = self.client.get_endpoint(service_type='network')
if endpoint:
return True
return False
except key_ex.EndpointNotFound:
return False
def authenticate(self):
"""Authenticate against the server.

View File

@ -16,7 +16,6 @@
"""
Network interface.
"""
from novaclient import api_versions
from novaclient import base
from novaclient import exceptions
from novaclient.i18n import _
@ -24,21 +23,13 @@ from novaclient.i18n import _
class Network(base.Resource):
"""
A network.
A network as defined in the Networking (Neutron) API.
"""
HUMAN_ID = True
NAME_ATTR = "label"
NAME_ATTR = "name"
def __repr__(self):
return "<Network: %s>" % self.label
def delete(self):
"""
DEPRECATED: Delete this network.
:returns: An instance of novaclient.base.TupleWithMeta
"""
return self.manager.delete(self)
return "<Network: %s>" % self.name
class NeutronManager(base.Manager):
@ -72,145 +63,3 @@ class NeutronManager(base.Manager):
else:
matches[0].append_request_ids(matches.request_ids)
return matches[0]
class NetworkManager(base.ManagerWithFind):
"""
DEPRECATED: Manage :class:`Network` resources.
"""
resource_class = Network
@api_versions.deprecated_after('2.35')
def list(self):
"""
DEPRECATED: Get a list of all networks.
:rtype: list of :class:`Network`.
"""
return self._list("/os-networks", "networks")
@api_versions.deprecated_after('2.35')
def get(self, network):
"""
DEPRECATED: Get a specific network.
:param network: The ID of the :class:`Network` to get.
:rtype: :class:`Network`
"""
return self._get("/os-networks/%s" % base.getid(network),
"network")
@api_versions.deprecated_after('2.35')
def delete(self, network):
"""
DEPRECATED: Delete a specific network.
:param network: The ID of the :class:`Network` to delete.
:returns: An instance of novaclient.base.TupleWithMeta
"""
return self._delete("/os-networks/%s" % base.getid(network))
@api_versions.deprecated_after('2.35')
def create(self, **kwargs):
"""
DEPRECATED: Create (allocate) a network. The following parameters are
optional except for label; cidr or cidr_v6 must be specified, too.
:param label: str
:param bridge: str
:param bridge_interface: str
:param cidr: str
:param cidr_v6: str
:param dns1: str
:param dns2: str
:param fixed_cidr: str
:param gateway: str
:param gateway_v6: str
:param multi_host: str
:param priority: str
:param project_id: str
:param vlan: int
:param vlan_start: int
:param vpn_start: int
:param mtu: int
:param enable_dhcp: int
:param dhcp_server: str
:param share_address: int
:param allowed_start: str
:param allowed_end: str
:rtype: object of :class:`Network`
"""
body = {"network": kwargs}
return self._create('/os-networks', body, 'network')
@api_versions.deprecated_after('2.35')
def disassociate(self, network, disassociate_host=True,
disassociate_project=True):
"""
DEPRECATED: Disassociate a specific network from project and/or host.
:param network: The ID of the :class:`Network`.
:param disassociate_host: Whether to disassociate the host
:param disassociate_project: Whether to disassociate the project
:returns: An instance of novaclient.base.TupleWithMeta
"""
if disassociate_host and disassociate_project:
body = {"disassociate": None}
elif disassociate_project:
body = {"disassociate_project": None}
elif disassociate_host:
body = {"disassociate_host": None}
else:
raise exceptions.CommandError(
_("Must disassociate either host or project or both"))
resp, body = self.api.client.post("/os-networks/%s/action" %
base.getid(network), body=body)
return self.convert_into_with_meta(body, resp)
@api_versions.deprecated_after('2.35')
def associate_host(self, network, host):
"""
DEPRECATED: Associate a specific network with a host.
:param network: The ID of the :class:`Network`.
:param host: The name of the host to associate the network with
:returns: An instance of novaclient.base.TupleWithMeta
"""
resp, body = self.api.client.post("/os-networks/%s/action" %
base.getid(network),
body={"associate_host": host})
return self.convert_into_with_meta(body, resp)
@api_versions.deprecated_after('2.35')
def associate_project(self, network):
"""
DEPRECATED: Associate a specific network with a project.
The project is defined by the project authenticated against
:param network: The ID of the :class:`Network`.
:returns: An instance of novaclient.base.TupleWithMeta
"""
resp, body = self.api.client.post("/os-networks/add",
body={"id": network})
return self.convert_into_with_meta(body, resp)
@api_versions.deprecated_after('2.35')
def add(self, network=None):
"""
DEPRECATED: Associates the current project with a network. Network can
be chosen automatically or provided explicitly.
:param network: The ID of the :class:`Network` to associate (optional).
:returns: An instance of novaclient.base.TupleWithMeta
"""
resp, body = self.api.client.post("/os-networks/add",
body={"id": base.getid(network)
if network else None})
return self.convert_into_with_meta(body, resp)

View File

@ -2037,7 +2037,7 @@ def _find_flavor(cs, flavor):
return cs.flavors.find(ram=flavor)
def _find_network_id_neutron(cs, net_name):
def _find_network_id(cs, net_name):
"""Get unique network ID from network name from neutron"""
try:
return cs.neutron.find_network(net_name).id
@ -2045,50 +2045,6 @@ def _find_network_id_neutron(cs, net_name):
raise exceptions.CommandError(six.text_type(e))
def _find_network_id(cs, net_name):
"""Find the network id for a network name.
If we have access to neutron in the service catalog, use neutron
for this lookup, otherwise use nova. This ensures that we do the
right thing in the future.
Once nova network support is deleted, we can delete this check and
the has_neutron function.
"""
if cs.has_neutron():
return _find_network_id_neutron(cs, net_name)
else:
# The network proxy API methods were deprecated in 2.36 and will return
# a 404 so we fallback to 2.35 to maintain a transition for CLI users.
want_version = api_versions.APIVersion('2.35')
cur_version = cs.api_version
if cs.api_version > want_version:
cs.api_version = want_version
try:
return _find_network_id_novanet(cs, net_name)
finally:
cs.api_version = cur_version
def _find_network_id_novanet(cs, net_name):
"""Get unique network ID from network name."""
network_id = None
for net_info in cs.networks.list():
if net_name == net_info.label:
if network_id is not None:
msg = (_("Multiple network name matches found for name '%s', "
"use network ID to be more specific.") % net_name)
raise exceptions.NoUniqueMatch(msg)
else:
network_id = net_info.id
if network_id is None:
msg = (_("No network name match for name '%s'") % net_name)
raise exceptions.ResourceNotFound(msg % {'network': net_name})
else:
return network_id
@utils.arg('server', metavar='<server>', help=_('Name or ID of server.'))
@utils.arg(
'network_id',

View File

@ -1,6 +1,9 @@
---
prelude: >
Deprecated network-related resource commands have been removed.
Deprecated network-related resource commands and python API bindings
have been removed. From this point on, python-novaclient will no longer
work with nova-network *except* for the ``nova virtual-interface-list``
command.
upgrade:
- |
The following deprecated network-related resource commands have been
@ -61,6 +64,7 @@ upgrade:
* novaclient.v2.floating_ips
* novaclient.v2.floating_ips_bulk
* novaclient.v2.fping
* novaclient.v2.networks
* novaclient.v2.security_group_default_rules
* novaclient.v2.security_group_rules
* novaclient.v2.security_groups

View File

@ -11,6 +11,7 @@ mock>=2.0 # BSD
python-keystoneclient>=3.8.0 # Apache-2.0
python-cinderclient>=2.0.1 # Apache-2.0
python-glanceclient>=2.5.0 # Apache-2.0
python-neutronclient>=5.1.0 # Apache-2.0
requests-mock>=1.1 # Apache-2.0
sphinx>=1.5.1 # BSD
os-client-config>=1.22.0 # Apache-2.0