Merge "api: Remove 'os-agents' API"

This commit is contained in:
Zuul 2020-11-14 10:06:43 +00:00 committed by Gerrit Code Review
commit eb6ce97544
12 changed files with 51 additions and 1072 deletions

View File

@ -11,6 +11,12 @@ hypervisor-specific extension is currently only for the Xen driver. Use of
guest agents is possible only if the underlying service provider uses
the Xen driver.
.. warning::
These APIs only works with the Xen virt driver, which was deprecated in the
20.0.0 (Train) release.
They were removed in the 22.0.0 (Victoria) release.
List Agent Builds
=================
@ -20,7 +26,7 @@ Lists agent builds.
Normal response codes: 200
Error response codes: unauthorized(401), forbidden(403)
Error response codes: unauthorized(401), forbidden(403), gone(410)
Request
-------
@ -58,7 +64,8 @@ Creates an agent build.
Normal response codes: 200
Error response codes: badRequest(400), unauthorized(401), forbidden(403), conflict(409)
Error response codes: badRequest(400), unauthorized(401), forbidden(403),
conflict(409), gone(410)
Request
-------
@ -106,7 +113,8 @@ Updates an agent build.
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
-------
@ -150,7 +158,8 @@ Deletes an existing agent build.
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
-------

View File

@ -13,153 +13,28 @@
# under the License.
import webob.exc
from webob import exc
from nova.api.openstack.compute.schemas import agents as schema
from nova.api.openstack import wsgi
from nova.api import validation
from nova import exception
from nova import objects
from nova.policies import agents as agents_policies
from nova import utils
class AgentController(wsgi.Controller):
"""The agent is talking about guest agent.The host can use this for
things like accessing files on the disk, configuring networking,
or running other applications/scripts in the guest while it is
running. Typically this uses some hypervisor-specific transport
to avoid being dependent on a working network configuration.
Xen, VMware, and VirtualBox have guest agents,although the Xen
driver is the only one with an implementation for managing them
in openstack. KVM doesn't really have a concept of a guest agent
(although one could be written).
"""(Removed) Controller for agent resources.
You can find the design of agent update in this link:
http://wiki.openstack.org/AgentUpdate
In this design We need update agent in guest from host, so we need
some interfaces to update the agent info in host.
You can find more information about the design of the GuestAgent in
the following link:
http://wiki.openstack.org/GuestAgent
http://wiki.openstack.org/GuestAgentXenStoreCommunication
This was removed during the Victoria release along with the XenAPI driver.
"""
@validation.query_schema(schema.index_query_275, '2.75')
@validation.query_schema(schema.index_query, '2.0', '2.74')
@wsgi.expected_errors(())
@wsgi.expected_errors(410)
def index(self, req):
"""Return a list of all agent builds. Filter by hypervisor."""
context = req.environ['nova.context']
context.can(agents_policies.BASE_POLICY_NAME % 'list', target={})
hypervisor = None
agents = []
if 'hypervisor' in req.GET:
hypervisor = req.GET['hypervisor']
raise exc.HTTPGone()
builds = objects.AgentList.get_all(context, hypervisor=hypervisor)
for agent_build in builds:
agents.append({'hypervisor': agent_build.hypervisor,
'os': agent_build.os,
'architecture': agent_build.architecture,
'version': agent_build.version,
'md5hash': agent_build.md5hash,
'agent_id': agent_build.id,
'url': agent_build.url})
return {'agents': agents}
@wsgi.expected_errors((400, 404))
@validation.schema(schema.update)
@wsgi.expected_errors(410)
def update(self, req, id, body):
"""Update an existing agent build."""
context = req.environ['nova.context']
context.can(agents_policies.BASE_POLICY_NAME % 'update', target={})
raise exc.HTTPGone()
# TODO(oomichi): This parameter name "para" is different from the ones
# of the other APIs. Most other names are resource names like "server"
# etc. This name should be changed to "agent" for consistent naming
# with v2.1+microversions.
para = body['para']
url = para['url']
md5hash = para['md5hash']
version = para['version']
try:
utils.validate_integer(id, 'id')
except exception.InvalidInput as exc:
raise webob.exc.HTTPBadRequest(explanation=exc.format_message())
agent = objects.Agent(context=context, id=id)
agent.obj_reset_changes()
agent.version = version
agent.url = url
agent.md5hash = md5hash
try:
agent.save()
except exception.AgentBuildNotFound as ex:
raise webob.exc.HTTPNotFound(explanation=ex.format_message())
# TODO(alex_xu): The agent_id should be integer that consistent with
# create/index actions. But parameter 'id' is string type that parsed
# from url. This is a bug, but because back-compatibility, it can't be
# fixed for v2 API. This will be fixed in v2.1 API by Microversions in
# the future. lp bug #1333494
return {"agent": {'agent_id': id, 'version': version,
'url': url, 'md5hash': md5hash}}
# TODO(oomichi): Here should be 204(No Content) instead of 200 by v2.1
# +microversions because the resource agent has been deleted completely
# when returning a response.
@wsgi.expected_errors((400, 404))
@wsgi.response(200)
@wsgi.expected_errors(410)
def delete(self, req, id):
"""Deletes an existing agent build."""
context = req.environ['nova.context']
context.can(agents_policies.BASE_POLICY_NAME % 'delete', target={})
raise exc.HTTPGone()
try:
utils.validate_integer(id, 'id')
except exception.InvalidInput as exc:
raise webob.exc.HTTPBadRequest(explanation=exc.format_message())
try:
agent = objects.Agent(context=context, id=id)
agent.destroy()
except exception.AgentBuildNotFound as ex:
raise webob.exc.HTTPNotFound(explanation=ex.format_message())
# TODO(oomichi): Here should be 201(Created) instead of 200 by v2.1
# +microversions because the creation of a resource agent finishes
# when returning a response.
@wsgi.expected_errors(409)
@wsgi.response(200)
@validation.schema(schema.create)
@wsgi.expected_errors(410)
def create(self, req, body):
"""Creates a new agent build."""
context = req.environ['nova.context']
context.can(agents_policies.BASE_POLICY_NAME % 'create', target={})
agent = body['agent']
hypervisor = agent['hypervisor']
os = agent['os']
architecture = agent['architecture']
version = agent['version']
url = agent['url']
md5hash = agent['md5hash']
agent_obj = objects.Agent(context=context)
agent_obj.hypervisor = hypervisor
agent_obj.os = os
agent_obj.architecture = architecture
agent_obj.version = version
agent_obj.url = url
agent_obj.md5hash = md5hash
try:
agent_obj.create()
agent['agent_id'] = agent_obj.id
except exception.AgentBuildExists as ex:
raise webob.exc.HTTPConflict(explanation=ex.format_message())
return {'agent': agent}
raise exc.HTTPGone()

View File

@ -1,100 +0,0 @@
# Copyright 2013 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.
import copy
from nova.api.validation import parameter_types
create = {
'type': 'object',
'properties': {
'agent': {
'type': 'object',
'properties': {
'hypervisor': {
'type': 'string', 'minLength': 0, 'maxLength': 255,
'pattern': '^[a-zA-Z0-9-._ ]*$'
},
'os': {
'type': 'string', 'minLength': 0, 'maxLength': 255,
'pattern': '^[a-zA-Z0-9-._ ]*$'
},
'architecture': {
'type': 'string', 'minLength': 0, 'maxLength': 255,
'pattern': '^[a-zA-Z0-9-._ ]*$'
},
'version': {
'type': 'string', 'minLength': 0, 'maxLength': 255,
'pattern': '^[a-zA-Z0-9-._ ]*$'
},
'url': {
'type': 'string', 'minLength': 0, 'maxLength': 255,
'format': 'uri'
},
'md5hash': {
'type': 'string', 'minLength': 0, 'maxLength': 255,
'pattern': '^[a-fA-F0-9]*$'
},
},
'required': ['hypervisor', 'os', 'architecture', 'version',
'url', 'md5hash'],
'additionalProperties': False,
},
},
'required': ['agent'],
'additionalProperties': False,
}
update = {
'type': 'object',
'properties': {
'para': {
'type': 'object',
'properties': {
'version': {
'type': 'string', 'minLength': 0, 'maxLength': 255,
'pattern': '^[a-zA-Z0-9-._ ]*$'
},
'url': {
'type': 'string', 'minLength': 0, 'maxLength': 255,
'format': 'uri'
},
'md5hash': {
'type': 'string', 'minLength': 0, 'maxLength': 255,
'pattern': '^[a-fA-F0-9]*$'
},
},
'required': ['version', 'url', 'md5hash'],
'additionalProperties': False,
},
},
'required': ['para'],
'additionalProperties': False,
}
index_query = {
'type': 'object',
'properties': {
'hypervisor': parameter_types.common_query_param
},
# 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 microversion 2.75, we have blocked the additional
# parameters.
'additionalProperties': True
}
index_query_275 = copy.deepcopy(index_query)
index_query_275['additionalProperties'] = False

View File

@ -19,6 +19,8 @@ from nova.objects import base
from nova.objects import fields
# TODO(stephenfin): Remove this object; it's not necessary since the removal of
# XenAPI
@base.NovaObjectRegistry.register
class Agent(base.NovaPersistentObject, base.NovaObject):
VERSION = '1.0'
@ -69,6 +71,8 @@ class Agent(base.NovaPersistentObject, base.NovaObject):
self.obj_reset_changes()
# TODO(stephenfin): Remove this object; it's not necessary since the removal of
# XenAPI
@base.NovaObjectRegistry.register
class AgentList(base.ObjectListBase, base.NovaObject):
VERSION = '1.0'

View File

@ -15,7 +15,6 @@ import itertools
from nova.policies import admin_actions
from nova.policies import admin_password
from nova.policies import agents
from nova.policies import aggregates
from nova.policies import assisted_volume_snapshots
from nova.policies import attach_interfaces
@ -75,7 +74,6 @@ def list_rules():
base.list_rules(),
admin_actions.list_rules(),
admin_password.list_rules(),
agents.list_rules(),
aggregates.list_rules(),
assisted_volume_snapshots.list_rules(),
attach_interfaces.list_rules(),

View File

@ -1,108 +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-agents:%s'
DEPRECATED_AGENTS_POLICY = policy.DeprecatedRule(
'os_compute_api:os-agents',
base.RULE_ADMIN_API,
)
DEPRECATED_REASON = """
Nova API policies are introducing new default roles with scope_type
capabilities. Old policies are deprecated and silently going to be ignored
in nova 23.0.0 release.
"""
agents_policies = [
policy.DocumentedRuleDefault(
name=BASE_POLICY_NAME % 'list',
check_str=base.SYSTEM_READER,
description="""List guest agent builds
This is XenAPI driver specific.
It is used to force the upgrade of the XenAPI guest agent on instance boot.
""",
operations=[
{
'path': '/os-agents',
'method': 'GET'
},
],
scope_types=['system'],
deprecated_rule=DEPRECATED_AGENTS_POLICY,
deprecated_reason=DEPRECATED_REASON,
deprecated_since='21.0.0'),
policy.DocumentedRuleDefault(
name=BASE_POLICY_NAME % 'create',
check_str=base.SYSTEM_ADMIN,
description="""Create guest agent builds
This is XenAPI driver specific.
It is used to force the upgrade of the XenAPI guest agent on instance boot.
""",
operations=[
{
'path': '/os-agents',
'method': 'POST'
},
],
scope_types=['system'],
deprecated_rule=DEPRECATED_AGENTS_POLICY,
deprecated_reason=DEPRECATED_REASON,
deprecated_since='21.0.0'),
policy.DocumentedRuleDefault(
name=BASE_POLICY_NAME % 'update',
check_str=base.SYSTEM_ADMIN,
description="""Update guest agent builds
This is XenAPI driver specific.
It is used to force the upgrade of the XenAPI guest agent on instance boot.
""",
operations=[
{
'path': '/os-agents/{agent_build_id}',
'method': 'PUT'
},
],
scope_types=['system'],
deprecated_rule=DEPRECATED_AGENTS_POLICY,
deprecated_reason=DEPRECATED_REASON,
deprecated_since='21.0.0'),
policy.DocumentedRuleDefault(
name=BASE_POLICY_NAME % 'delete',
check_str=base.SYSTEM_ADMIN,
description="""Delete guest agent builds
This is XenAPI driver specific.
It is used to force the upgrade of the XenAPI guest agent on instance boot.
""",
operations=[
{
'path': '/os-agents/{agent_build_id}',
'method': 'DELETE'
}
],
scope_types=['system'],
deprecated_rule=DEPRECATED_AGENTS_POLICY,
deprecated_reason=DEPRECATED_REASON,
deprecated_since='21.0.0'),
]
def list_rules():
return agents_policies

View File

@ -13,86 +13,23 @@
# License for the specific language governing permissions and limitations
# under the License.
from nova.db.sqlalchemy import models
from nova.tests.functional.api_sample_tests import api_sample_base
class AgentsJsonTest(api_sample_base.ApiSampleTestBaseV21):
ADMIN_API = True
sample_dir = "os-agents"
def setUp(self):
super(AgentsJsonTest, self).setUp()
fake_agents_list = [{'url': 'http://example.com/path/to/resource',
'hypervisor': 'xen',
'architecture': 'x86',
'os': 'os',
'version': '8.0',
'md5hash': 'add6bb58e139be103324d04d82d8f545',
'id': 1}]
def fake_agent_build_create(context, values):
values['id'] = 1
agent_build_ref = models.AgentBuild()
agent_build_ref.update(values)
return agent_build_ref
def fake_agent_build_get_all(context, hypervisor):
agent_build_all = []
for agent in fake_agents_list:
if hypervisor and hypervisor != agent['hypervisor']:
continue
agent_build_ref = models.AgentBuild()
agent_build_ref.update(agent)
agent_build_all.append(agent_build_ref)
return agent_build_all
def fake_agent_build_update(context, agent_build_id, values):
pass
def fake_agent_build_destroy(context, agent_update_id):
pass
self.stub_out("nova.db.api.agent_build_create",
fake_agent_build_create)
self.stub_out("nova.db.api.agent_build_get_all",
fake_agent_build_get_all)
self.stub_out("nova.db.api.agent_build_update",
fake_agent_build_update)
self.stub_out("nova.db.api.agent_build_destroy",
fake_agent_build_destroy)
def test_agent_create(self):
# Creates a new agent build.
project = {'url': 'http://example.com/path/to/resource',
'hypervisor': 'xen',
'architecture': 'x86',
'os': 'os',
'version': '8.0',
'md5hash': 'add6bb58e139be103324d04d82d8f545'
}
response = self._do_post('os-agents', 'agent-post-req',
project)
self._verify_response('agent-post-resp', project, response, 200)
self.api.api_post('/os-agents', {}, check_response_status=[410])
def test_agent_list(self):
# Return a list of all agent builds.
response = self._do_get('os-agents')
self._verify_response('agents-get-resp', {}, response, 200)
self.api.api_get('/os-agents', check_response_status=[410])
def test_agent_update(self):
# Update an existing agent build.
agent_id = 1
subs = {'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545'}
response = self._do_put('os-agents/%s' % agent_id,
'agent-update-put-req', subs)
self._verify_response('agent-update-put-resp', subs, response, 200)
self.api.api_put('/os-agents/1', {}, check_response_status=[410])
def test_agent_delete(self):
# Deletes an existing agent build.
agent_id = 1
response = self._do_delete('os-agents/%s' % agent_id)
self.assertEqual(200, response.status_code)
self.api.api_delete('/os-agents/1', check_response_status=[410])

View File

@ -1,431 +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 mock
import webob.exc
from nova.api.openstack.compute import agents as agents_v21
from nova.db import api as db
from nova.db.sqlalchemy import models
from nova import exception
from nova import test
from nova.tests.unit.api.openstack import fakes
fake_agents_list = [{'hypervisor': 'kvm', 'os': 'win',
'architecture': 'x86',
'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545',
'id': 1},
{'hypervisor': 'kvm', 'os': 'linux',
'architecture': 'x86',
'version': '16.0',
'url': 'http://example.com/path/to/resource1',
'md5hash': 'add6bb58e139be103324d04d82d8f546',
'id': 2},
{'hypervisor': 'xen', 'os': 'linux',
'architecture': 'x86',
'version': '16.0',
'url': 'http://example.com/path/to/resource2',
'md5hash': 'add6bb58e139be103324d04d82d8f547',
'id': 3},
{'hypervisor': 'xen', 'os': 'win',
'architecture': 'power',
'version': '7.0',
'url': 'http://example.com/path/to/resource3',
'md5hash': 'add6bb58e139be103324d04d82d8f548',
'id': 4},
]
def fake_agent_build_get_all(context, hypervisor):
agent_build_all = []
for agent in fake_agents_list:
if hypervisor and hypervisor != agent['hypervisor']:
continue
agent_build_ref = models.AgentBuild()
agent_build_ref.update(agent)
agent_build_all.append(agent_build_ref)
return agent_build_all
def fake_agent_build_update(context, agent_build_id, values):
pass
def fake_agent_build_destroy(context, agent_update_id):
pass
def fake_agent_build_create(context, values):
values['id'] = 1
agent_build_ref = models.AgentBuild()
agent_build_ref.update(values)
return agent_build_ref
class AgentsTestV21(test.NoDBTestCase):
controller = agents_v21.AgentController()
validation_error = exception.ValidationError
microversion = '2.1'
def setUp(self):
super(AgentsTestV21, self).setUp()
self.stub_out("nova.db.api.agent_build_get_all",
fake_agent_build_get_all)
self.stub_out("nova.db.api.agent_build_update",
fake_agent_build_update)
self.stub_out("nova.db.api.agent_build_destroy",
fake_agent_build_destroy)
self.stub_out("nova.db.api.agent_build_create",
fake_agent_build_create)
self.req = self._get_http_request()
def _get_http_request(self):
return fakes.HTTPRequest.blank('', version=self.microversion)
def test_agents_create(self):
body = {'agent': {'hypervisor': 'kvm',
'os': 'win',
'architecture': 'x86',
'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
response = {'agent': {'hypervisor': 'kvm',
'os': 'win',
'architecture': 'x86',
'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545',
'agent_id': 1}}
res_dict = self.controller.create(self.req, body=body)
self.assertEqual(res_dict, response)
def _test_agents_create_key_error(self, key):
body = {'agent': {'hypervisor': 'kvm',
'os': 'win',
'architecture': 'x86',
'version': '7.0',
'url': 'xxx://xxxx/xxx/xxx',
'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
body['agent'].pop(key)
self.assertRaises(self.validation_error,
self.controller.create, self.req, body=body)
def test_agents_create_without_hypervisor(self):
self._test_agents_create_key_error('hypervisor')
def test_agents_create_without_os(self):
self._test_agents_create_key_error('os')
def test_agents_create_without_architecture(self):
self._test_agents_create_key_error('architecture')
def test_agents_create_without_version(self):
self._test_agents_create_key_error('version')
def test_agents_create_without_url(self):
self._test_agents_create_key_error('url')
def test_agents_create_without_md5hash(self):
self._test_agents_create_key_error('md5hash')
def test_agents_create_with_wrong_type(self):
body = {'agent': None}
self.assertRaises(self.validation_error,
self.controller.create, self.req, body=body)
def test_agents_create_with_empty_type(self):
body = {}
self.assertRaises(self.validation_error,
self.controller.create, self.req, body=body)
def test_agents_create_with_existed_agent(self):
def fake_agent_build_create_with_exited_agent(context, values):
raise exception.AgentBuildExists(**values)
self.stub_out('nova.db.api.agent_build_create',
fake_agent_build_create_with_exited_agent)
body = {'agent': {'hypervisor': 'kvm',
'os': 'win',
'architecture': 'x86',
'version': '7.0',
'url': 'xxx://xxxx/xxx/xxx',
'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
self.assertRaises(webob.exc.HTTPConflict, self.controller.create,
self.req, body=body)
def _test_agents_create_with_invalid_length(self, key):
body = {'agent': {'hypervisor': 'kvm',
'os': 'win',
'architecture': 'x86',
'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
body['agent'][key] = 'x' * 256
self.assertRaises(self.validation_error,
self.controller.create, self.req, body=body)
def test_agents_create_with_invalid_length_hypervisor(self):
self._test_agents_create_with_invalid_length('hypervisor')
def test_agents_create_with_invalid_length_os(self):
self._test_agents_create_with_invalid_length('os')
def test_agents_create_with_invalid_length_architecture(self):
self._test_agents_create_with_invalid_length('architecture')
def test_agents_create_with_invalid_length_version(self):
self._test_agents_create_with_invalid_length('version')
def test_agents_create_with_invalid_length_url(self):
self._test_agents_create_with_invalid_length('url')
def test_agents_create_with_invalid_length_md5hash(self):
self._test_agents_create_with_invalid_length('md5hash')
def test_agents_delete(self):
self.controller.delete(self.req, 1)
def test_agents_delete_with_id_not_found(self):
with mock.patch.object(db, 'agent_build_destroy',
side_effect=exception.AgentBuildNotFound(id=1)):
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.delete, self.req, 1)
def test_agents_delete_string_id(self):
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.delete, self.req, 'string_id')
def _test_agents_list(self, query_string=None):
req = fakes.HTTPRequest.blank('', use_admin_context=True,
query_string=query_string,
version=self.microversion)
res_dict = self.controller.index(req)
agents_list = [{'hypervisor': 'kvm', 'os': 'win',
'architecture': 'x86',
'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545',
'agent_id': 1},
{'hypervisor': 'kvm', 'os': 'linux',
'architecture': 'x86',
'version': '16.0',
'url': 'http://example.com/path/to/resource1',
'md5hash': 'add6bb58e139be103324d04d82d8f546',
'agent_id': 2},
{'hypervisor': 'xen', 'os': 'linux',
'architecture': 'x86',
'version': '16.0',
'url': 'http://example.com/path/to/resource2',
'md5hash': 'add6bb58e139be103324d04d82d8f547',
'agent_id': 3},
{'hypervisor': 'xen', 'os': 'win',
'architecture': 'power',
'version': '7.0',
'url': 'http://example.com/path/to/resource3',
'md5hash': 'add6bb58e139be103324d04d82d8f548',
'agent_id': 4},
]
self.assertEqual(res_dict, {'agents': agents_list})
def test_agents_list(self):
self._test_agents_list()
def test_agents_list_with_hypervisor(self):
req = fakes.HTTPRequest.blank('', use_admin_context=True,
query_string='hypervisor=kvm',
version=self.microversion)
res_dict = self.controller.index(req)
response = [{'hypervisor': 'kvm', 'os': 'win',
'architecture': 'x86',
'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545',
'agent_id': 1},
{'hypervisor': 'kvm', 'os': 'linux',
'architecture': 'x86',
'version': '16.0',
'url': 'http://example.com/path/to/resource1',
'md5hash': 'add6bb58e139be103324d04d82d8f546',
'agent_id': 2},
]
self.assertEqual(res_dict, {'agents': response})
def test_agents_list_with_multi_hypervisor_filter(self):
query_string = 'hypervisor=xen&hypervisor=kvm'
req = fakes.HTTPRequest.blank('', use_admin_context=True,
query_string=query_string,
version=self.microversion)
res_dict = self.controller.index(req)
response = [{'hypervisor': 'kvm', 'os': 'win',
'architecture': 'x86',
'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545',
'agent_id': 1},
{'hypervisor': 'kvm', 'os': 'linux',
'architecture': 'x86',
'version': '16.0',
'url': 'http://example.com/path/to/resource1',
'md5hash': 'add6bb58e139be103324d04d82d8f546',
'agent_id': 2},
]
self.assertEqual(res_dict, {'agents': response})
def test_agents_list_query_allow_negative_int_as_string(self):
req = fakes.HTTPRequest.blank('', use_admin_context=True,
query_string='hypervisor=-1',
version=self.microversion)
res_dict = self.controller.index(req)
self.assertEqual(res_dict, {'agents': []})
def test_agents_list_query_allow_int_as_string(self):
req = fakes.HTTPRequest.blank('', use_admin_context=True,
query_string='hypervisor=1',
version=self.microversion)
res_dict = self.controller.index(req)
self.assertEqual(res_dict, {'agents': []})
def test_agents_list_with_unknown_filter(self):
query_string = 'unknown_filter=abc'
self._test_agents_list(query_string=query_string)
def test_agents_list_with_hypervisor_and_additional_filter(self):
req = fakes.HTTPRequest.blank(
'', use_admin_context=True,
query_string='hypervisor=kvm&additional_filter=abc',
version=self.microversion)
res_dict = self.controller.index(req)
response = [{'hypervisor': 'kvm', 'os': 'win',
'architecture': 'x86',
'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545',
'agent_id': 1},
{'hypervisor': 'kvm', 'os': 'linux',
'architecture': 'x86',
'version': '16.0',
'url': 'http://example.com/path/to/resource1',
'md5hash': 'add6bb58e139be103324d04d82d8f546',
'agent_id': 2},
]
self.assertEqual(res_dict, {'agents': response})
def test_agents_update(self):
body = {'para': {'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
response = {'agent': {'agent_id': 1,
'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
res_dict = self.controller.update(self.req, 1, body=body)
self.assertEqual(res_dict, response)
def _test_agents_update_key_error(self, key):
body = {'para': {'version': '7.0',
'url': 'xxx://xxxx/xxx/xxx',
'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
body['para'].pop(key)
self.assertRaises(self.validation_error,
self.controller.update, self.req, 1, body=body)
def test_agents_update_without_version(self):
self._test_agents_update_key_error('version')
def test_agents_update_without_url(self):
self._test_agents_update_key_error('url')
def test_agents_update_without_md5hash(self):
self._test_agents_update_key_error('md5hash')
def test_agents_update_with_wrong_type(self):
body = {'agent': None}
self.assertRaises(self.validation_error,
self.controller.update, self.req, 1, body=body)
def test_agents_update_with_empty(self):
body = {}
self.assertRaises(self.validation_error,
self.controller.update, self.req, 1, body=body)
def test_agents_update_value_error(self):
body = {'para': {'version': '7.0',
'url': 1111,
'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
self.assertRaises(self.validation_error,
self.controller.update, self.req, 1, body=body)
def test_agents_update_with_string_id(self):
body = {'para': {'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, self.req,
'string_id', body=body)
def _test_agents_update_with_invalid_length(self, key):
body = {'para': {'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
body['para'][key] = 'x' * 256
self.assertRaises(self.validation_error,
self.controller.update, self.req, 1, body=body)
def test_agents_update_with_invalid_length_version(self):
self._test_agents_update_with_invalid_length('version')
def test_agents_update_with_invalid_length_url(self):
self._test_agents_update_with_invalid_length('url')
def test_agents_update_with_invalid_length_md5hash(self):
self._test_agents_update_with_invalid_length('md5hash')
def test_agents_update_with_id_not_found(self):
with mock.patch.object(db, 'agent_build_update',
side_effect=exception.AgentBuildNotFound(id=1)):
body = {'para': {'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.update, self.req, 1, body=body)
class AgentsTestV275(AgentsTestV21):
microversion = '2.75'
def test_agents_list_additional_filter_old_version(self):
req = fakes.HTTPRequest.blank(
'', use_admin_context=True,
query_string='additional_filter=abc',
version='2.74')
self.controller.index(req)
def test_agents_list_with_unknown_filter(self):
req = fakes.HTTPRequest.blank(
'', use_admin_context=True,
query_string='unknown_filter=abc',
version=self.microversion)
self.assertRaises(exception.ValidationError,
self.controller.index, req)
def test_agents_list_with_hypervisor_and_additional_filter(self):
req = fakes.HTTPRequest.blank(
'', use_admin_context=True,
query_string='hypervisor=kvm&additional_filter=abc',
version=self.microversion)
self.assertRaises(exception.ValidationError,
self.controller.index, req)

View File

@ -54,10 +54,6 @@ policy_data = """
"os_compute_api:os-admin-actions:reset_network": "",
"os_compute_api:os-admin-actions:reset_state": "",
"os_compute_api:os-admin-password": "",
"os_compute_api:os-agents:list": "",
"os_compute_api:os-agents:create": "",
"os_compute_api:os-agents:update": "",
"os_compute_api:os-agents:delete": "",
"os_compute_api:os-aggregates:set_metadata": "",
"os_compute_api:os-aggregates:remove_host": "",
"os_compute_api:os-aggregates:add_host": "",

