Remove support for /os-fping REST API

This drops support for the fping compute REST API which
has been deprecated since Newton:

  I1a8a44530be29292561e90d6f7bd7ed512a88ee3

To match the os-cloudpipe and os-certificates removals
the os-fping controller now returns a 410 response.

The related fping_path configuration option is removed
along with the related fping policy rules.

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-fping
was removed.

A release note is started which we can build on for each
nova-network specific API that we remove in this series.

Part of blueprint remova-nova-network

Change-Id: Ia36aaa8f74adc2b540c49523db522cd85ab17ed2
This commit is contained in:
Matt Riedemann 2018-05-10 15:12:35 -04:00
parent 25fa2470e2
commit 02661caabc
14 changed files with 36 additions and 449 deletions

View File

@ -65,7 +65,6 @@ the `API guide <http://developer.openstack.org/api-guide/compute/index.html>`_.
.. include:: os-floating-ip-pools.inc
.. include:: os-floating-ips.inc
.. include:: os-floating-ips-bulk.inc
.. include:: os-fping.inc
.. include:: os-security-groups.inc
.. include:: os-security-group-default-rules.inc
.. include:: os-security-group-rules.inc
@ -81,3 +80,4 @@ Compute API in the past, but no longer exist.
.. include:: os-certificates.inc
.. include:: os-cloudpipe.inc
.. include:: os-fping.inc

View File

@ -9,6 +9,7 @@
This API only works with ``nova-network`` which is
deprecated. It should be avoided in any new applications.
These will fail with a 404 starting from microversion 2.36.
It was removed in the 18.0.0 Rocky release.
Pings instances and reports which instances are alive.
@ -37,7 +38,8 @@ change these permissions through the ``policy.json`` file.
Normal response codes: 200
Error response codes: serviceUnavailable(503), unauthorized(401), forbidden(403)
Error response codes: serviceUnavailable(503), unauthorized(401), forbidden(403),
itemNotFound(404), gone(410)
Request
-------
@ -80,7 +82,7 @@ change these permissions through the ``policy.json`` file.
Normal response codes: 200
Error response codes: serviceUnavailable(503), unauthorized(401), forbidden(403),
itemNotFound(404)
itemNotFound(404), gone(410)
Request
-------

View File

@ -14,126 +14,17 @@
# License for the specific language governing permissions and limitations
# under the License.
import itertools
import os
from webob import exc
from oslo_concurrency import processutils
from nova.api.openstack.api_version_request \
import MAX_PROXY_API_SUPPORT_VERSION
from nova.api.openstack import common
from nova.api.openstack.compute.schemas import fping as schema
from nova.api.openstack import wsgi
from nova.api import validation
from nova import compute
import nova.conf
from nova.i18n import _
from nova.policies import fping as fping_policies
CONF = nova.conf.CONF
class FpingController(wsgi.Controller):
def __init__(self, network_api=None):
self.compute_api = compute.API()
self.last_call = {}
def check_fping(self):
if not os.access(CONF.api.fping_path, os.X_OK):
raise exc.HTTPServiceUnavailable(
explanation=_("fping utility is not found."))
@staticmethod
def fping(ips):
fping_ret = processutils.execute(CONF.api.fping_path, *ips,
check_exit_code=False)
if not fping_ret:
return set()
alive_ips = set()
for line in fping_ret[0].split("\n"):
ip = line.split(" ", 1)[0]
if "alive" in line:
alive_ips.add(ip)
return alive_ips
@staticmethod
def _get_instance_ips(context, instance):
ret = []
for network in common.get_networks_for_instance(
context, instance).values():
all_ips = itertools.chain(network["ips"], network["floating_ips"])
ret += [ip["address"] for ip in all_ips]
return ret
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
@validation.query_schema(schema.index_query)
@wsgi.expected_errors(503)
@wsgi.expected_errors(410)
def index(self, req):
context = req.environ["nova.context"]
search_opts = dict(deleted=False)
if "all_tenants" in req.GET:
context.can(fping_policies.POLICY_ROOT % 'all_tenants')
else:
context.can(fping_policies.BASE_POLICY_NAME)
if context.project_id:
search_opts["project_id"] = context.project_id
else:
search_opts["user_id"] = context.user_id
self.check_fping()
include = req.GET.get("include", None)
if include:
include = set(include.split(","))
exclude = set()
else:
include = None
exclude = req.GET.get("exclude", None)
if exclude:
exclude = set(exclude.split(","))
else:
exclude = set()
raise exc.HTTPGone()
instance_list = self.compute_api.get_all(
context, search_opts=search_opts)
ip_list = []
instance_ips = {}
instance_projects = {}
for instance in instance_list:
uuid = instance.uuid
if uuid in exclude or (include is not None and
uuid not in include):
continue
ips = [str(ip) for ip in self._get_instance_ips(context, instance)]
instance_ips[uuid] = ips
instance_projects[uuid] = instance.project_id
ip_list += ips
alive_ips = self.fping(ip_list)
res = []
for instance_uuid, ips in instance_ips.items():
res.append({
"id": instance_uuid,
"project_id": instance_projects[instance_uuid],
"alive": bool(set(ips) & alive_ips),
})
return {"servers": res}
@wsgi.Controller.api_version("2.1", MAX_PROXY_API_SUPPORT_VERSION)
@wsgi.expected_errors((404, 503))
@wsgi.expected_errors(410)
def show(self, req, id):
context = req.environ["nova.context"]
context.can(fping_policies.BASE_POLICY_NAME)
self.check_fping()
instance = common.get_instance(self.compute_api, context, id)
ips = [str(ip) for ip in self._get_instance_ips(context, instance)]
alive_ips = self.fping(ips)
return {
"server": {
"id": instance.uuid,
"project_id": instance.project_id,
"alive": bool(set(ips) & alive_ips),
}
}
raise exc.HTTPGone()

