Remove support for /os-fixed-ips REST API

This drops support for the os-fixed-ips compute REST API which has been
deprecated since
Newton: I1a8a44530be29292561e90d6f7bd7ed512a88ee3

Now it returns 410 response. Unit tests are removed and the functional API
sample test is just asserting the 410 response now. The API sample docs are
left intact since the API reference still builds from those and can be
considered more or less branchless, so people looking at the API reference
can apply it to older deployments of nova before os-fixed-ips was removed.

Part of blueprint remove-nova-network

Change-Id: I61f758ff9285448d431b45f67c70286082b4ee90
This commit is contained in:
jichen 2018-05-15 16:22:08 +08:00 committed by Matt Riedemann
parent 7968670d52
commit 5097309f89
15 changed files with 31 additions and 554 deletions

View File

@ -60,7 +60,6 @@ the `API guide <http://developer.openstack.org/api-guide/compute/index.html>`_.
.. include:: images.inc
.. include:: os-baremetal-nodes.inc
.. include:: os-tenant-network.inc
.. include:: os-fixed-ips.inc
.. include:: os-floating-ip-dns.inc
.. include:: os-floating-ip-pools.inc
.. include:: os-floating-ips.inc
@ -81,3 +80,4 @@ Compute API in the past, but no longer exist.
.. include:: os-cloudpipe.inc
.. include:: os-fping.inc
.. include:: os-virtual-interfaces.inc
.. include:: os-fixed-ips.inc

View File

@ -6,9 +6,9 @@
.. warning::
These APIs are proxy calls to the Network service. Nova has
deprecated all the proxy APIs and users should use the native APIs
instead. These will fail with a 404 starting from microversion 2.36.
These APIs only work with **nova-network** which is deprecated.
These will fail with a 404 starting from microversion 2.36.
They were removed in the 18.0.0 Rocky release.
Shows data for a fixed IP, such as host name, CIDR, and address. Also,
reserves and releases a fixed IP address.
@ -22,7 +22,8 @@ Shows details for a fixed IP address.
Normal response codes: 200
Error response codes: badRequest(400), unauthorized(401), forbidden(403), itemNotFound(404)
Error response codes: badRequest(400), unauthorized(401), forbidden(403),
itemNotFound(404), gone(410)
Request
-------
@ -61,7 +62,8 @@ To release a fixed IP address, specify ``unreserve`` in the request body.
Normal response codes: 202
Error response codes: badRequest(400), unauthorized(401), forbidden(403), itemNotFound(404)
Error response codes: badRequest(400), unauthorized(401), forbidden(403),
itemNotFound(404), gone(410)
Request
-------

View File