View File

@ -1,212 +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.
import mock
from nova.api.openstack.compute import agents
from nova.db.sqlalchemy import models
from nova import exception
from nova.policies import base as base_policy
from nova.tests.unit.api.openstack import fakes
from nova.tests.unit.policies import base
from nova.tests.unit import policy_fixture
class AgentsPolicyTest(base.BasePolicyTest):
"""Test os-agents APIs policies with all possible context.
This class defines the set of context with different roles
which are allowed and not allowed to pass the policy checks.
With those set of context, it will call the API operation and
verify the expected behaviour.
"""
def setUp(self):
super(AgentsPolicyTest, self).setUp()
self.controller = agents.AgentController()
self.req = fakes.HTTPRequest.blank('')
# Check that admin is able to perform the CRUD operation
# on agents.
self.admin_authorized_contexts = [
self.legacy_admin_context, self.system_admin_context,
self.project_admin_context]
# Check that non-admin is not able to perform the CRUD operation
# on agents.
self.admin_unauthorized_contexts = [
self.system_member_context, self.system_reader_context,
self.system_foo_context, self.project_member_context,
self.other_project_member_context,
self.other_project_reader_context,
self.project_foo_context, self.project_reader_context
]
# Check that system scoped admin, member and reader are able to
# read the agent data.
# NOTE(gmann): Until old default rule which is admin_api is
# deprecated and not removed, project admin and legacy admin
# will be able to read the agent data. This make sure that existing
# tokens will keep working even we have changed this policy defaults
# to reader role.
self.reader_authorized_contexts = [
self.system_admin_context, self.system_member_context,
self.system_reader_context, self.legacy_admin_context,
self.project_admin_context]
# Check that non-system-reader are not able to read the agent
# data
self.reader_unauthorized_contexts = [
self.system_foo_context, self.other_project_member_context,
self.project_foo_context, self.project_member_context,
self.project_reader_context, self.other_project_reader_context,
]
@mock.patch('nova.db.api.agent_build_destroy')
def test_delete_agent_policy(self, mock_delete):
rule_name = "os_compute_api:os-agents:delete"
self.common_policy_check(self.admin_authorized_contexts,
self.admin_unauthorized_contexts,
rule_name, self.controller.delete,
self.req, 1)
@mock.patch('nova.db.api.agent_build_get_all')
def test_index_agents_policy(self, mock_get):
rule_name = "os_compute_api:os-agents:list"
self.common_policy_check(self.reader_authorized_contexts,
self.reader_unauthorized_contexts,
rule_name, self.controller.index,
self.req)
@mock.patch('nova.db.api.agent_build_update')
def test_update_agent_policy(self, mock_update):
rule_name = "os_compute_api:os-agents:update"
body = {'para': {'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
self.common_policy_check(self.admin_authorized_contexts,
self.admin_unauthorized_contexts,
rule_name, self.controller.update,
self.req, 1, body=body)
def test_create_agent_policy(self):
rule_name = "os_compute_api:os-agents:create"
body = {'agent': {'hypervisor': 'kvm',
'os': 'win',
'architecture': 'x86',
'version': '7.0',
'url': 'http://example.com/path/to/resource',
'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
def fake_agent_build_create(context, values):
values['id'] = 1
agent_build_ref = models.AgentBuild()
agent_build_ref.update(values)
return agent_build_ref
self.stub_out("nova.db.api.agent_build_create",
fake_agent_build_create)
self.common_policy_check(self.admin_authorized_contexts,
self.admin_unauthorized_contexts,
rule_name, self.controller.create,
self.req, body=body)
class AgentsScopeTypePolicyTest(AgentsPolicyTest):
"""Test os-agents APIs policies with system scope enabled.
This class set the nova.conf [oslo_policy] enforce_scope to True
so that we can switch on the scope checking on oslo policy side.
It defines the set of context with scoped token
which are allowed and not allowed to pass the policy checks.
With those set of context, it will run the API operation and
verify the expected behaviour.
"""
def setUp(self):
super(AgentsScopeTypePolicyTest, self).setUp()
self.flags(enforce_scope=True, group="oslo_policy")
# Check that system admin is able to perform the CRUD operation
# on agents.
self.admin_authorized_contexts = [
self.system_admin_context]
# Check that non-system or non-admin is not able to perform the CRUD
# operation on agents.
self.admin_unauthorized_contexts = [
self.legacy_admin_context, self.system_member_context,
self.system_reader_context, self.project_admin_context,
self.system_foo_context, self.project_member_context,
self.other_project_member_context,
self.project_foo_context, self.project_reader_context,
self.other_project_reader_context,
]
# Check that system admin, member and reader are able to read the
# agent data
self.reader_authorized_contexts = [
self.system_admin_context, self.system_member_context,
self.system_reader_context]
# Check that non-system or non-reader are not able to read the agent
# data
self.reader_unauthorized_contexts = [
self.system_foo_context, self.legacy_admin_context,
self.project_admin_context, self.project_member_context,
self.other_project_member_context,
self.project_foo_context, self.project_reader_context,
self.other_project_reader_context,
]
class AgentsDeprecatedPolicyTest(base.BasePolicyTest):
"""Test os-agents APIs Deprecated policies.
This class checks if deprecated policy rules are
overridden by user on policy.yaml file then they
still work because oslo.policy add deprecated rules
in logical OR condition and enforce them for policy
checks if overridden.
"""
def setUp(self):
super(AgentsDeprecatedPolicyTest, self).setUp()
self.controller = agents.AgentController()
self.admin_req = fakes.HTTPRequest.blank('')
self.admin_req.environ['nova.context'] = self.project_admin_context
self.reader_req = fakes.HTTPRequest.blank('')
self.reader_req.environ['nova.context'] = self.project_reader_context
self.deprecated_policy = "os_compute_api:os-agents"
# Overridde rule with different checks than defaults so that we can
# verify the rule overridden case.
override_rules = {self.deprecated_policy: base_policy.RULE_ADMIN_API}
# NOTE(gmann): Only override the deprecated rule in policy file so
# that we can verify if overridden checks are considered by
# oslo.policy. Oslo.policy will consider the overridden rules if:
# 1. overridden deprecated rule's checks are different than defaults
# 2. new rules are not present in policy file
self.policy = self.useFixture(policy_fixture.OverridePolicyFixture(
rules_in_file=override_rules))
def test_deprecated_policy_overridden_rule_is_checked(self):
# Test to verify if deprecatd overridden policy is working.
# check for success as admin role. Deprecated rule
# has been overridden with admin checks in policy.yaml
# If admin role pass it means overridden rule is enforced by
# olso.policy because new default is system reader and the old
# default is admin.
with mock.patch('nova.db.api.agent_build_get_all'):
self.controller.index(self.admin_req)
# check for failure with reader context.
exc = self.assertRaises(exception.PolicyNotAuthorized,
self.controller.index, self.reader_req)
self.assertEqual(
"Policy doesn't allow os_compute_api:os-agents:list to be"
" performed.",
exc.format_message())

View File

@ -337,9 +337,6 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
"os_compute_api:os-aggregates:add_host",
"os_compute_api:os-aggregates:remove_host",
"os_compute_api:os-aggregates:set_metadata",
"os_compute_api:os-agents:create",
"os_compute_api:os-agents:update",
"os_compute_api:os-agents:delete",
"os_compute_api:os-evacuate",
"os_compute_api:os-extended-server-attributes",
"os_compute_api:os-flavor-access:remove_tenant_access",
@ -484,7 +481,6 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
"os_compute_api:os-instance-actions:events:details",
"os_compute_api:os-instance-usage-audit-log:list",
"os_compute_api:os-instance-usage-audit-log:show",
"os_compute_api:os-agents:list",
"os_compute_api:os-hosts:list",
"os_compute_api:os-hosts:show",
"os_compute_api:os-hypervisors:list",

View File

@ -3,10 +3,25 @@ upgrade:
- |
The ``XenAPI`` driver, which was deprecated in the 20.0.0 (Train), has now
been removed.
- |
The following config options only apply when using the ``XenAPI`` virt
driver which has now been removed. The config options have therefore been
removed also.
A number of APIs that only worked with the ``XenAPI`` driver have been
removed along with their related policy rules. Calling these APIs will now
result in a ``410 (Gone)`` error response.
* ``GET /os-agents``
* ``POST /os-agents``
* ``PUT /os-agents/{agent_id}``
* ``DELETE /os-agents/{agent_id}``
The ``XenAPI`` specific policies have been removed:
* ``os_compute_api:os-agents``
* ``os_compute_api:os-agents:list``
* ``os_compute_api:os-agents:create``
* ``os_compute_api:os-agents:update``
* ``os_compute_api:os-agents:delete``
The ``XenAPI`` specific configuration options have been removed.
* ``[xenserver] agent_timeout``
* ``[xenserver] agent_version_timeout``