Merge "Remove support for /os-fping REST API"

This commit is contained in:
Zuul 2018-06-06 21:00:58 +00:00 committed by Gerrit Code Review
commit 3a852179e2
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

@ -309,20 +309,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,
@ -365,7 +351,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``