summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api-ref/source/os-agents.inc17
-rw-r--r--nova/api/openstack/compute/agents.py147
-rw-r--r--nova/api/openstack/compute/schemas/agents.py100
-rw-r--r--nova/objects/agent.py4
-rw-r--r--nova/policies/__init__.py2
-rw-r--r--nova/policies/agents.py108
-rw-r--r--nova/tests/functional/api_sample_tests/test_agents.py71
-rw-r--r--nova/tests/unit/api/openstack/compute/test_agents.py431
-rw-r--r--nova/tests/unit/fake_policy.py4
-rw-r--r--nova/tests/unit/policies/test_agents.py212
-rw-r--r--nova/tests/unit/test_policy.py4
-rw-r--r--releasenotes/notes/remove-xenapi-driver-194756049f22dc9e.yaml23
12 files changed, 51 insertions, 1072 deletions
diff --git a/api-ref/source/os-agents.inc b/api-ref/source/os-agents.inc
index 33bd9fbd3a..f9ab86a62c 100644
--- a/api-ref/source/os-agents.inc
+++ b/api-ref/source/os-agents.inc
@@ -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
-------
diff --git a/nova/api/openstack/compute/agents.py b/nova/api/openstack/compute/agents.py
index 3edc63eb31..38e690b59e 100644
--- a/nova/api/openstack/compute/agents.py
+++ b/nova/api/openstack/compute/agents.py
@@ -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']
-
- 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})
+ raise exc.HTTPGone()
- 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={})
-
- # 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())
+ raise exc.HTTPGone()
- # 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={})
-
- 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())
+ raise exc.HTTPGone()
- # 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()
diff --git a/nova/api/openstack/compute/schemas/agents.py b/nova/api/openstack/compute/schemas/agents.py
deleted file mode 100644
index 54add72d0f..0000000000
--- a/nova/api/openstack/compute/schemas/agents.py
+++ /dev/null
@@ -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
diff --git a/nova/objects/agent.py b/nova/objects/agent.py
index 9f5884453d..9bea1df406 100644
--- a/nova/objects/agent.py
+++ b/nova/objects/agent.py
@@ -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'
diff --git a/nova/policies/__init__.py b/nova/policies/__init__.py
index 91362d2606..d5c485cfa3 100644
--- a/nova/policies/__init__.py
+++ b/nova/policies/__init__.py
@@ -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(),
diff --git a/nova/policies/agents.py b/nova/policies/agents.py
deleted file mode 100644
index eb420b8dca..0000000000
--- a/nova/policies/agents.py
+++ /dev/null
@@ -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
diff --git a/nova/tests/functional/api_sample_tests/test_agents.py b/nova/tests/functional/api_sample_tests/test_agents.py
index 6702a1092d..894a0b8e90 100644
--- a/nova/tests/functional/api_sample_tests/test_agents.py
+++ b/nova/tests/functional/api_sample_tests/test_agents.py
@@ -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])
diff --git a/nova/tests/unit/api/openstack/compute/test_agents.py b/nova/tests/unit/api/openstack/compute/test_agents.py
deleted file mode 100644
index bed4fc3106..0000000000
--- a/nova/tests/unit/api/openstack/compute/test_agents.py
+++ /dev/null
@@ -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)
diff --git a/nova/tests/unit/fake_policy.py b/nova/tests/unit/fake_policy.py
index 5efe002110..9f19d29ef0 100644
--- a/nova/tests/unit/fake_policy.py
+++ b/nova/tests/unit/fake_policy.py
@@ -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": "",
diff --git a/nova/tests/unit/policies/test_agents.py b/nova/tests/unit/policies/test_agents.py
deleted file mode 100644
index d4c5f28b31..0000000000
--- a/nova/tests/unit/policies/test_agents.py
+++ /dev/null
@@ -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())
diff --git a/nova/tests/unit/test_policy.py b/nova/tests/unit/test_policy.py
index 31fee0be74..aae8e6346f 100644
--- a/nova/tests/unit/test_policy.py
+++ b/nova/tests/unit/test_policy.py
@@ -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",
diff --git a/releasenotes/notes/remove-xenapi-driver-194756049f22dc9e.yaml b/releasenotes/notes/remove-xenapi-driver-194756049f22dc9e.yaml
index 25f82ce1e8..a09b29b24d 100644
--- a/releasenotes/notes/remove-xenapi-driver-194756049f22dc9e.yaml
+++ b/releasenotes/notes/remove-xenapi-driver-194756049f22dc9e.yaml
@@ -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``