View File

@ -1,28 +0,0 @@
# Copyright 2017 NEC 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
index_query = {
'type': 'object',
'properties': {
'all_tenants': parameter_types.multi_params({'type': 'string'}),
'include': parameter_types.multi_params({'type': 'string'}),
'exclude': parameter_types.multi_params({'type': 'string'})
},
# NOTE(gmann): This is kept True to keep backward compatibility.
# As of now Schema validation stripped out the additional parameters and
# does not raise 400. In the future, we may block the additional parameters
# by bump in Microversion.
'additionalProperties': True
}

View File

@ -297,20 +297,6 @@ Possible values:
""")
]
fping_path_opts = [
cfg.StrOpt("fping_path",
default="/usr/sbin/fping",
deprecated_group="DEFAULT",
deprecated_for_removal=True,
deprecated_since="18.0.0",
deprecated_reason="""
This option only used in /os-fping API and the API itself was deprecated
at version 2.36 (Newton release), also, the API itself is based on nova-network
and nova-network is deprecated as well.
""",
help="The full path to the fping binary.")
]
os_network_opts = [
cfg.BoolOpt("use_neutron_default_nets",
default=False,
@ -353,7 +339,6 @@ API_OPTS = (auth_opts +
file_opts +
osapi_opts +
osapi_hide_opts +
fping_path_opts +
os_network_opts +
enable_inst_pw_opts)

View File

@ -46,7 +46,6 @@ from nova.policies import floating_ip_dns
from nova.policies import floating_ip_pools
from nova.policies import floating_ips
from nova.policies import floating_ips_bulk
from nova.policies import fping
from nova.policies import hide_server_addresses
from nova.policies import hosts
from nova.policies import hypervisors
@ -124,7 +123,6 @@ def list_rules():
floating_ip_pools.list_rules(),
floating_ips.list_rules(),
floating_ips_bulk.list_rules(),
fping.list_rules(),
hide_server_addresses.list_rules(),
hosts.list_rules(),
hypervisors.list_rules(),

View File

@ -1,62 +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-fping'
POLICY_ROOT = 'os_compute_api:os-fping:%s'
fping_policies = [
policy.DocumentedRuleDefault(
POLICY_ROOT % 'all_tenants',
base.RULE_ADMIN_API,
"""Pings instances for all projects and reports which instances
are alive.
os-fping API is deprecated as this works only with nova-network
which itself is deprecated.""",
[
{
'method': 'GET',
'path': '/os-fping?all_tenants=true'
}
]),
policy.DocumentedRuleDefault(
BASE_POLICY_NAME,
base.RULE_ADMIN_OR_OWNER,
"""Pings instances, particular instance and reports which instances
are alive.
os-fping API is deprecated as this works only with nova-network
which itself is deprecated.""",
[
{
'method': 'GET',
'path': '/os-fping'
},
{
'method': 'GET',
'path': '/os-fping/{instance_id}'
}
])
]
def list_rules():
return fping_policies

View File

@ -1,7 +0,0 @@
{
"server": {
"alive": false,
"id": "%(uuid)s",
"project_id": "6f70656e737461636b20342065766572"
}
}

View File

@ -1,9 +0,0 @@
{
"servers": [
{
"alive": false,
"id": "%(uuid)s",
"project_id": "6f70656e737461636b20342065766572"
}
]
}

View File

@ -13,30 +13,22 @@
# License for the specific language governing permissions and limitations
# under the License.
from nova.tests.functional.api_sample_tests import test_servers
from nova.tests.unit.api.openstack.compute import test_fping
from oslo_utils import uuidutils
from nova.tests.functional.api import client as api_client
from nova.tests.functional import api_samples_test_base
class FpingSampleJsonTests(test_servers.ServersSampleBase):
sample_dir = "os-fping"
def setUp(self):
super(FpingSampleJsonTests, self).setUp()
def fake_check_fping(self):
pass
self.stub_out("oslo_concurrency.processutils.execute",
test_fping.execute)
self.stub_out("nova.api.openstack.compute.fping."
"FpingController.check_fping",
fake_check_fping)
class FpingSampleJsonTests(api_samples_test_base.ApiSampleTestBase):
api_major_version = 'v2'
def test_get_fping(self):
self._post_server()
response = self._do_get('os-fping')
self._verify_response('fping-get-resp', {}, response, 200)
ex = self.assertRaises(api_client.OpenStackApiException,
self.api.api_get, '/os-fping')
self.assertEqual(410, ex.response.status_code)
def test_get_fping_details(self):
uuid = self._post_server()
response = self._do_get('os-fping/%s' % (uuid))
self._verify_response('fping-get-details-resp', {}, response, 200)
ex = self.assertRaises(api_client.OpenStackApiException,
self.api.api_get, '/os-fping/%s' %
uuidutils.generate_uuid())
self.assertEqual(410, ex.response.status_code)

View File

@ -1,186 +0,0 @@
# Copyright 2011 Grid Dynamics
# Copyright 2011 OpenStack Foundation
# 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.
import mock
import webob
from nova.api.openstack.compute import fping as fping_v21
from nova import exception
from nova import test
from nova.tests.unit.api.openstack import fakes
FAKE_UUID = fakes.FAKE_UUID
def execute(*cmd, **args):
return "".join(["%s is alive" % ip for ip in cmd[1:]])
class FpingTestV21(test.TestCase):
controller_cls = fping_v21.FpingController
def setUp(self):
super(FpingTestV21, self).setUp()
self.flags(use_ipv6=False)
return_server = fakes.fake_instance_get()
return_servers = fakes.fake_instance_get_all_by_filters()
self.stub_out("nova.compute.instance_list.get_instances_sorted",
return_servers)
self.stub_out("nova.db.instance_get_by_uuid",
return_server)
self.stub_out('oslo_concurrency.processutils.execute',
execute)
self.stub_out("nova.api.openstack.compute.fping.FpingController."
"check_fping",
lambda self: None)
self.controller = self.controller_cls()
def _get_url(self):
return "/v2/1234"
def test_fping_index(self):
req = fakes.HTTPRequest.blank(self._get_url() + "/os-fping")
res_dict = self.controller.index(req)
self.assertIn("servers", res_dict)
for srv in res_dict["servers"]:
for key in "project_id", "id", "alive":
self.assertIn(key, srv)
def test_fping_index_policy(self):
req = fakes.HTTPRequest.blank(self._get_url() +
"os-fping?all_tenants=1")
self.assertRaises(exception.Forbidden, self.controller.index, req)
req = fakes.HTTPRequest.blank(self._get_url() +
"/os-fping?all_tenants=1")
req.environ["nova.context"].is_admin = True
res_dict = self.controller.index(req)
self.assertIn("servers", res_dict)
def test_fping_index_include(self):
req = fakes.HTTPRequest.blank(self._get_url() + "/os-fping")
res_dict = self.controller.index(req)
ids = [srv["id"] for srv in res_dict["servers"]]
req = fakes.HTTPRequest.blank(self._get_url() +
"/os-fping?include=%s" % ids[0])
res_dict = self.controller.index(req)
self.assertEqual(len(res_dict["servers"]), 1)
self.assertEqual(res_dict["servers"][0]["id"], ids[0])
def test_fping_index_exclude(self):
req = fakes.HTTPRequest.blank(self._get_url() + "/os-fping")
res_dict = self.controller.index(req)
ids = [srv["id"] for srv in res_dict["servers"]]
req = fakes.HTTPRequest.blank(self._get_url() +
"/os-fping?exclude=%s" %
",".join(ids[1:]))
res_dict = self.controller.index(req)
self.assertEqual(len(res_dict["servers"]), 1)
self.assertEqual(res_dict["servers"][0]["id"], ids[0])
def test_fping_index_with_negative_int_filters(self):
req = fakes.HTTPRequest.blank(self._get_url() +
'/os-fping?all_tenants=-1&include=-21&exclude=-3',
use_admin_context=True)
self.controller.index(req)
def test_fping_index_with_string_filter(self):
req = fakes.HTTPRequest.blank(self._get_url() +
'/os-fping?all_tenants=abc&include=abc1&exclude=abc2',
use_admin_context=True)
self.controller.index(req)
def test_fping_index_duplicate_query_parameters_validation(self):
params = {
'all_tenants': 1,
'include': 'UUID1',
'exclude': 'UUID2'
}
for param, value in params.items():
req = fakes.HTTPRequest.blank(self._get_url()
+ '/os-fping?%s=%s&%s=%s' %
(param, value, param, value),
use_admin_context=True)
self.controller.index(req)
def test_fping_index_pagination_with_additional_filter(self):
req = fakes.HTTPRequest.blank(self._get_url() +
'/os-fping?all_tenants=1&include=UUID1&additional=3',
use_admin_context=True)
self.controller.index(req)
def test_fping_show(self):
req = fakes.HTTPRequest.blank(self._get_url() +
"os-fping/%s" % FAKE_UUID)
res_dict = self.controller.show(req, FAKE_UUID)
self.assertIn("server", res_dict)
srv = res_dict["server"]
for key in "project_id", "id", "alive":
self.assertIn(key, srv)
@mock.patch('nova.db.instance_get_by_uuid')
def test_fping_show_with_not_found(self, mock_get_instance):
mock_get_instance.side_effect = exception.InstanceNotFound(
instance_id='')
req = fakes.HTTPRequest.blank(self._get_url() +
"os-fping/%s" % FAKE_UUID)
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.show, req, FAKE_UUID)
class FpingPolicyEnforcementV21(test.NoDBTestCase):
def setUp(self):
super(FpingPolicyEnforcementV21, self).setUp()
self.controller = fping_v21.FpingController()
self.req = fakes.HTTPRequest.blank('')
def common_policy_check(self, rule, func, *arg, **kwarg):
self.policy.set_rules(rule)
exc = self.assertRaises(
exception.PolicyNotAuthorized, func, *arg, **kwarg)
self.assertEqual(
"Policy doesn't allow %s to be performed." %
rule.popitem()[0], exc.format_message())
def test_list_policy_failed(self):
rule = {"os_compute_api:os-fping": "project:non_fake"}
self.common_policy_check(rule, self.controller.index, self.req)
self.req.GET.update({"all_tenants": "True"})
rule = {"os_compute_api:os-fping:all_tenants":
"project:non_fake"}
self.common_policy_check(rule, self.controller.index, self.req)
def test_show_policy_failed(self):
rule = {"os_compute_api:os-fping": "project:non_fake"}
self.common_policy_check(
rule, self.controller.show, self.req, FAKE_UUID)
class FpingTestDeprecation(test.NoDBTestCase):
def setUp(self):
super(FpingTestDeprecation, self).setUp()
self.controller = fping_v21.FpingController()
self.req = fakes.HTTPRequest.blank('', version='2.36')
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.index, self.req)

View File

@ -53,7 +53,6 @@ policy_data = """
"os_compute_api:os-floating-ip-pools": "",
"os_compute_api:os-floating-ips": "",
"os_compute_api:os-floating-ips-bulk": "",
"os_compute_api:os-fping": "",
"os_compute_api:os-instance-actions": "",
"os_compute_api:os-instance-usage-audit-log": "",

View File

@ -315,7 +315,6 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
"os_compute_api:os-floating-ips-bulk",
"os_compute_api:os-floating-ip-dns:domain:delete",
"os_compute_api:os-floating-ip-dns:domain:update",
"os_compute_api:os-fping:all_tenants",
"os_compute_api:os-hosts",
"os_compute_api:os-hypervisors",
"os_compute_api:os-instance-actions:events",
@ -411,7 +410,6 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
"os_compute_api:os-floating-ip-dns",
"os_compute_api:os-floating-ip-pools",
"os_compute_api:os-floating-ips",
"os_compute_api:os-fping",
"os_compute_api:image-size",
"os_compute_api:os-instance-actions",
"os_compute_api:os-keypairs",

View File

@ -0,0 +1,14 @@
---
upgrade:
- |
The *nova-network* service has been deprecated since the 14.0.0 Newton
release and now the following *nova-network* specific REST APIs have been
removed along with their related policy rules. Calling these APIs will now
result in a ``410 HTTPGone`` error response.
* ``GET /os-fping``
* ``GET /os-fping/{server_id}``
In addition, the following configuration options have been removed.
* ``[api]/fping_path``