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
This commit is contained in:
Brian Waldon 2012-05-04 14:36:52 -07:00
parent 7ad7e9049c
commit 99f3822fd3
13 changed files with 52 additions and 259 deletions

View File

@ -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"]],

View File

@ -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]

View File

@ -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],

View File

@ -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)

View File

@ -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()

View File

@ -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()

View File

@ -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,

View File

@ -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))

View File

@ -180,7 +180,6 @@ class ExtensionControllerTest(ExtensionTestCase):
"Rescue",
"SchedulerHints",
"SecurityGroups",
"ServerActionList",
"ServerDiagnostics",
"ServerStartStop",
"SimpleTenantUsage",

View File

@ -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": [],

View File

@ -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()

View File

@ -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)

View File

@ -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)