summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-12-05 18:51:58 +0000
committerGerrit Code Review <review@openstack.org>2012-12-05 18:51:58 +0000
commit2804b01a6bb404d3e120289680a3cfa4e4c3e380 (patch)
treec9b6aa55a51bb2d37c7932ffc779d95d10149654
parentf9245c8353f1f9a89a2f578c2b53264c0ea3b3a5 (diff)
parent82042ac2766b892d561836cd312656940522734a (diff)
downloadnova-2804b01a6bb404d3e120289680a3cfa4e4c3e380.tar.gz
nova-2804b01a6bb404d3e120289680a3cfa4e4c3e380.tar.xz
nova-2804b01a6bb404d3e120289680a3cfa4e4c3e380.zip
Merge "Add agent build API support for list/create/delete/modify agent build"
-rw-r--r--doc/api_samples/all_extensions/extensions-get-resp.json8
-rw-r--r--doc/api_samples/all_extensions/extensions-get-resp.xml3
-rw-r--r--doc/api_samples/os-agents/agent-post-req.json10
-rw-r--r--doc/api_samples/os-agents/agent-post-req.xml9
-rw-r--r--doc/api_samples/os-agents/agent-post-resp.json11
-rw-r--r--doc/api_samples/os-agents/agent-post-resp.xml10
-rw-r--r--doc/api_samples/os-agents/agent-update-put-req.json7
-rw-r--r--doc/api_samples/os-agents/agent-update-put-req.xml6
-rw-r--r--doc/api_samples/os-agents/agent-update-put-resp.json8
-rw-r--r--doc/api_samples/os-agents/agent-update-put-resp.xml7
-rw-r--r--doc/api_samples/os-agents/agents-get-resp.json13
-rw-r--r--doc/api_samples/os-agents/agents-get-resp.xml4
-rw-r--r--etc/nova/policy.json1
-rw-r--r--nova/api/openstack/compute/contrib/agents.py171
-rw-r--r--nova/db/api.py4
-rw-r--r--nova/db/sqlalchemy/api.py25
-rw-r--r--nova/exception.py4
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_agents.py185
-rw-r--r--nova/tests/api/openstack/compute/test_extensions.py1
-rw-r--r--nova/tests/fake_policy.py1
-rw-r--r--nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl8
-rw-r--r--nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl3
-rw-r--r--nova/tests/integrated/api_samples/os-agents/agent-post-req.json.tpl10
-rw-r--r--nova/tests/integrated/api_samples/os-agents/agent-post-req.xml.tpl9
-rw-r--r--nova/tests/integrated/api_samples/os-agents/agent-post-resp.json.tpl12
-rw-r--r--nova/tests/integrated/api_samples/os-agents/agent-post-resp.xml.tpl10
-rw-r--r--nova/tests/integrated/api_samples/os-agents/agent-update-put-req.json.tpl7
-rw-r--r--nova/tests/integrated/api_samples/os-agents/agent-update-put-req.xml.tpl6
-rw-r--r--nova/tests/integrated/api_samples/os-agents/agent-update-put-resp.json.tpl8
-rw-r--r--nova/tests/integrated/api_samples/os-agents/agent-update-put-resp.xml.tpl7
-rw-r--r--nova/tests/integrated/api_samples/os-agents/agents-get-resp.json.tpl13
-rw-r--r--nova/tests/integrated/api_samples/os-agents/agents-get-resp.xml.tpl4
-rw-r--r--nova/tests/integrated/test_api_samples.py104
33 files changed, 679 insertions, 10 deletions
diff --git a/doc/api_samples/all_extensions/extensions-get-resp.json b/doc/api_samples/all_extensions/extensions-get-resp.json
index 399d937a7..cf3d66a76 100644
--- a/doc/api_samples/all_extensions/extensions-get-resp.json
+++ b/doc/api_samples/all_extensions/extensions-get-resp.json
@@ -65,6 +65,14 @@
"updated": "2011-09-20T00:00:00+00:00"
},
{
+ "alias": "os-agents",
+ "description": "Agents support",
+ "links": [],
+ "name": "Agents",
+ "namespace": "http://docs.openstack.org/compute/ext/agents/api/v2",
+ "updated": "2012-10-28T00:00:00-00:00"
+ },
+ {
"alias": "os-aggregates",
"description": "Admin-only aggregate administration",
"links": [],
diff --git a/doc/api_samples/all_extensions/extensions-get-resp.xml b/doc/api_samples/all_extensions/extensions-get-resp.xml
index e4d3b8cc3..44816c09c 100644
--- a/doc/api_samples/all_extensions/extensions-get-resp.xml
+++ b/doc/api_samples/all_extensions/extensions-get-resp.xml
@@ -28,6 +28,9 @@
resetNetwork, injectNetworkInfo, lock, unlock, createBackup
</description>
</extension>
+ <extension alias="os-agents" updated="2012-10-28T00:00:00-00:00" namespace="http://docs.openstack.org/compute/ext/agents/api/v2" name="Agents">
+ <description>Agents support</description>
+ </extension>
<extension alias="os-aggregates" updated="2012-01-12T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/aggregates/api/v1.1" name="Aggregates">
<description>Admin-only aggregate administration</description>
</extension>
diff --git a/doc/api_samples/os-agents/agent-post-req.json b/doc/api_samples/os-agents/agent-post-req.json
new file mode 100644
index 000000000..217993b17
--- /dev/null
+++ b/doc/api_samples/os-agents/agent-post-req.json
@@ -0,0 +1,10 @@
+{
+ "agent": {
+ "hypervisor": "hypervisor",
+ "os": "os",
+ "architecture": "x86",
+ "version": "8.0",
+ "md5hash": "add6bb58e139be103324d04d82d8f545",
+ "url": "xxxxxxxxxxxx"
+ }
+} \ No newline at end of file
diff --git a/doc/api_samples/os-agents/agent-post-req.xml b/doc/api_samples/os-agents/agent-post-req.xml
new file mode 100644
index 000000000..be93e97ce
--- /dev/null
+++ b/doc/api_samples/os-agents/agent-post-req.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<agent>
+ <hypervisor>hypervisor</hypervisor>
+ <os>os</os>
+ <architecture>x86</architecture>
+ <version>8.0</version>
+ <md5hash>add6bb58e139be103324d04d82d8f545</md5hash>
+ <url>xxxxxxxxxxxx</url>
+</agent> \ No newline at end of file
diff --git a/doc/api_samples/os-agents/agent-post-resp.json b/doc/api_samples/os-agents/agent-post-resp.json
new file mode 100644
index 000000000..418d11f50
--- /dev/null
+++ b/doc/api_samples/os-agents/agent-post-resp.json
@@ -0,0 +1,11 @@
+{
+ "agent": {
+ "agent_id": "1",
+ "architecture": "x86",
+ "hypervisor": "hypervisor",
+ "md5hash": "add6bb58e139be103324d04d82d8f545",
+ "os": "os",
+ "url": "xxxxxxxxxxxx",
+ "version": "8.0"
+ }
+} \ No newline at end of file
diff --git a/doc/api_samples/os-agents/agent-post-resp.xml b/doc/api_samples/os-agents/agent-post-resp.xml
new file mode 100644
index 000000000..79f62b7fb
--- /dev/null
+++ b/doc/api_samples/os-agents/agent-post-resp.xml
@@ -0,0 +1,10 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<agent>
+ <url>xxxxxxxxxxxx</url>
+ <hypervisor>hypervisor</hypervisor>
+ <md5hash>add6bb58e139be103324d04d82d8f545</md5hash>
+ <version>8.0</version>
+ <architecture>x86</architecture>
+ <os>os</os>
+ <agent_id>1</agent_id>
+</agent> \ No newline at end of file
diff --git a/doc/api_samples/os-agents/agent-update-put-req.json b/doc/api_samples/os-agents/agent-update-put-req.json
new file mode 100644
index 000000000..e4eaf5352
--- /dev/null
+++ b/doc/api_samples/os-agents/agent-update-put-req.json
@@ -0,0 +1,7 @@
+{
+ "para": {
+ "url": "xxx://xxxx/xxx/xxx",
+ "md5hash": "add6bb58e139be103324d04d82d8f545",
+ "version": "7.0"
+ }
+} \ No newline at end of file
diff --git a/doc/api_samples/os-agents/agent-update-put-req.xml b/doc/api_samples/os-agents/agent-update-put-req.xml
new file mode 100644
index 000000000..f759880c1
--- /dev/null
+++ b/doc/api_samples/os-agents/agent-update-put-req.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<para>
+ <version>7.0</version>
+ <url>xxx://xxxx/xxx/xxx</url>
+ <md5hash>add6bb58e139be103324d04d82d8f545</md5hash>
+</para> \ No newline at end of file
diff --git a/doc/api_samples/os-agents/agent-update-put-resp.json b/doc/api_samples/os-agents/agent-update-put-resp.json
new file mode 100644
index 000000000..6b67222c8
--- /dev/null
+++ b/doc/api_samples/os-agents/agent-update-put-resp.json
@@ -0,0 +1,8 @@
+{
+ "agent": {
+ "agent_id": "1",
+ "md5hash": "add6bb58e139be103324d04d82d8f545",
+ "url": "xxx://xxxx/xxx/xxx",
+ "version": "7.0"
+ }
+} \ No newline at end of file
diff --git a/doc/api_samples/os-agents/agent-update-put-resp.xml b/doc/api_samples/os-agents/agent-update-put-resp.xml
new file mode 100644
index 000000000..badf2750e
--- /dev/null
+++ b/doc/api_samples/os-agents/agent-update-put-resp.xml
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<agent>
+ <url>xxx://xxxx/xxx/xxx</url>
+ <version>7.0</version>
+ <agent_id>1</agent_id>
+ <md5hash>add6bb58e139be103324d04d82d8f545</md5hash>
+</agent> \ No newline at end of file
diff --git a/doc/api_samples/os-agents/agents-get-resp.json b/doc/api_samples/os-agents/agents-get-resp.json
new file mode 100644
index 000000000..36eac4ced
--- /dev/null
+++ b/doc/api_samples/os-agents/agents-get-resp.json
@@ -0,0 +1,13 @@
+{
+ "agents": [
+ {
+ "agent_id": "1",
+ "architecture": "x86",
+ "hypervisor": "hypervisor",
+ "md5hash": "add6bb58e139be103324d04d82d8f545",
+ "os": "os",
+ "url": "xxxxxxxxxxxx",
+ "version": "8.0"
+ }
+ ]
+} \ No newline at end of file
diff --git a/doc/api_samples/os-agents/agents-get-resp.xml b/doc/api_samples/os-agents/agents-get-resp.xml
new file mode 100644
index 000000000..4194f62c9
--- /dev/null
+++ b/doc/api_samples/os-agents/agents-get-resp.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<agents>
+ <agent url="xxxxxxxxxxxx" hypervisor="hypervisor" md5hash="add6bb58e139be103324d04d82d8f545" version="8.0" architecture="x86" os="os" agent_id="1"/>
+</agents> \ No newline at end of file
diff --git a/etc/nova/policy.json b/etc/nova/policy.json
index 778203e75..942b74f66 100644
--- a/etc/nova/policy.json
+++ b/etc/nova/policy.json
@@ -28,6 +28,7 @@
"compute_extension:admin_actions:resetState": "rule:admin_api",
"compute_extension:admin_actions:migrate": "rule:admin_api",
"compute_extension:aggregates": "rule:admin_api",
+ "compute_extension:agents": "rule:admin_api",
"compute_extension:certificates": "",
"compute_extension:cloudpipe": "rule:admin_api",
"compute_extension:cloudpipe_update": "rule:admin_api",
diff --git a/nova/api/openstack/compute/contrib/agents.py b/nova/api/openstack/compute/contrib/agents.py
new file mode 100644
index 000000000..218f06b52
--- /dev/null
+++ b/nova/api/openstack/compute/contrib/agents.py
@@ -0,0 +1,171 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 IBM
+# 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 webob.exc
+
+from nova.api.openstack import extensions
+from nova.api.openstack import wsgi
+from nova.api.openstack import xmlutil
+from nova import db
+from nova import exception
+from nova.openstack.common import log as logging
+
+
+LOG = logging.getLogger(__name__)
+authorize = extensions.extension_authorizer('compute', 'agents')
+
+
+class AgentsIndexTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('agents')
+ elem = xmlutil.SubTemplateElement(root, 'agent', selector='agents')
+ elem.set('hypervisor')
+ elem.set('os')
+ elem.set('architecture')
+ elem.set('version')
+ elem.set('md5hash')
+ elem.set('agent_id')
+ elem.set('url')
+
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class AgentController(object):
+ """
+ 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).
+
+ You can find the design of agent update in this link:
+ http://wiki.openstack.org/AgentUpdate
+ and find the code in nova.virt.xenapi.vmops.VMOps._boot_new_instance.
+ 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
+ """
+ @wsgi.serializers(xml=AgentsIndexTemplate)
+ def index(self, req):
+ """
+ Return a list of all agent builds. Filter by hypervisor.
+ """
+ context = req.environ['nova.context']
+ authorize(context)
+ hypervisor = None
+ agents = []
+ if 'hypervisor' in req.GET:
+ hypervisor = req.GET['hypervisor']
+
+ for agent_build in db.agent_build_get_all(context, hypervisor):
+ 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}
+
+ def update(self, req, id, body):
+ """Update an existing agent build."""
+ context = req.environ['nova.context']
+ authorize(context)
+
+ try:
+ para = body['para']
+ url = para['url']
+ md5hash = para['md5hash']
+ version = para['version']
+ except (TypeError, KeyError):
+ raise webob.exc.HTTPUnprocessableEntity()
+
+ try:
+ db.agent_build_update(context, id,
+ {'version': version,
+ 'url': url,
+ 'md5hash': md5hash})
+ except exception.AgentBuildNotFound as ex:
+ raise webob.exc.HTTPNotFound(explanation=str(ex))
+
+ return {"agent": {'agent_id': id, 'version': version,
+ 'url': url, 'md5hash': md5hash}}
+
+ def delete(self, req, id):
+ """Deletes an existing agent build."""
+ context = req.environ['nova.context']
+ authorize(context)
+
+ try:
+ db.agent_build_destroy(context, id)
+ except exception.AgentBuildNotFound as ex:
+ raise webob.exc.HTTPNotFound(explanation=str(ex))
+
+ def create(self, req, body):
+ """Creates a new agent build."""
+ context = req.environ['nova.context']
+ authorize(context)
+
+ try:
+ agent = body['agent']
+ hypervisor = agent['hypervisor']
+ os = agent['os']
+ architecture = agent['architecture']
+ version = agent['version']
+ url = agent['url']
+ md5hash = agent['md5hash']
+ except (TypeError, KeyError):
+ raise webob.exc.HTTPUnprocessableEntity()
+
+ try:
+ agent_build_ref = db.agent_build_create(context,
+ {'hypervisor': hypervisor,
+ 'os': os,
+ 'architecture': architecture,
+ 'version': version,
+ 'url': url,
+ 'md5hash': md5hash})
+ agent['agent_id'] = agent_build_ref.id
+ except Exception as ex:
+ raise webob.exc.HTTPServerError(str(ex))
+ return {'agent': agent}
+
+
+class Agents(extensions.ExtensionDescriptor):
+ """Agents support"""
+
+ name = "Agents"
+ alias = "os-agents"
+ namespace = "http://docs.openstack.org/compute/ext/agents/api/v2"
+ updated = "2012-10-28T00:00:00-00:00"
+
+ def get_resources(self):
+ resources = []
+ resource = extensions.ResourceExtension('os-agents',
+ AgentController())
+ resources.append(resource)
+ return resources
diff --git a/nova/db/api.py b/nova/db/api.py
index ad928f585..cfa6a6487 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -1372,9 +1372,9 @@ def agent_build_get_by_triple(context, hypervisor, os, architecture):
architecture)
-def agent_build_get_all(context):
+def agent_build_get_all(context, hypervisor=None):
"""Get all agent builds."""
- return IMPL.agent_build_get_all(context)
+ return IMPL.agent_build_get_all(context, hypervisor)
def agent_build_destroy(context, agent_update_id):
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index f2d804985..f7c0373e6 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -3968,8 +3968,13 @@ def agent_build_get_by_triple(context, hypervisor, os, architecture,
@require_admin_context
-def agent_build_get_all(context):
- return model_query(context, models.AgentBuild, read_deleted="no").\
+def agent_build_get_all(context, hypervisor=None):
+ if hypervisor:
+ return model_query(context, models.AgentBuild, read_deleted="no").\
+ filter_by(hypervisor=hypervisor).\
+ all()
+ else:
+ return model_query(context, models.AgentBuild, read_deleted="no").\
all()
@@ -3977,12 +3982,15 @@ def agent_build_get_all(context):
def agent_build_destroy(context, agent_build_id):
session = get_session()
with session.begin():
- model_query(context, models.AgentBuild, session=session,
- read_deleted="yes").\
+ agent_build_ref = model_query(context, models.AgentBuild,
+ session=session, read_deleted="yes").\
filter_by(id=agent_build_id).\
- update({'deleted': True,
- 'deleted_at': timeutils.utcnow(),
- 'updated_at': literal_column('updated_at')})
+ first()
+ if not agent_build_ref:
+ raise exception.AgentBuildNotFound(id=agent_build_id)
+ agent_build_ref.update({'deleted': True,
+ 'deleted_at': timeutils.utcnow(),
+ 'updated_at': literal_column('updated_at')})
@require_admin_context
@@ -3993,7 +4001,8 @@ def agent_build_update(context, agent_build_id, values):
session=session, read_deleted="yes").\
filter_by(id=agent_build_id).\
first()
-
+ if not agent_build_ref:
+ raise exception.AgentBuildNotFound(id=agent_build_id)
agent_build_ref.update(values)
agent_build_ref.save(session=session)
diff --git a/nova/exception.py b/nova/exception.py
index 7629db9fe..7477d9c63 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -412,6 +412,10 @@ class NotFound(NovaException):
code = 404
+class AgentBuildNotFound(NotFound):
+ message = _("No agent-build associated with id %(id)s.")
+
+
class VolumeNotFound(NotFound):
message = _("Volume %(volume_id)s could not be found.")
diff --git a/nova/tests/api/openstack/compute/contrib/test_agents.py b/nova/tests/api/openstack/compute/contrib/test_agents.py
new file mode 100644
index 000000000..60659b3c6
--- /dev/null
+++ b/nova/tests/api/openstack/compute/contrib/test_agents.py
@@ -0,0 +1,185 @@
+# Copyright 2012 IBM
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+from nova.api.openstack.compute.contrib import agents
+from nova import context
+from nova import db
+from nova.db.sqlalchemy import models
+from nova import test
+
+fake_agents_list = [{'hypervisor': 'kvm', 'os': 'win',
+ 'architecture': 'x86',
+ 'version': '7.0',
+ 'url': 'xxx://xxxx/xxx/xxx',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f545',
+ 'id': 1},
+ {'hypervisor': 'kvm', 'os': 'linux',
+ 'architecture': 'x86',
+ 'version': '16.0',
+ 'url': 'xxx://xxxx/xxx/xxx1',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f546',
+ 'id': 2},
+ {'hypervisor': 'xen', 'os': 'linux',
+ 'architecture': 'x86',
+ 'version': '16.0',
+ 'url': 'xxx://xxxx/xxx/xxx2',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f547',
+ 'id': 3},
+ {'hypervisor': 'xen', 'os': 'win',
+ 'architecture': 'power',
+ 'version': '7.0',
+ 'url': 'xxx://xxxx/xxx/xxx3',
+ '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 FakeRequest(object):
+ environ = {"nova.context": context.get_admin_context()}
+ GET = {}
+
+
+class FakeRequestWithHypervisor(object):
+ environ = {"nova.context": context.get_admin_context()}
+ GET = {'hypervisor': 'kvm'}
+
+
+class AgentsTest(test.TestCase):
+
+ def setUp(self):
+ super(AgentsTest, self).setUp()
+
+ self.stubs.Set(db, "agent_build_get_all",
+ fake_agent_build_get_all)
+ self.stubs.Set(db, "agent_build_update",
+ fake_agent_build_update)
+ self.stubs.Set(db, "agent_build_destroy",
+ fake_agent_build_destroy)
+ self.stubs.Set(db, "agent_build_create",
+ fake_agent_build_create)
+ self.context = context.get_admin_context()
+ self.controller = agents.AgentController()
+
+ def tearDown(self):
+ super(AgentsTest, self).tearDown()
+
+ def test_agents_create(self):
+ req = FakeRequest()
+ body = {'agent': {'hypervisor': 'kvm',
+ 'os': 'win',
+ 'architecture': 'x86',
+ 'version': '7.0',
+ 'url': 'xxx://xxxx/xxx/xxx',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
+ response = {'agent': {'hypervisor': 'kvm',
+ 'os': 'win',
+ 'architecture': 'x86',
+ 'version': '7.0',
+ 'url': 'xxx://xxxx/xxx/xxx',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f545',
+ 'agent_id': 1}}
+ res_dict = self.controller.create(req, body)
+ self.assertEqual(res_dict, response)
+
+ def test_agents_delete(self):
+ req = FakeRequest()
+ self.controller.delete(req, 1)
+
+ def test_agents_list(self):
+ req = FakeRequest()
+ res_dict = self.controller.index(req)
+ agents_list = [{'hypervisor': 'kvm', 'os': 'win',
+ 'architecture': 'x86',
+ 'version': '7.0',
+ 'url': 'xxx://xxxx/xxx/xxx',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f545',
+ 'agent_id': 1},
+ {'hypervisor': 'kvm', 'os': 'linux',
+ 'architecture': 'x86',
+ 'version': '16.0',
+ 'url': 'xxx://xxxx/xxx/xxx1',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f546',
+ 'agent_id': 2},
+ {'hypervisor': 'xen', 'os': 'linux',
+ 'architecture': 'x86',
+ 'version': '16.0',
+ 'url': 'xxx://xxxx/xxx/xxx2',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f547',
+ 'agent_id': 3},
+ {'hypervisor': 'xen', 'os': 'win',
+ 'architecture': 'power',
+ 'version': '7.0',
+ 'url': 'xxx://xxxx/xxx/xxx3',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f548',
+ 'agent_id': 4},
+ ]
+ self.assertEqual(res_dict, {'agents': agents_list})
+
+ def test_agents_list_with_hypervisor(self):
+ req = FakeRequestWithHypervisor()
+ res_dict = self.controller.index(req)
+ response = [{'hypervisor': 'kvm', 'os': 'win',
+ 'architecture': 'x86',
+ 'version': '7.0',
+ 'url': 'xxx://xxxx/xxx/xxx',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f545',
+ 'agent_id': 1},
+ {'hypervisor': 'kvm', 'os': 'linux',
+ 'architecture': 'x86',
+ 'version': '16.0',
+ 'url': 'xxx://xxxx/xxx/xxx1',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f546',
+ 'agent_id': 2},
+ ]
+ self.assertEqual(res_dict, {'agents': response})
+
+ def test_agents_update(self):
+ req = FakeRequest()
+ body = {'para': {'version': '7.0',
+ 'url': 'xxx://xxxx/xxx/xxx',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
+ response = {'agent': {'agent_id': 1,
+ 'version': '7.0',
+ 'url': 'xxx://xxxx/xxx/xxx',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f545'}}
+ res_dict = self.controller.update(req, 1, body)
+ self.assertEqual(res_dict, response)
diff --git a/nova/tests/api/openstack/compute/test_extensions.py b/nova/tests/api/openstack/compute/test_extensions.py
index eab55f95e..66dac3feb 100644
--- a/nova/tests/api/openstack/compute/test_extensions.py
+++ b/nova/tests/api/openstack/compute/test_extensions.py
@@ -158,6 +158,7 @@ class ExtensionControllerTest(ExtensionTestCase):
"AdminActions",
"Aggregates",
"AvailabilityZone",
+ "Agents",
"Certificates",
"Cloudpipe",
"CloudpipeUpdate",
diff --git a/nova/tests/fake_policy.py b/nova/tests/fake_policy.py
index b3ae0fa17..7813cddc0 100644
--- a/nova/tests/fake_policy.py
+++ b/nova/tests/fake_policy.py
@@ -103,6 +103,7 @@ policy_data = """
"compute_extension:admin_actions:resetState": "",
"compute_extension:admin_actions:migrate": "",
"compute_extension:aggregates": "",
+ "compute_extension:agents": "",
"compute_extension:certificates": "",
"compute_extension:cloudpipe": "",
"compute_extension:cloudpipe_update": "",
diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl
index 65cbb4889..0b27896fd 100644
--- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl
@@ -73,6 +73,14 @@
"updated": "%(timestamp)s"
},
{
+ "alias": "os-agents",
+ "description": "%(text)s",
+ "links": [],
+ "name": "Agents",
+ "namespace": "http://docs.openstack.org/compute/ext/agents/api/v2",
+ "updated": "%(timestamp)s"
+ },
+ {
"alias": "os-availability-zone",
"description": "%(text)s",
"links": [],
diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl
index bdef0266c..fec850997 100644
--- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl
@@ -30,6 +30,9 @@
<extension alias="os-availability-zone" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/availabilityzone/api/v1.1" name="AvailabilityZone">
<description>%(text)s</description>
</extension>
+ <extension alias="os-agents" name="Agents" namespace="http://docs.openstack.org/compute/ext/agents/api/v2" updated="%(timestamp)s">
+ <description>%(text)s</description>
+ </extension>
<extension alias="os-certificates" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/certificates/api/v1.1" name="Certificates">
<description>%(text)s</description>
</extension>
diff --git a/nova/tests/integrated/api_samples/os-agents/agent-post-req.json.tpl b/nova/tests/integrated/api_samples/os-agents/agent-post-req.json.tpl
new file mode 100644
index 000000000..6dbd2f17c
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-agents/agent-post-req.json.tpl
@@ -0,0 +1,10 @@
+{
+ "agent": {
+ "hypervisor": "%(hypervisor)s",
+ "os": "%(os)s",
+ "architecture": "%(architecture)s",
+ "version": "%(version)s",
+ "md5hash": "%(md5hash)s",
+ "url": "%(url)s"
+ }
+}
diff --git a/nova/tests/integrated/api_samples/os-agents/agent-post-req.xml.tpl b/nova/tests/integrated/api_samples/os-agents/agent-post-req.xml.tpl
new file mode 100644
index 000000000..5c777749a
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-agents/agent-post-req.xml.tpl
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<agent>
+ <hypervisor>%(hypervisor)s</hypervisor>
+ <os>%(os)s</os>
+ <architecture>%(architecture)s</architecture>
+ <version>%(version)s</version>
+ <md5hash>%(md5hash)s</md5hash>
+ <url>%(url)s</url>
+</agent>
diff --git a/nova/tests/integrated/api_samples/os-agents/agent-post-resp.json.tpl b/nova/tests/integrated/api_samples/os-agents/agent-post-resp.json.tpl
new file mode 100644
index 000000000..abe83564f
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-agents/agent-post-resp.json.tpl
@@ -0,0 +1,12 @@
+{
+ "agent": {
+ "hypervisor": "%(hypervisor)s",
+ "os": "%(os)s",
+ "architecture": "%(architecture)s",
+ "version": "%(version)s",
+ "md5hash": "%(md5hash)s",
+ "url": "%(url)s",
+ "agent_id": "%(agent_id)d"
+ }
+}
+
diff --git a/nova/tests/integrated/api_samples/os-agents/agent-post-resp.xml.tpl b/nova/tests/integrated/api_samples/os-agents/agent-post-resp.xml.tpl
new file mode 100644
index 000000000..ecf97b91e
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-agents/agent-post-resp.xml.tpl
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<agent>
+ <url>%(url)s</url>
+ <hypervisor>%(hypervisor)s</hypervisor>
+ <md5hash>%(md5hash)s</md5hash>
+ <version>%(version)s</version>
+ <architecture>%(architecture)s</architecture>
+ <os>%(os)s</os>
+ <agent_id>%(agent_id)d</agent_id>
+</agent>
diff --git a/nova/tests/integrated/api_samples/os-agents/agent-update-put-req.json.tpl b/nova/tests/integrated/api_samples/os-agents/agent-update-put-req.json.tpl
new file mode 100644
index 000000000..d447350e0
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-agents/agent-update-put-req.json.tpl
@@ -0,0 +1,7 @@
+{
+ "para": {
+ "url": "%(url)s",
+ "md5hash": "%(md5hash)s",
+ "version": "%(version)s"
+ }
+}
diff --git a/nova/tests/integrated/api_samples/os-agents/agent-update-put-req.xml.tpl b/nova/tests/integrated/api_samples/os-agents/agent-update-put-req.xml.tpl
new file mode 100644
index 000000000..19751dc80
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-agents/agent-update-put-req.xml.tpl
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<para>
+ <version>%(version)s</version>
+ <url>%(url)s</url>
+ <md5hash>%(md5hash)s</md5hash>
+</para>
diff --git a/nova/tests/integrated/api_samples/os-agents/agent-update-put-resp.json.tpl b/nova/tests/integrated/api_samples/os-agents/agent-update-put-resp.json.tpl
new file mode 100644
index 000000000..110e52cd3
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-agents/agent-update-put-resp.json.tpl
@@ -0,0 +1,8 @@
+{
+ "agent": {
+ "agent_id": "%(agent_id)d",
+ "url": "%(url)s",
+ "md5hash": "%(md5hash)s",
+ "version": "%(version)s"
+ }
+}
diff --git a/nova/tests/integrated/api_samples/os-agents/agent-update-put-resp.xml.tpl b/nova/tests/integrated/api_samples/os-agents/agent-update-put-resp.xml.tpl
new file mode 100644
index 000000000..2c9e50572
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-agents/agent-update-put-resp.xml.tpl
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<agent>
+ <agent_id>%(agent_id)d</agent_id>
+ <version>%(version)s</version>
+ <url>%(url)s</url>
+ <md5hash>%(md5hash)s</md5hash>
+</agent>
diff --git a/nova/tests/integrated/api_samples/os-agents/agents-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-agents/agents-get-resp.json.tpl
new file mode 100644
index 000000000..dac1f76ff
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-agents/agents-get-resp.json.tpl
@@ -0,0 +1,13 @@
+{
+ "agents": [
+ {
+ "hypervisor": "%(hypervisor)s",
+ "os": "%(os)s",
+ "architecture": "%(architecture)s",
+ "version": "%(version)s",
+ "md5hash": "%(md5hash)s",
+ "url": "%(url)s",
+ "agent_id": "%(agent_id)d"
+ }
+ ]
+}
diff --git a/nova/tests/integrated/api_samples/os-agents/agents-get-resp.xml.tpl b/nova/tests/integrated/api_samples/os-agents/agents-get-resp.xml.tpl
new file mode 100644
index 000000000..fbbbdad28
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-agents/agents-get-resp.xml.tpl
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<agents>
+ <agent hypervisor="%(hypervisor)s" os="%(os)s" architecture="%(architecture)s" version="%(version)s" md5hash="%(md5hash)s" url="%(url)s" agent_id="%(agent_id)d"/>
+</agents>
diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py
index 1fbf16fd3..4142e058f 100644
--- a/nova/tests/integrated/test_api_samples.py
+++ b/nova/tests/integrated/test_api_samples.py
@@ -26,6 +26,7 @@ from nova.cloudpipe.pipelib import CloudPipe
from nova.compute import api
from nova import context
from nova import db
+from nova.db.sqlalchemy import models
from nova.network.manager import NetworkManager
from nova.openstack.common import cfg
from nova.openstack.common import importutils
@@ -1284,6 +1285,109 @@ class CloudPipeUpdateXmlTest(CloudPipeUpdateJsonTest):
ctype = "xml"
+class AgentsJsonTest(ApiSampleTestBase):
+ extension_name = "nova.api.openstack.compute.contrib.agents.Agents"
+
+ def _get_flags(self):
+ f = super(AgentsJsonTest, self)._get_flags()
+ f['osapi_compute_extension'] = CONF.osapi_compute_extension[:]
+ return f
+
+ def setUp(self):
+ super(AgentsJsonTest, self).setUp()
+
+ fake_agents_list = [{'url': 'xxxxxxxxxxxx',
+ 'hypervisor': 'hypervisor',
+ '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.stubs.Set(db, "agent_build_create",
+ fake_agent_build_create)
+ self.stubs.Set(db, "agent_build_get_all",
+ fake_agent_build_get_all)
+ self.stubs.Set(db, "agent_build_update",
+ fake_agent_build_update)
+ self.stubs.Set(db, "agent_build_destroy",
+ fake_agent_build_destroy)
+
+ def test_agent_create(self):
+ """Creates a new agent build."""
+ project = {'url': 'xxxxxxxxxxxx',
+ 'hypervisor': 'hypervisor',
+ 'architecture': 'x86',
+ 'os': 'os',
+ 'version': '8.0',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f545'
+ }
+ response = self._do_post('os-agents', 'agent-post-req',
+ project)
+ self.assertEqual(response.status, 200)
+ project['agent_id'] = 1
+ self._verify_response('agent-post-resp', project, response)
+ return project
+
+ def test_agent_list(self):
+ """ Return a list of all agent builds."""
+ response = self._do_get('os-agents')
+ self.assertEqual(response.status, 200)
+ project = {'url': 'xxxxxxxxxxxx',
+ 'hypervisor': 'hypervisor',
+ 'architecture': 'x86',
+ 'os': 'os',
+ 'version': '8.0',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f545',
+ 'agent_id': 1
+ }
+ return self._verify_response('agents-get-resp', project, response)
+
+ def test_agent_update(self):
+ """Update an existing agent build."""
+ agent_id = 1
+ subs = {'version': '7.0',
+ 'url': 'xxx://xxxx/xxx/xxx',
+ 'md5hash': 'add6bb58e139be103324d04d82d8f545'}
+ response = self._do_put('os-agents/%s' % agent_id,
+ 'agent-update-put-req', subs)
+ self.assertEqual(response.status, 200)
+ subs['agent_id'] = 1
+ return self._verify_response('agent-update-put-resp', subs, response)
+
+ def test_agent_delete(self):
+ """Deletes an existing agent build."""
+ agent_id = 1
+ response = self._do_delete('os-agents/%s' % agent_id)
+ self.assertEqual(response.status, 200)
+
+
+class AgentsXmlTest(AgentsJsonTest):
+ ctype = "xml"
+
+
class AggregatesSampleJsonTest(ServersSampleBase):
extension_name = "nova.api.openstack.compute.contrib" + \
".aggregates.Aggregates"