api: Remove 'os-agents' API
This was only useful with XenAPI and can therefore be removed. Change-Id: I9512f605dd2b3b0e88c951ed086250d57056303d Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
parent
8aea747c97
commit
7ac52e643c
|
@ -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
|
guest agents is possible only if the underlying service provider uses
|
||||||
the Xen driver.
|
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
|
List Agent Builds
|
||||||
=================
|
=================
|
||||||
|
|
||||||
|
@ -20,7 +26,7 @@ Lists agent builds.
|
||||||
|
|
||||||
Normal response codes: 200
|
Normal response codes: 200
|
||||||
|
|
||||||
Error response codes: unauthorized(401), forbidden(403)
|
Error response codes: unauthorized(401), forbidden(403), gone(410)
|
||||||
|
|
||||||
Request
|
Request
|
||||||
-------
|
-------
|
||||||
|
@ -58,7 +64,8 @@ Creates an agent build.
|
||||||
|
|
||||||
Normal response codes: 200
|
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
|
Request
|
||||||
-------
|
-------
|
||||||
|
@ -106,7 +113,8 @@ Updates an agent build.
|
||||||
|
|
||||||
Normal response codes: 200
|
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
|
Request
|
||||||
-------
|
-------
|
||||||
|
@ -150,7 +158,8 @@ Deletes an existing agent build.
|
||||||
|
|
||||||
Normal response codes: 200
|
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
|
Request
|
||||||
-------
|
-------
|
||||||
|
|
|
@ -13,153 +13,28 @@
|
||||||
# under the License.
|
# 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.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):
|
class AgentController(wsgi.Controller):
|
||||||
"""The agent is talking about guest agent.The host can use this for
|
"""(Removed) Controller for agent resources.
|
||||||
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).
|
|
||||||
|
|
||||||
You can find the design of agent update in this link:
|
This was removed during the Victoria release along with the XenAPI driver.
|
||||||
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
|
|
||||||
"""
|
"""
|
||||||
@validation.query_schema(schema.index_query_275, '2.75')
|
@wsgi.expected_errors(410)
|
||||||
@validation.query_schema(schema.index_query, '2.0', '2.74')
|
|
||||||
@wsgi.expected_errors(())
|
|
||||||
def index(self, req):
|
def index(self, req):
|
||||||
"""Return a list of all agent builds. Filter by hypervisor."""
|
raise exc.HTTPGone()
|
||||||
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']
|
|
||||||
|
|
||||||
builds = objects.AgentList.get_all(context, hypervisor=hypervisor)
|
@wsgi.expected_errors(410)
|
||||||
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)
|
|
||||||
def update(self, req, id, body):
|
def update(self, req, id, body):
|
||||||
"""Update an existing agent build."""
|
raise exc.HTTPGone()
|
||||||
context = req.environ['nova.context']
|
|
||||||
context.can(agents_policies.BASE_POLICY_NAME % 'update', target={})
|
|
||||||
|
|
||||||
# TODO(oomichi): This parameter name "para" is different from the ones
|
@wsgi.expected_errors(410)
|
||||||
# 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)
|
|
||||||
def delete(self, req, id):
|
def delete(self, req, id):
|
||||||
"""Deletes an existing agent build."""
|
raise exc.HTTPGone()
|
||||||
context = req.environ['nova.context']
|
|
||||||
context.can(agents_policies.BASE_POLICY_NAME % 'delete', target={})
|
|
||||||
|
|
||||||
try:
|
@wsgi.expected_errors(410)
|
||||||
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)
|
|
||||||
def create(self, req, body):
|
def create(self, req, body):
|
||||||
"""Creates a new agent build."""
|
raise exc.HTTPGone()
|
||||||
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}
|
|
||||||
|
|
|
@ -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
|
|
|
@ -19,6 +19,8 @@ from nova.objects import base
|
||||||
from nova.objects import fields
|
from nova.objects import fields
|
||||||
|
|
||||||
|
|
||||||
|
# TODO(stephenfin): Remove this object; it's not necessary since the removal of
|
||||||
|
# XenAPI
|
||||||
@base.NovaObjectRegistry.register
|
@base.NovaObjectRegistry.register
|
||||||
class Agent(base.NovaPersistentObject, base.NovaObject):
|
class Agent(base.NovaPersistentObject, base.NovaObject):
|
||||||
VERSION = '1.0'
|
VERSION = '1.0'
|
||||||
|
@ -69,6 +71,8 @@ class Agent(base.NovaPersistentObject, base.NovaObject):
|
||||||
self.obj_reset_changes()
|
self.obj_reset_changes()
|
||||||
|
|
||||||
|
|
||||||
|
# TODO(stephenfin): Remove this object; it's not necessary since the removal of
|
||||||
|
# XenAPI
|
||||||
@base.NovaObjectRegistry.register
|
@base.NovaObjectRegistry.register
|
||||||
class AgentList(base.ObjectListBase, base.NovaObject):
|
class AgentList(base.ObjectListBase, base.NovaObject):
|
||||||
VERSION = '1.0'
|
VERSION = '1.0'
|
||||||
|
|
|
@ -15,7 +15,6 @@ import itertools
|
||||||
|
|
||||||
from nova.policies import admin_actions
|
from nova.policies import admin_actions
|
||||||
from nova.policies import admin_password
|
from nova.policies import admin_password
|
||||||
from nova.policies import agents
|
|
||||||
from nova.policies import aggregates
|
from nova.policies import aggregates
|
||||||
from nova.policies import assisted_volume_snapshots
|
from nova.policies import assisted_volume_snapshots
|
||||||
from nova.policies import attach_interfaces
|
from nova.policies import attach_interfaces
|
||||||
|
@ -75,7 +74,6 @@ def list_rules():
|
||||||
base.list_rules(),
|
base.list_rules(),
|
||||||
admin_actions.list_rules(),
|
admin_actions.list_rules(),
|
||||||
admin_password.list_rules(),
|
admin_password.list_rules(),
|
||||||
agents.list_rules(),
|
|
||||||
aggregates.list_rules(),
|
aggregates.list_rules(),
|
||||||
assisted_volume_snapshots.list_rules(),
|
assisted_volume_snapshots.list_rules(),
|
||||||
attach_interfaces.list_rules(),
|
attach_interfaces.list_rules(),
|
||||||
|
|
|
@ -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
|
|
|
@ -13,86 +13,23 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from nova.db.sqlalchemy import models
|
|
||||||
from nova.tests.functional.api_sample_tests import api_sample_base
|
from nova.tests.functional.api_sample_tests import api_sample_base
|
||||||
|
|
||||||
|
|
||||||
class AgentsJsonTest(api_sample_base.ApiSampleTestBaseV21):
|
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):
|
def test_agent_create(self):
|
||||||
# Creates a new agent build.
|
# Creates a new agent build.
|
||||||
project = {'url': 'http://example.com/path/to/resource',
|
self.api.api_post('/os-agents', {}, check_response_status=[410])
|
||||||
'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)
|
|
||||||
|
|
||||||
def test_agent_list(self):
|
def test_agent_list(self):
|
||||||
# Return a list of all agent builds.
|
# Return a list of all agent builds.
|
||||||
response = self._do_get('os-agents')
|
self.api.api_get('/os-agents', check_response_status=[410])
|
||||||
self._verify_response('agents-get-resp', {}, response, 200)
|
|
||||||
|
|
||||||
def test_agent_update(self):
|
def test_agent_update(self):
|
||||||
# Update an existing agent build.
|
# Update an existing agent build.
|
||||||
agent_id = 1
|
self.api.api_put('/os-agents/1', {}, check_response_status=[410])
|
||||||
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)
|
|
||||||
|
|
||||||
def test_agent_delete(self):
|
def test_agent_delete(self):
|
||||||
# Deletes an existing agent build.
|
# Deletes an existing agent build.
|
||||||
agent_id = 1
|
self.api.api_delete('/os-agents/1', check_response_status=[410])
|
||||||
response = self._do_delete('os-agents/%s' % agent_id)
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
|
|
|
@ -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)
|
|
|
@ -54,10 +54,6 @@ policy_data = """
|
||||||
"os_compute_api:os-admin-actions:reset_network": "",
|
"os_compute_api:os-admin-actions:reset_network": "",
|
||||||
"os_compute_api:os-admin-actions:reset_state": "",
|
"os_compute_api:os-admin-actions:reset_state": "",
|
||||||
"os_compute_api:os-admin-password": "",
|
"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:set_metadata": "",
|
||||||
"os_compute_api:os-aggregates:remove_host": "",
|
"os_compute_api:os-aggregates:remove_host": "",
|
||||||
"os_compute_api:os-aggregates:add_host": "",
|
"os_compute_api:os-aggregates:add_host": "",
|
||||||
|
|
|
@ -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())
|
|
|
@ -337,9 +337,6 @@ class RealRolePolicyTestCase(test.NoDBTestCase):
|
||||||
"os_compute_api:os-aggregates:add_host",
|
"os_compute_api:os-aggregates:add_host",
|
||||||
"os_compute_api:os-aggregates:remove_host",
|
"os_compute_api:os-aggregates:remove_host",
|
||||||
"os_compute_api:os-aggregates:set_metadata",
|
"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-evacuate",
|
||||||
"os_compute_api:os-extended-server-attributes",
|
"os_compute_api:os-extended-server-attributes",
|
||||||
"os_compute_api:os-flavor-access:remove_tenant_access",
|
"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-actions:events:details",
|
||||||
"os_compute_api:os-instance-usage-audit-log:list",
|
"os_compute_api:os-instance-usage-audit-log:list",
|
||||||
"os_compute_api:os-instance-usage-audit-log:show",
|
"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:list",
|
||||||
"os_compute_api:os-hosts:show",
|
"os_compute_api:os-hosts:show",
|
||||||
"os_compute_api:os-hypervisors:list",
|
"os_compute_api:os-hypervisors:list",
|
||||||
|
|
|
@ -3,10 +3,25 @@ upgrade:
|
||||||
- |
|
- |
|
||||||
The ``XenAPI`` driver, which was deprecated in the 20.0.0 (Train), has now
|
The ``XenAPI`` driver, which was deprecated in the 20.0.0 (Train), has now
|
||||||
been removed.
|
been removed.
|
||||||
- |
|
|
||||||
The following config options only apply when using the ``XenAPI`` virt
|
A number of APIs that only worked with the ``XenAPI`` driver have been
|
||||||
driver which has now been removed. The config options have therefore been
|
removed along with their related policy rules. Calling these APIs will now
|
||||||
removed also.
|
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_timeout``
|
||||||
* ``[xenserver] agent_version_timeout``
|
* ``[xenserver] agent_version_timeout``
|
||||||
|
|
Loading…
Reference in New Issue