summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbin/nova-manage6
-rw-r--r--nova/api/ec2/admin.py5
-rw-r--r--nova/api/openstack/contrib/simple_tenant_usage.py2
-rw-r--r--nova/api/openstack/create_instance_helper.py6
-rw-r--r--nova/api/openstack/servers.py24
-rw-r--r--nova/db/sqlalchemy/api.py12
-rw-r--r--nova/image/glance.py14
-rw-r--r--nova/tests/api/openstack/test_servers.py25
-rw-r--r--nova/tests/image/test_glance.py26
-rw-r--r--nova/tests/test_cloud.py7
-rw-r--r--nova/tests/test_db_api.py4
-rw-r--r--nova/tests/test_libvirt.py10
12 files changed, 109 insertions, 32 deletions
diff --git a/bin/nova-manage b/bin/nova-manage
index c9cf4266d..c3b2c71ce 100755
--- a/bin/nova-manage
+++ b/bin/nova-manage
@@ -166,7 +166,7 @@ class VpnCommands(object):
print address,
print vpn['host'],
print ec2utils.id_to_ec2_id(vpn['id']),
- print vpn['state_description'],
+ print vpn['vm_state'],
print state
else:
print None
@@ -869,7 +869,7 @@ class VmCommands(object):
instance['hostname'],
instance['host'],
instance['instance_type'].name,
- instance['state_description'],
+ instance['vm_state'],
instance['launched_at'],
instance['image_ref'],
instance['kernel_id'],
@@ -1223,7 +1223,7 @@ class VsaCommands(object):
type=vc['instance_type']['name'],
fl_ip=floating_addr,
fx_ip=fixed_addr,
- stat=vc['state_description'],
+ stat=vc['vm_state'],
host=vc['host'],
time=str(vc['created_at']))
diff --git a/nova/api/ec2/admin.py b/nova/api/ec2/admin.py
index dfbbc0a2b..75e029509 100644
--- a/nova/api/ec2/admin.py
+++ b/nova/api/ec2/admin.py
@@ -21,7 +21,6 @@ Admin API controller, exposed through http via the api worker.
"""
import base64
-import datetime
import netaddr
import urllib
@@ -33,6 +32,7 @@ from nova import log as logging
from nova import utils
from nova.api.ec2 import ec2utils
from nova.auth import manager
+from nova.compute import vm_states
FLAGS = flags.FLAGS
@@ -273,8 +273,7 @@ class AdminController(object):
"""Get the VPN instance for a project ID."""
for instance in db.instance_get_all_by_project(context, project_id):
if (instance['image_id'] == str(FLAGS.vpn_image_id)
- and not instance['state_description'] in
- ['shutting_down', 'shutdown']):
+ and not instance['vm_state'] in [vm_states.DELETED]):
return instance
def start_vpn(self, context, project):
diff --git a/nova/api/openstack/contrib/simple_tenant_usage.py b/nova/api/openstack/contrib/simple_tenant_usage.py
index 69b38e229..42691a9fa 100644
--- a/nova/api/openstack/contrib/simple_tenant_usage.py
+++ b/nova/api/openstack/contrib/simple_tenant_usage.py
@@ -116,7 +116,7 @@ class SimpleTenantUsageController(object):
if info['ended_at']:
info['state'] = 'terminated'
else:
- info['state'] = instance['state_description']
+ info['state'] = instance['vm_state']
now = datetime.utcnow()
diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py
index fd9247f79..29e071609 100644
--- a/nova/api/openstack/create_instance_helper.py
+++ b/nova/api/openstack/create_instance_helper.py
@@ -94,7 +94,7 @@ class CreateInstanceHelper(object):
try:
image_service, image_id = nova.image.get_image_service(image_href)
kernel_id, ramdisk_id = self._get_kernel_ramdisk_from_image(
- req, image_id)
+ req, image_service, image_id)
images = set([str(x['id']) for x in image_service.index(context)])
assert str(image_id) in images
except Exception, e:
@@ -247,12 +247,12 @@ class CreateInstanceHelper(object):
msg = _("Server name is an empty string")
raise exc.HTTPBadRequest(explanation=msg)
- def _get_kernel_ramdisk_from_image(self, req, image_id):
+ def _get_kernel_ramdisk_from_image(self, req, image_service, image_id):
"""Fetch an image from the ImageService, then if present, return the
associated kernel and ramdisk image IDs.
"""
context = req.environ['nova.context']
- image_meta = self._image_service.show(context, image_id)
+ image_meta = image_service.show(context, image_id)
# NOTE(sirp): extracted to a separate method to aid unit-testing, the
# new method doesn't need a request obj or an ImageService stub
kernel_id, ramdisk_id = self._do_get_kernel_ramdisk_from_image(
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index 1b3eddd05..977958f5d 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -106,6 +106,14 @@ class Controller(object):
raise exception.InvalidInput(reason=reason)
search_opts['vm_state'] = state
+ if 'changes-since' in search_opts:
+ try:
+ parsed = utils.parse_isotime(search_opts['changes-since'])
+ except ValueError:
+ msg = _('Invalid changes-since value')
+ raise exc.HTTPBadRequest(explanation=msg)
+ search_opts['changes-since'] = parsed
+
# By default, compute's get_all() will return deleted instances.
# If an admin hasn't specified a 'deleted' search option, we need
# to filter out deleted instances by setting the filter ourselves.
@@ -113,23 +121,17 @@ class Controller(object):
# should return recently deleted images according to the API spec.
if 'deleted' not in search_opts:
- # Admin hasn't specified deleted filter
if 'changes-since' not in search_opts:
- # No 'changes-since', so we need to find non-deleted servers
+ # No 'changes-since', so we only want non-deleted servers
search_opts['deleted'] = False
- else:
- # This is the default, but just in case..
- search_opts['deleted'] = True
-
- instance_list = self.compute_api.get_all(
- context, search_opts=search_opts)
- # FIXME(comstud): 'changes-since' is not fully implemented. Where
- # should this be filtered?
+ instance_list = self.compute_api.get_all(context,
+ search_opts=search_opts)
limited_list = self._limit_items(instance_list, req)
servers = [self._build_view(req, inst, is_detail)['server']
- for inst in limited_list]
+ for inst in limited_list]
+
return dict(servers=servers)
@scheduler_api.redirect_handler
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index c97ff5070..b99667afc 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -36,6 +36,7 @@ from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import joinedload
from sqlalchemy.orm import joinedload_all
from sqlalchemy.sql import func
+from sqlalchemy.sql.expression import desc
from sqlalchemy.sql.expression import literal_column
FLAGS = flags.FLAGS
@@ -1250,12 +1251,17 @@ def instance_get_all_by_filters(context, filters):
options(joinedload_all('fixed_ips.network')).\
options(joinedload('metadata')).\
options(joinedload('instance_type')).\
- filter_by(deleted=can_read_deleted(context))
+ order_by(desc(models.Instance.created_at))
# Make a copy of the filters dictionary to use going forward, as we'll
# be modifying it and we shouldn't affect the caller's use of it.
filters = filters.copy()
+ if 'changes-since' in filters:
+ changes_since = filters['changes-since']
+ query_prefix = query_prefix.\
+ filter(models.Instance.updated_at > changes_since)
+
if not context.is_admin:
# If we're not admin context, add appropriate filter..
if context.project_id:
@@ -1277,9 +1283,7 @@ def instance_get_all_by_filters(context, filters):
query_prefix = _exact_match_filter(query_prefix, filter_name,
filters.pop(filter_name))
- instances = query_prefix.\
- filter_by(deleted=can_read_deleted(context)).\
- all()
+ instances = query_prefix.all()
if not instances:
return []
diff --git a/nova/image/glance.py b/nova/image/glance.py
index 7233eb18d..80abc7384 100644
--- a/nova/image/glance.py
+++ b/nova/image/glance.py
@@ -280,6 +280,20 @@ class GlanceImageService(service.BaseImageService):
image_meta = _convert_from_string(image_meta)
return image_meta
+ @staticmethod
+ def _is_image_available(context, image_meta):
+ """Check image availability.
+
+ Under Glance, images are always available if the context has
+ an auth_token. Otherwise, we fall back to the superclass
+ method.
+
+ """
+ if hasattr(context, 'auth_token') and context.auth_token:
+ return True
+ return service.BaseImageService._is_image_available(context,
+ image_meta)
+
# utility functions
def _convert_timestamps_to_datetimes(image_meta):
diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py
index 412aa439c..1591ea56c 100644
--- a/nova/tests/api/openstack/test_servers.py
+++ b/nova/tests/api/openstack/test_servers.py
@@ -1265,6 +1265,31 @@ class ServersTest(test.TestCase):
self.assertEqual(len(servers), 1)
self.assertEqual(servers[0]['id'], 100)
+ def test_get_servers_allows_changes_since_v1_1(self):
+ def fake_get_all(compute_self, context, search_opts=None):
+ self.assertNotEqual(search_opts, None)
+ self.assertTrue('changes-since' in search_opts)
+ changes_since = datetime.datetime(2011, 1, 24, 17, 8, 1)
+ self.assertEqual(search_opts['changes-since'], changes_since)
+ self.assertTrue('deleted' not in search_opts)
+ return [stub_instance(100)]
+
+ self.stubs.Set(nova.compute.API, 'get_all', fake_get_all)
+
+ params = 'changes-since=2011-01-24T17:08:01Z'
+ req = webob.Request.blank('/v1.1/fake/servers?%s' % params)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ servers = json.loads(res.body)['servers']
+ self.assertEqual(len(servers), 1)
+ self.assertEqual(servers[0]['id'], 100)
+
+ def test_get_servers_allows_changes_since_bad_value_v1_1(self):
+ params = 'changes-since=asdf'
+ req = webob.Request.blank('/v1.1/fake/servers?%s' % params)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 400)
+
def test_get_servers_unknown_or_admin_options1(self):
"""Test getting servers by admin-only or unknown options.
This tests when admin_api is off. Make sure the admin and
diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py
index 5df25df37..b1ebd8436 100644
--- a/nova/tests/image/test_glance.py
+++ b/nova/tests/image/test_glance.py
@@ -20,6 +20,7 @@ import datetime
import unittest
from nova import context
+from nova import exception
from nova import test
from nova.image import glance
@@ -105,6 +106,31 @@ class TestGlanceImageServiceProperties(BaseGlanceTest):
'properties': {'prop1': 'propvalue1', 'foo': 'bar'}}
self.assertEqual(image_meta, expected)
+ def test_show_raises_when_no_authtoken_in_the_context(self):
+ fixtures = {'image1': {'name': 'image1', 'is_public': False,
+ 'foo': 'bar',
+ 'properties': {'prop1': 'propvalue1'}}}
+ self.client.images = fixtures
+ self.context.auth_token = False
+
+ expected = {'name': 'image1', 'is_public': True,
+ 'properties': {'prop1': 'propvalue1', 'foo': 'bar'}}
+ self.assertRaises(exception.ImageNotFound,
+ self.service.show, self.context, 'image1')
+
+ def test_show_passes_through_to_client_with_authtoken_in_context(self):
+ fixtures = {'image1': {'name': 'image1', 'is_public': False,
+ 'foo': 'bar',
+ 'properties': {'prop1': 'propvalue1'}}}
+ self.client.images = fixtures
+ self.context.auth_token = True
+
+ expected = {'name': 'image1', 'is_public': False,
+ 'properties': {'prop1': 'propvalue1', 'foo': 'bar'}}
+
+ image_meta = self.service.show(self.context, 'image1')
+ self.assertEqual(image_meta, expected)
+
def test_detail_passes_through_to_client(self):
fixtures = {'image1': {'id': '1', 'name': 'image1', 'is_public': True,
'foo': 'bar',
diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py
index 806c29e42..3fe6a9b42 100644
--- a/nova/tests/test_cloud.py
+++ b/nova/tests/test_cloud.py
@@ -486,8 +486,11 @@ class CloudTestCase(test.TestCase):
inst2 = db.instance_create(self.context, args2)
db.instance_destroy(self.context, inst1.id)
result = self.cloud.describe_instances(self.context)
- result = result['reservationSet'][0]['instancesSet']
- self.assertEqual(result[0]['instanceId'],
+ result1 = result['reservationSet'][0]['instancesSet']
+ self.assertEqual(result1[0]['instanceId'],
+ ec2utils.id_to_ec2_id(inst1.id))
+ result2 = result['reservationSet'][1]['instancesSet']
+ self.assertEqual(result2[0]['instanceId'],
ec2utils.id_to_ec2_id(inst2.id))
def _block_device_mapping_create(self, instance_id, mappings):
diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py
index 038c07f40..60d7abd8c 100644
--- a/nova/tests/test_db_api.py
+++ b/nova/tests/test_db_api.py
@@ -91,5 +91,7 @@ class DbApiTestCase(test.TestCase):
inst2 = db.instance_create(self.context, args2)
db.instance_destroy(self.context, inst1.id)
result = db.instance_get_all_by_filters(self.context.elevated(), {})
- self.assertEqual(1, len(result))
+ self.assertEqual(2, len(result))
self.assertEqual(result[0].id, inst2.id)
+ self.assertEqual(result[1].id, inst1.id)
+ self.assertTrue(result[1].deleted)
diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py
index 6a213b4f0..8c6775b29 100644
--- a/nova/tests/test_libvirt.py
+++ b/nova/tests/test_libvirt.py
@@ -34,6 +34,7 @@ from nova import test
from nova import utils
from nova.api.ec2 import cloud
from nova.compute import power_state
+from nova.compute import vm_states
from nova.virt.libvirt import connection
from nova.virt.libvirt import firewall
@@ -674,8 +675,9 @@ class LibvirtConnTestCase(test.TestCase):
# Preparing data
self.compute = utils.import_object(FLAGS.compute_manager)
- instance_dict = {'host': 'fake', 'state': power_state.RUNNING,
- 'state_description': 'running'}
+ instance_dict = {'host': 'fake',
+ 'power_state': power_state.RUNNING,
+ 'vm_state': vm_states.ACTIVE}
instance_ref = db.instance_create(self.context, self.test_instance)
instance_ref = db.instance_update(self.context, instance_ref['id'],
instance_dict)
@@ -713,8 +715,8 @@ class LibvirtConnTestCase(test.TestCase):
self.compute.rollback_live_migration)
instance_ref = db.instance_get(self.context, instance_ref['id'])
- self.assertTrue(instance_ref['state_description'] == 'running')
- self.assertTrue(instance_ref['state'] == power_state.RUNNING)
+ self.assertTrue(instance_ref['vm_state'] == vm_states.ACTIVE)
+ self.assertTrue(instance_ref['power_state'] == power_state.RUNNING)
volume_ref = db.volume_get(self.context, volume_ref['id'])
self.assertTrue(volume_ref['status'] == 'in-use')