From 99f3822fd3341eecb4bc8d699b9721fdf59aeee8 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Fri, 4 May 2012 14:36:52 -0700 Subject: [PATCH] Remove instance action logging mechanism * Remove InstanceActions db model * Remove relevant db api functions * Add migration 93 which drops the instance_actions * Remove server_action_list API extension * Fixes bug 994846 Change-Id: Ibbd787183034314460f41c84b9ad152655739209 --- etc/nova/policy.json | 1 - .../compute/contrib/server_action_list.py | 78 --------------- nova/compute/api.py | 5 - nova/db/api.py | 10 -- nova/db/sqlalchemy/api.py | 21 ---- .../093_drop_instance_actions_table.py | 52 ++++++++++ nova/db/sqlalchemy/models.py | 10 -- .../contrib/test_server_action_list.py | 99 ------------------- .../api/openstack/compute/test_extensions.py | 1 - nova/tests/policy.json | 2 - nova/tests/test_compute.py | 21 ---- nova/tests/vmwareapi/db_fakes.py | 5 - nova/virt/vmwareapi_conn.py | 6 -- 13 files changed, 52 insertions(+), 259 deletions(-) delete mode 100644 nova/api/openstack/compute/contrib/server_action_list.py create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/093_drop_instance_actions_table.py delete mode 100644 nova/tests/api/openstack/compute/contrib/test_server_action_list.py diff --git a/etc/nova/policy.json b/etc/nova/policy.json index 481620a096e5..aa44be0bd4bd 100644 --- a/etc/nova/policy.json +++ b/etc/nova/policy.json @@ -47,7 +47,6 @@ "compute_extension:quota_classes": [], "compute_extension:rescue": [], "compute_extension:security_groups": [], - "compute_extension:server_action_list": [["rule:admin_api"]], "compute_extension:server_diagnostics": [["rule:admin_api"]], "compute_extension:simple_tenant_usage:show": [["rule:admin_or_owner"]], "compute_extension:simple_tenant_usage:list": [["rule:admin_api"]], diff --git a/nova/api/openstack/compute/contrib/server_action_list.py b/nova/api/openstack/compute/contrib/server_action_list.py deleted file mode 100644 index 55c167442df4..000000000000 --- a/nova/api/openstack/compute/contrib/server_action_list.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2011 OpenStack LLC. -# 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 compute -from nova import exception - - -sa_nsmap = {None: wsgi.XMLNS_V11} -authorize = extensions.extension_authorizer('compute', 'server_action_list') - - -class ServerActionsTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('actions') - elem = xmlutil.SubTemplateElement(root, 'action', selector='actions') - elem.set('created_at') - elem.set('action') - elem.set('error') - return xmlutil.MasterTemplate(root, 1, nsmap=sa_nsmap) - - -class ServerActionListController(object): - @wsgi.serializers(xml=ServerActionsTemplate) - def index(self, req, server_id): - context = req.environ["nova.context"] - authorize(context) - compute_api = compute.API() - - try: - instance = compute_api.get(context, server_id) - except exception.NotFound: - raise webob.exc.HTTPNotFound(_("Instance not found")) - - items = compute_api.get_actions(context, instance) - - def _format_item(item): - return { - 'created_at': str(item['created_at']), - 'action': item['action'], - 'error': item['error'], - } - - return {'actions': [_format_item(item) for item in items]} - - -class Server_action_list(extensions.ExtensionDescriptor): - """Allow Admins to view pending server actions""" - - name = "ServerActionList" - alias = "os-server-action-list" - namespace = ("http://docs.openstack.org/compute/ext/" - "server-actions-list/api/v1.1") - updated = "2011-12-21T00:00:00+00:00" - - def get_resources(self): - parent_def = {'member_name': 'server', 'collection_name': 'servers'} - #NOTE(bcwaldon): This should be prefixed with 'os-' - ext = extensions.ResourceExtension('actions', - ServerActionListController(), - parent=parent_def) - return [ext] diff --git a/nova/compute/api.py b/nova/compute/api.py index 6c6afa6b34fb..b54aa1b57a55 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1515,11 +1515,6 @@ class API(BaseAPI): return self._call_compute_message("get_diagnostics", context, instance) - @wrap_check_policy - def get_actions(self, context, instance): - """Retrieve actions for the given instance.""" - return self.db.instance_get_actions(context, instance['uuid']) - @wrap_check_policy @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.SHUTOFF, vm_states.RESCUED], diff --git a/nova/db/api.py b/nova/db/api.py index 34de50faa0de..93eea8f10239 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -623,16 +623,6 @@ def instance_remove_security_group(context, instance_id, security_group_id): security_group_id) -def instance_action_create(context, values): - """Create an instance action from the values dictionary.""" - return IMPL.instance_action_create(context, values) - - -def instance_get_actions(context, instance_uuid): - """Get instance actions by instance uuid.""" - return IMPL.instance_get_actions(context, instance_uuid) - - def instance_get_id_to_uuid_mapping(context, ids): """Return a dictionary containing 'ID: UUID' given the ids""" return IMPL.instance_get_id_to_uuid_mapping(context, ids) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 02c835515d83..46e080578dde 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1681,27 +1681,6 @@ def instance_remove_security_group(context, instance_uuid, security_group_id): 'updated_at': literal_column('updated_at')}) -@require_context -def instance_action_create(context, values): - """Create an instance action from the values dictionary.""" - action_ref = models.InstanceActions() - action_ref.update(values) - - session = get_session() - with session.begin(): - action_ref.save(session=session) - return action_ref - - -@require_admin_context -def instance_get_actions(context, instance_uuid): - """Return the actions associated to the given instance id""" - session = get_session() - return session.query(models.InstanceActions).\ - filter_by(instance_uuid=instance_uuid).\ - all() - - @require_context def instance_get_id_to_uuid_mapping(context, ids): session = get_session() diff --git a/nova/db/sqlalchemy/migrate_repo/versions/093_drop_instance_actions_table.py b/nova/db/sqlalchemy/migrate_repo/versions/093_drop_instance_actions_table.py new file mode 100644 index 000000000000..dc69607f6214 --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/093_drop_instance_actions_table.py @@ -0,0 +1,52 @@ +# Copyright 2012 Openstack, LLC. +# 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 sqlalchemy import Boolean, Column, DateTime, ForeignKey +from sqlalchemy import Integer, MetaData, String, Table, Text + + +def upgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + instance_actions = Table('instance_actions', meta, autoload=True) + instance_actions.drop() + + +def downgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + instances = Table('instances', meta, autoload=True, + autoload_with=migrate_engine) + + instance_actions = Table('instance_actions', meta, + Column('created_at', DateTime(timezone=False)), + Column('updated_at', DateTime(timezone=False)), + Column('deleted_at', DateTime(timezone=False)), + Column('deleted', Boolean(create_constraint=True, name=None)), + Column('id', Integer(), primary_key=True, nullable=False), + Column('instance_id', + Integer(), + ForeignKey('instances.id')), + Column('action', + String(length=255, convert_unicode=False, + assert_unicode=None, + unicode_error=None, _warn_on_bytestring=False)), + Column('error', + Text(length=None, convert_unicode=False, + assert_unicode=None, + unicode_error=None, _warn_on_bytestring=False)), + ) + instance_actions.create() diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index e35a78257a1e..9007de424860 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -300,15 +300,6 @@ class InstanceInfoCache(BASE, NovaBase): primaryjoin=instance_id == Instance.uuid) -class InstanceActions(BASE, NovaBase): - """Represents a guest VM's actions and results""" - __tablename__ = "instance_actions" - id = Column(Integer, primary_key=True) - instance_uuid = Column(String(36), ForeignKey('instances.uuid')) - action = Column(String(255)) - error = Column(Text) - - class InstanceTypes(BASE, NovaBase): """Represent possible instance_types or flavor of VM offered""" __tablename__ = "instance_types" @@ -1051,7 +1042,6 @@ def register_models(): FixedIp, FloatingIp, Instance, - InstanceActions, InstanceFault, InstanceMetadata, InstanceTypeExtraSpecs, diff --git a/nova/tests/api/openstack/compute/contrib/test_server_action_list.py b/nova/tests/api/openstack/compute/contrib/test_server_action_list.py deleted file mode 100644 index 14ea2972c677..000000000000 --- a/nova/tests/api/openstack/compute/contrib/test_server_action_list.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright 2011 Eldar Nugaev -# 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 datetime -import json -import unittest - -from lxml import etree - -from nova.api.openstack import compute -from nova.api.openstack.compute import extensions -from nova.api.openstack.compute.contrib import server_action_list -from nova.api.openstack import wsgi -import nova.compute -from nova import test -from nova.tests.api.openstack import fakes -import nova.utils - - -dt = datetime.datetime.utcnow() - - -def fake_get_actions(self, _context, instance_uuid): - return [ - {'action': 'rebuild', 'error': None, 'created_at': dt}, - {'action': 'reboot', 'error': 'Failed!', 'created_at': dt}, - ] - - -def fake_instance_get(self, _context, instance_uuid): - return {'uuid': instance_uuid} - - -class ServerActionsTest(test.TestCase): - - def setUp(self): - super(ServerActionsTest, self).setUp() - self.flags(verbose=True) - self.stubs.Set(nova.compute.API, 'get_actions', fake_get_actions) - self.stubs.Set(nova.compute.API, 'get', fake_instance_get) - - self.router = compute.APIRouter() - - def test_get_actions(self): - uuid = nova.utils.gen_uuid() - req = fakes.HTTPRequest.blank('/fake/servers/%s/actions' % uuid) - res = req.get_response(self.router) - output = json.loads(res.body) - expected = {'actions': [ - {'action': 'rebuild', 'error': None, 'created_at': str(dt)}, - {'action': 'reboot', 'error': 'Failed!', 'created_at': str(dt)}, - ]} - self.assertEqual(output, expected) - - -class TestServerActionsXMLSerializer(unittest.TestCase): - namespace = wsgi.XMLNS_V11 - - def _tag(self, elem): - tagname = elem.tag - self.assertEqual(tagname[0], '{') - tmp = tagname.partition('}') - namespace = tmp[0][1:] - self.assertEqual(namespace, self.namespace) - return tmp[2] - - def test_index_serializer(self): - serializer = server_action_list.ServerActionsTemplate() - exemplar = [dict( - created_at=datetime.datetime.now(), - action='foo', - error='quxx'), - dict( - created_at=datetime.datetime.now(), - action='bar', - error='xxuq')] - text = serializer.serialize(dict(actions=exemplar)) - - print text - tree = etree.fromstring(text) - - self.assertEqual('actions', self._tag(tree)) - self.assertEqual(len(tree), len(exemplar)) - for idx, child in enumerate(tree): - self.assertEqual('action', self._tag(child)) - for field in ('created_at', 'action', 'error'): - self.assertEqual(str(exemplar[idx][field]), child.get(field)) diff --git a/nova/tests/api/openstack/compute/test_extensions.py b/nova/tests/api/openstack/compute/test_extensions.py index 0db8c73951a4..4be7e9c581e0 100644 --- a/nova/tests/api/openstack/compute/test_extensions.py +++ b/nova/tests/api/openstack/compute/test_extensions.py @@ -180,7 +180,6 @@ class ExtensionControllerTest(ExtensionTestCase): "Rescue", "SchedulerHints", "SecurityGroups", - "ServerActionList", "ServerDiagnostics", "ServerStartStop", "SimpleTenantUsage", diff --git a/nova/tests/policy.json b/nova/tests/policy.json index 16c8066906b6..83929d0bf9eb 100644 --- a/nova/tests/policy.json +++ b/nova/tests/policy.json @@ -13,7 +13,6 @@ "compute:delete_instance_metadata": [], "compute:get_instance_faults": [], - "compute:get_actions": [], "compute:get_diagnostics": [], "compute:get_lock": [], @@ -104,7 +103,6 @@ "compute_extension:quota_classes": [], "compute_extension:rescue": [], "compute_extension:security_groups": [], - "compute_extension:server_action_list": [], "compute_extension:server_diagnostics": [], "compute_extension:simple_tenant_usage:show": [], "compute_extension:simple_tenant_usage:list": [], diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index b6b2271689ac..fad6ba5e1ec4 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -3362,27 +3362,6 @@ class ComputeAPITestCase(BaseTestCase): self.compute_api.get_diagnostics(self.context, instance) self.compute_api.delete(self.context, instance) - def test_get_actions(self): - - expected = [{'id': 1, - 'instance_id': 5, - 'action': 'rebuild', - 'error': '', - }] - - def fake_get_actions(context, instance): - return expected - - self.stubs.Set(nova.db, 'instance_get_actions', - fake_get_actions) - - instance = self._create_fake_instance() - context = self.context.elevated() - actual = self.compute_api.get_actions(context, instance) - self.assertEqual(expected, actual) - - self.compute_api.delete(self.context, instance) - def test_inject_file(self): """Ensure we can write a file to an instance""" instance = self._create_fake_instance() diff --git a/nova/tests/vmwareapi/db_fakes.py b/nova/tests/vmwareapi/db_fakes.py index ab2c015809bf..7911d3f37ffd 100644 --- a/nova/tests/vmwareapi/db_fakes.py +++ b/nova/tests/vmwareapi/db_fakes.py @@ -92,10 +92,6 @@ def stub_out_db_instance_api(stubs): 'vlan': 100} return FakeModel(fields) - def fake_instance_action_create(context, action): - """Stubs out the db.instance_action_create method.""" - pass - def fake_instance_type_get_all(context, inactive=0, filters=None): return INSTANCE_TYPES.values() @@ -104,6 +100,5 @@ def stub_out_db_instance_api(stubs): stubs.Set(db, 'instance_create', fake_instance_create) stubs.Set(db, 'network_get_by_instance', fake_network_get_by_instance) - stubs.Set(db, 'instance_action_create', fake_instance_action_create) stubs.Set(db, 'instance_type_get_all', fake_instance_type_get_all) stubs.Set(db, 'instance_type_get_by_name', fake_instance_type_get_by_name) diff --git a/nova/virt/vmwareapi_conn.py b/nova/virt/vmwareapi_conn.py index aeb94d8c7c53..7fde10e5d465 100644 --- a/nova/virt/vmwareapi_conn.py +++ b/nova/virt/vmwareapi_conn.py @@ -389,10 +389,6 @@ class VMWareAPISession(object): task_info = self._call_method(vim_util, "get_dynamic_property", task_ref, "Task", "info") task_name = task_info.name - action = dict( - instance_uuid=instance_uuid, - action=task_name[0:255], - error=None) if task_info.state in ['queued', 'running']: return elif task_info.state == 'success': @@ -401,11 +397,9 @@ class VMWareAPISession(object): done.send("success") else: error_info = str(task_info.error.localizedMessage) - action["error"] = error_info LOG.warn(_("Task [%(task_name)s] %(task_ref)s " "status: error %(error_info)s") % locals()) done.send_exception(exception.NovaException(error_info)) - db.instance_action_create(context.get_admin_context(), action) except Exception, excep: LOG.warn(_("In vmwareapi:_poll_task, Got this error %s") % excep) done.send_exception(excep)