@ -12,96 +12,23 @@
# License for the specific language governing permissions and limitations
# under the License.
import webob
import webob.exc
from webob import exc
from nova.api.openstack.api_version_request \
import MAX_PROXY_API_SUPPORT_VERSION
from nova.api.openstack.compute.schemas import fixed_ips
from nova.api.openstack import wsgi
from nova.api import validation
from nova import exception
from nova.i18n import _
from nova import objects
from nova.policies import fixed_ips as fi_policies
class FixedIPController(wsgi.Controller):
@wsgi.Controller.api_version('2.1', '2.3')
def _fill_reserved_status(self, req, fixed_ip, fixed_ip_info):
# NOTE(mriedem): To be backwards compatible, < 2.4 version does not
# show anything about reserved status.
pass
@wsgi.Controller.api_version('2.4') # noqa
def _fill_reserved_status(self, req, fixed_ip, fixed_ip_info):
fixed_ip_info['fixed_ip']['reserved'] = fixed_ip.reserved
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
@wsgi.expected_errors((400, 404))
@wsgi.expected_errors((410))
def show(self, req, id):
"""Return data about the given fixed IP."""
context = req.environ['nova.context']
context.can(fi_policies.BASE_POLICY_NAME)
raise exc.HTTPGone()
attrs = ['network', 'instance']
try:
fixed_ip = objects.FixedIP.get_by_address(context, id,
expected_attrs=attrs)
except exception.FixedIpNotFoundForAddress as ex:
raise webob.exc.HTTPNotFound(explanation=ex.format_message())
except exception.FixedIpInvalid as ex:
raise webob.exc.HTTPBadRequest(explanation=ex.format_message())
fixed_ip_info = {"fixed_ip": {}}
if fixed_ip is None:
msg = _("Fixed IP %s has been deleted") % id
raise webob.exc.HTTPNotFound(explanation=msg)
fixed_ip_info['fixed_ip']['cidr'] = str(fixed_ip.network.cidr)
fixed_ip_info['fixed_ip']['address'] = str(fixed_ip.address)
if fixed_ip.instance:
fixed_ip_info['fixed_ip']['hostname'] = fixed_ip.instance.hostname
fixed_ip_info['fixed_ip']['host'] = fixed_ip.instance.host
else:
fixed_ip_info['fixed_ip']['hostname'] = None
fixed_ip_info['fixed_ip']['host'] = None
self._fill_reserved_status(req, fixed_ip, fixed_ip_info)
return fixed_ip_info
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
@wsgi.response(202)
@wsgi.expected_errors((400, 404))
@validation.schema(fixed_ips.reserve)
@wsgi.expected_errors((410))
@wsgi.action('reserve')
def reserve(self, req, id, body):
context = req.environ['nova.context']
context.can(fi_policies.BASE_POLICY_NAME)
raise exc.HTTPGone()
return self._set_reserved(context, id, True)
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
@wsgi.response(202)
@wsgi.expected_errors((400, 404))
@validation.schema(fixed_ips.unreserve)
@wsgi.expected_errors((410))
@wsgi.action('unreserve')
def unreserve(self, req, id, body):
context = req.environ['nova.context']
context.can(fi_policies.BASE_POLICY_NAME)
return self._set_reserved(context, id, False)
def _set_reserved(self, context, address, reserved):
try:
fixed_ip = objects.FixedIP.get_by_address(context, address)
fixed_ip.reserved = reserved
fixed_ip.save()
except exception.FixedIpNotFoundForAddress:
msg = _("Fixed IP %s not found") % address
raise webob.exc.HTTPNotFound(explanation=msg)
except exception.FixedIpInvalid:
msg = _("Fixed IP %s not valid") % address
raise webob.exc.HTTPBadRequest(explanation=msg)
raise exc.HTTPGone()

View File

@ -1,36 +0,0 @@
# Copyright 2015 Intel Corporation
# All Rights Reserved.
#
# 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 nova.api.validation import parameter_types
reserve = {
'type': 'object',
'properties': {
'reserve': parameter_types.none,
},
'required': ['reserve'],
'additionalProperties': False,
}
unreserve = {
'type': 'object',
'properties': {
'unreserve': parameter_types.none,
},
'required': ['unreserve'],
'additionalProperties': False,
}

View File

@ -36,7 +36,6 @@ from nova.policies import extended_server_attributes
from nova.policies import extended_status
from nova.policies import extended_volumes
from nova.policies import extensions
from nova.policies import fixed_ips
from nova.policies import flavor_access
from nova.policies import flavor_extra_specs
from nova.policies import flavor_manage
@ -112,7 +111,6 @@ def list_rules():
extended_status.list_rules(),
extended_volumes.list_rules(),
extensions.list_rules(),
fixed_ips.list_rules(),
flavor_access.list_rules(),
flavor_extra_specs.list_rules(),
flavor_manage.list_rules(),

View File

@ -1,49 +0,0 @@
# Copyright 2016 Cloudbase Solutions Srl
# All Rights Reserved.
#
# 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 oslo_policy import policy
from nova.policies import base
BASE_POLICY_NAME = 'os_compute_api:os-fixed-ips'
fixed_ips_policies = [
policy.DocumentedRuleDefault(
BASE_POLICY_NAME,
base.RULE_ADMIN_API,
"""Show details for, reserve and unreserve a fixed IP address.
These APIs are only available with nova-network which is deprecated.""",
[
{
'method': 'GET',
'path': '/os-fixed-ips/{fixed_ip}'
},
{
'method': 'POST',
'path': '/os-fixed-ips/{fixed_ip}/action (reserve)'
},
{
'method': 'POST',
'path': '/os-fixed-ips/{fixed_ip}/action (unreserve)'
}
]),
]
def list_rules():
return fixed_ips_policies

View File

@ -1,8 +0,0 @@
{
"fixed_ip": {
"cidr": "%(cidr)s",
"hostname": "%(hostname)s",
"host": "%(host)s",
"address": "%(address)s"
}
}

View File

@ -1,9 +0,0 @@
{
"fixed_ip": {
"cidr": "%(cidr)s",
"hostname": "%(hostname)s",
"host": "%(host)s",
"address": "%(address)s",
"reserved": %(reserved)s
}
}

View File

