diff --git a/doc/api_samples/all_extensions/extensions-get-resp.json b/doc/api_samples/all_extensions/extensions-get-resp.json index 399d937a7667..cf3d66a761bb 100644 --- a/doc/api_samples/all_extensions/extensions-get-resp.json +++ b/doc/api_samples/all_extensions/extensions-get-resp.json @@ -64,6 +64,14 @@ "namespace": "http://docs.openstack.org/compute/ext/admin-actions/api/v1.1", "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", diff --git a/doc/api_samples/all_extensions/extensions-get-resp.xml b/doc/api_samples/all_extensions/extensions-get-resp.xml index e4d3b8cc3106..44816c09cb1e 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 + + Agents support + Admin-only aggregate administration 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 000000000000..217993b17f72 --- /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 000000000000..be93e97ce432 --- /dev/null +++ b/doc/api_samples/os-agents/agent-post-req.xml @@ -0,0 +1,9 @@ + + + hypervisor + os + x86 + 8.0 + add6bb58e139be103324d04d82d8f545 + xxxxxxxxxxxx + \ 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 000000000000..418d11f5042f --- /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 000000000000..79f62b7fb92a --- /dev/null +++ b/doc/api_samples/os-agents/agent-post-resp.xml @@ -0,0 +1,10 @@ + + + xxxxxxxxxxxx + hypervisor + add6bb58e139be103324d04d82d8f545 + 8.0 + x86 + os + 1 + \ 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 000000000000..e4eaf535256f --- /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 000000000000..f759880c1728 --- /dev/null +++ b/doc/api_samples/os-agents/agent-update-put-req.xml @@ -0,0 +1,6 @@ + + + 7.0 + xxx://xxxx/xxx/xxx + add6bb58e139be103324d04d82d8f545 + \ 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 000000000000..6b67222c8c23 --- /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 000000000000..badf2750ea5d --- /dev/null +++ b/doc/api_samples/os-agents/agent-update-put-resp.xml @@ -0,0 +1,7 @@ + + + xxx://xxxx/xxx/xxx + 7.0 + 1 + add6bb58e139be103324d04d82d8f545 + \ 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 000000000000..36eac4ced7ba --- /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 000000000000..4194f62c965a --- /dev/null +++ b/doc/api_samples/os-agents/agents-get-resp.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/etc/nova/policy.json b/etc/nova/policy.json index 778203e756fc..942b74f66522 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 000000000000..218f06b52324 --- /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 ad928f5852e6..cfa6a6487711 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 c1b6e66dde4d..e8eea7d023a6 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 7629db9fe441..7477d9c63819 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 000000000000..60659b3c6aba --- /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 eab55f95e0a4..66dac3febe8a 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 b3ae0fa177df..7813cddc0d03 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 65cbb4889731..0b27896fd6a5 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 @@ -72,6 +72,14 @@ "namespace": "http://docs.openstack.org/compute/ext/aggregates/api/v1.1", "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", 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 bdef0266cfea..fec850997e1f 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 @@ %(text)s + + %(text)s + %(text)s 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 000000000000..6dbd2f17cbb5 --- /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 000000000000..5c777749a21d --- /dev/null +++ b/nova/tests/integrated/api_samples/os-agents/agent-post-req.xml.tpl @@ -0,0 +1,9 @@ + + + %(hypervisor)s + %(os)s + %(architecture)s + %(version)s + %(md5hash)s + %(url)s + 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 000000000000..abe83564f72b --- /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 000000000000..ecf97b91e958 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-agents/agent-post-resp.xml.tpl @@ -0,0 +1,10 @@ + + + %(url)s + %(hypervisor)s + %(md5hash)s + %(version)s + %(architecture)s + %(os)s + %(agent_id)d + 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 000000000000..d447350e0dfb --- /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 000000000000..19751dc80720 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-agents/agent-update-put-req.xml.tpl @@ -0,0 +1,6 @@ + + + %(version)s + %(url)s + %(md5hash)s + 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 000000000000..110e52cd3317 --- /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 000000000000..2c9e50572cf7 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-agents/agent-update-put-resp.xml.tpl @@ -0,0 +1,7 @@ + + + %(agent_id)d + %(version)s + %(url)s + %(md5hash)s + 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 000000000000..dac1f76ffb6f --- /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 000000000000..fbbbdad28850 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-agents/agents-get-resp.xml.tpl @@ -0,0 +1,4 @@ + + + + diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py index 4936ff2cbc45..9396583829b4 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"