@ -12,100 +12,22 @@
# License for the specific language governing permissions and limitations
# under the License.
from nova import exception
from nova.tests.functional.api_sample_tests import test_servers
from nova.tests.unit.objects import test_network
from nova.tests.unit import utils as test_utils
from nova.tests import uuidsentinel as uuids
from nova.tests.functional.api import client as api_client
from nova.tests.functional import api_samples_test_base
class FixedIpTest(test_servers.ServersSampleBase):
sample_dir = "os-fixed-ips"
microversion = None
def setUp(self):
super(FixedIpTest, self).setUp()
self.api.microversion = self.microversion
instance = dict(test_utils.get_test_instance(),
hostname='compute.host.pvt', host='host')
fake_fixed_ips = [{'id': 1,
'address': '192.168.1.1',
'network_id': 1,
'virtual_interface_id': 1,
'instance_uuid': uuids.instance_1,
'allocated': False,
'leased': False,
'reserved': False,
'created_at': None,
'deleted_at': None,
'updated_at': None,
'deleted': None,
'instance': instance,
'network': test_network.fake_network,
'host': None},
{'id': 2,
'address': '192.168.1.2',
'network_id': 1,
'virtual_interface_id': 2,
'instance_uuid': uuids.instance_2,
'allocated': False,
'leased': False,
'reserved': False,
'created_at': None,
'deleted_at': None,
'updated_at': None,
'deleted': None,
'instance': instance,
'network': test_network.fake_network,
'host': None},
]
def fake_fixed_ip_get_by_address(context, address,
columns_to_join=None):
for fixed_ip in fake_fixed_ips:
if fixed_ip['address'] == address:
return fixed_ip
raise exception.FixedIpNotFoundForAddress(address=address)
def fake_fixed_ip_update(context, address, values):
fixed_ip = fake_fixed_ip_get_by_address(context, address)
if fixed_ip is None:
raise exception.FixedIpNotFoundForAddress(address=address)
else:
for key in values:
fixed_ip[key] = values[key]
self.stub_out("nova.db.fixed_ip_get_by_address",
fake_fixed_ip_get_by_address)
self.stub_out("nova.db.fixed_ip_update", fake_fixed_ip_update)
class FixedIpTest(api_samples_test_base.ApiSampleTestBase):
api_major_version = 'v2'
def test_fixed_ip_reserve(self):
# Reserve a Fixed IP.
response = self._do_post('os-fixed-ips/192.168.1.1/action',
'fixedip-post-req', {})
self.assertEqual(202, response.status_code)
self.assertEqual("", response.text)
def _test_get_fixed_ip(self, **kwargs):
# Return data about the given fixed ip.
response = self._do_get('os-fixed-ips/192.168.1.1')
project = {'cidr': '192.168.1.0/24',
'hostname': 'compute.host.pvt',
'host': 'host',
'address': '192.168.1.1'}
project.update(**kwargs)
self._verify_response('fixedips-get-resp', project, response, 200)
ex = self.assertRaises(api_client.OpenStackApiException,
self.api.api_post,
'/os-fixed-ips/192.168.1.1/action',
{"reserve": None})
self.assertEqual(410, ex.response.status_code)
def test_get_fixed_ip(self):
self._test_get_fixed_ip()
class FixedIpV24Test(FixedIpTest):
microversion = '2.4'
# NOTE(gmann): microversion tests do not need to run for v2 API
# so defining scenarios only for v2.4 which will run the original tests
# by appending '(v2_4)' in test_id.
scenarios = [('v2_4', {'api_major_version': 'v2.1'})]
def test_get_fixed_ip(self):
self._test_get_fixed_ip(reserved='False')
ex = self.assertRaises(api_client.OpenStackApiException,
self.api.api_get, '/os-fixed-ips/192.168.1.1')
self.assertEqual(410, ex.response.status_code)

View File

@ -1,265 +0,0 @@
# Copyright 2012 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.
import webob
from nova.api.openstack import api_version_request
from nova.api.openstack.compute import fixed_ips as fixed_ips_v21
from nova.api.openstack import wsgi as os_wsgi
from nova import context
from nova import exception
from nova import test
from nova.tests.unit.api.openstack import fakes
from nova.tests.unit.objects import test_network
from nova.tests import uuidsentinel as uuids
fake_fixed_ips = [{'id': 1,
'address': '192.168.1.1',
'network_id': 1,
'virtual_interface_id': 1,
'instance_uuid': uuids.instance_1,
'allocated': False,
'leased': False,
'reserved': False,
'host': None,
'instance': None,
'network': test_network.fake_network,
'created_at': None,
'updated_at': None,
'deleted_at': None,
'deleted': False},
{'id': 2,
'address': '192.168.1.2',
'network_id': 1,
'virtual_interface_id': 2,
'instance_uuid': uuids.instance_2,
'allocated': False,
'leased': False,
'reserved': False,
'host': None,
'instance': None,
'network': test_network.fake_network,
'created_at': None,
'updated_at': None,
'deleted_at': None,
'deleted': False},
{'id': 3,
'address': '10.0.0.2',
'network_id': 1,
'virtual_interface_id': 3,
'instance_uuid': uuids.instance_3,
'allocated': False,
'leased': False,
'reserved': False,
'host': None,
'instance': None,
'network': test_network.fake_network,
'created_at': None,
'updated_at': None,
'deleted_at': None,
'deleted': True},
]
def fake_fixed_ip_get_by_address(context, address, columns_to_join=None):
if address == 'inv.ali.d.ip':
msg = "Invalid fixed IP Address %s in request" % address
raise exception.FixedIpInvalid(msg)
for fixed_ip in fake_fixed_ips:
if fixed_ip['address'] == address and not fixed_ip['deleted']:
return fixed_ip
raise exception.FixedIpNotFoundForAddress(address=address)
def fake_fixed_ip_update(context, address, values):
fixed_ip = fake_fixed_ip_get_by_address(context, address)
if fixed_ip is None:
raise exception.FixedIpNotFoundForAddress(address=address)
else:
for key in values:
fixed_ip[key] = values[key]
class FakeModel(object):
"""Stubs out for model."""
def __init__(self, values):
self.values = values
def __getattr__(self, name):
return self.values[name]
def __getitem__(self, key):
if key in self.values:
return self.values[key]
else:
raise NotImplementedError()
def __repr__(self):
return '<FakeModel: %s>' % self.values
def fake_network_get_all(context):
network = {'id': 1,
'cidr': "192.168.1.0/24"}
return [FakeModel(network)]
class FixedIpTestV21(test.NoDBTestCase):
fixed_ips = fixed_ips_v21
url = '/v2/fake/os-fixed-ips'
wsgi_api_version = os_wsgi.DEFAULT_API_VERSION
def setUp(self):
super(FixedIpTestV21, self).setUp()
self.stub_out("nova.db.fixed_ip_get_by_address",
fake_fixed_ip_get_by_address)
self.stub_out("nova.db.fixed_ip_update", fake_fixed_ip_update)
self.context = context.get_admin_context()
self.controller = self.fixed_ips.FixedIPController()
def _assert_equal(self, ret, exp):
self.assertEqual(ret.wsgi_code, exp)
def _get_reserve_action(self):
return self.controller.reserve
def _get_unreserve_action(self):
return self.controller.unreserve
def _get_reserved_status(self, address):
return {}
def test_fixed_ips_get(self):
req = fakes.HTTPRequest.blank('%s/192.168.1.1' % self.url)
req.api_version_request = api_version_request.APIVersionRequest(
self.wsgi_api_version)
res_dict = self.controller.show(req, '192.168.1.1')
response = {'fixed_ip': {'cidr': '192.168.1.0/24',
'hostname': None,
'host': None,
'address': '192.168.1.1'}}
response['fixed_ip'].update(self._get_reserved_status('192.168.1.1'))
self.assertEqual(response, res_dict, self.wsgi_api_version)
def test_fixed_ips_get_bad_ip_fail(self):
req = fakes.HTTPRequest.blank('%s/10.0.0.1' % self.url)
self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, req,
'10.0.0.1')
def test_fixed_ips_get_invalid_ip_address(self):
req = fakes.HTTPRequest.blank('%s/inv.ali.d.ip' % self.url)
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.show, req,
'inv.ali.d.ip')
def test_fixed_ips_get_deleted_ip_fail(self):
req = fakes.HTTPRequest.blank('%s/10.0.0.2' % self.url)
self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, req,
'10.0.0.2')
def test_fixed_ip_reserve(self):
fake_fixed_ips[0]['reserved'] = False
body = {'reserve': None}
req = fakes.HTTPRequest.blank('%s/192.168.1.1/action' % self.url)
action = self._get_reserve_action()
result = action(req, "192.168.1.1", body=body)
self._assert_equal(result or action, 202)
self.assertTrue(fake_fixed_ips[0]['reserved'])
def test_fixed_ip_reserve_bad_ip(self):
body = {'reserve': None}
req = fakes.HTTPRequest.blank('%s/10.0.0.1/action' % self.url)
action = self._get_reserve_action()
self.assertRaises(webob.exc.HTTPNotFound, action, req,
'10.0.0.1', body=body)
def test_fixed_ip_reserve_invalid_ip_address(self):
body = {'reserve': None}
req = fakes.HTTPRequest.blank('%s/inv.ali.d.ip/action' % self.url)
action = self._get_reserve_action()
self.assertRaises(webob.exc.HTTPBadRequest,
action, req, 'inv.ali.d.ip', body=body)
def test_fixed_ip_reserve_deleted_ip(self):
body = {'reserve': None}
action = self._get_reserve_action()
req = fakes.HTTPRequest.blank('%s/10.0.0.2/action' % self.url)
self.assertRaises(webob.exc.HTTPNotFound, action, req,
'10.0.0.2', body=body)
def test_fixed_ip_unreserve(self):
fake_fixed_ips[0]['reserved'] = True
body = {'unreserve': None}
req = fakes.HTTPRequest.blank('%s/192.168.1.1/action' % self.url)
action = self._get_unreserve_action()
result = action(req, "192.168.1.1", body=body)
self._assert_equal(result or action, 202)
self.assertFalse(fake_fixed_ips[0]['reserved'])
def test_fixed_ip_unreserve_bad_ip(self):
body = {'unreserve': None}
req = fakes.HTTPRequest.blank('%s/10.0.0.1/action' % self.url)
action = self._get_unreserve_action()
self.assertRaises(webob.exc.HTTPNotFound, action, req,
'10.0.0.1', body=body)
def test_fixed_ip_unreserve_invalid_ip_address(self):
body = {'unreserve': None}
req = fakes.HTTPRequest.blank('%s/inv.ali.d.ip/action' % self.url)
action = self._get_unreserve_action()
self.assertRaises(webob.exc.HTTPBadRequest,
action, req, 'inv.ali.d.ip', body=body)
def test_fixed_ip_unreserve_deleted_ip(self):
body = {'unreserve': None}
req = fakes.HTTPRequest.blank('%s/10.0.0.2/action' % self.url)
action = self._get_unreserve_action()
self.assertRaises(webob.exc.HTTPNotFound, action, req,
'10.0.0.2', body=body)
class FixedIpTestV24(FixedIpTestV21):
wsgi_api_version = '2.4'
def _get_reserved_status(self, address):
for fixed_ip in fake_fixed_ips:
if address == fixed_ip['address']:
return {'reserved': fixed_ip['reserved']}
self.fail('Invalid address: %s' % address)
class FixedIpDeprecationTest(test.NoDBTestCase):
def setUp(self):
super(FixedIpDeprecationTest, self).setUp()
self.req = fakes.HTTPRequest.blank('', version='2.36')
self.controller = fixed_ips_v21.FixedIPController()
def test_all_apis_return_not_found(self):
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller.show, self.req, fakes.FAKE_UUID)
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller.reserve, self.req, fakes.FAKE_UUID, {})
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller.unreserve, self.req, fakes.FAKE_UUID, {})

View File

@ -39,7 +39,6 @@ policy_data = """
"os_compute_api:ips:index": "",
"os_compute_api:ips:show": "",
"os_compute_api:extensions": "",
"os_compute_api:os-fixed-ips": "",
"os_compute_api:os-flavor-access:remove_tenant_access": "",
"os_compute_api:os-flavor-access:add_tenant_access": "",
"os_compute_api:os-flavor-extra-specs:index": "",

View File

@ -302,7 +302,6 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
"os_compute_api:os-cells:sync_instances",
"os_compute_api:os-evacuate",
"os_compute_api:os-extended-server-attributes",
"os_compute_api:os-fixed-ips",
"os_compute_api:os-flavor-access:remove_tenant_access",
"os_compute_api:os-flavor-access:add_tenant_access",
"os_compute_api:os-flavor-extra-specs:create",

View File

@ -9,6 +9,9 @@ upgrade:
* ``GET /os-fping``
* ``GET /os-fping/{server_id}``
* ``GET /servers/{server_id}/os-virtual-interfaces``
* ``GET /os-fixed-ips/{fixed_ip}``
* ``POST /os-fixed-ips/{fixed_ip}/action (reserve)``
* ``POST /os-fixed-ips/{fixed_ip}/action (unreserve)``
In addition, the following configuration options have been removed.