Merged trunk.

This commit is contained in:
Brian Lamar
2011-09-07 14:18:45 -04:00
16 changed files with 216 additions and 55 deletions

View File

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

View File

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

View File

@@ -1020,14 +1020,6 @@ class CloudController(object):
'status': volume['attach_status'],
'volumeId': ec2utils.id_to_ec2_vol_id(volume_id)}
@staticmethod
def _convert_to_set(lst, label):
if lst is None or lst == []:
return None
if not isinstance(lst, list):
lst = [lst]
return [{label: x} for x in lst]
def _format_kernel_id(self, instance_ref, result, key):
kernel_id = instance_ref['kernel_id']
if kernel_id is None:
@@ -1186,7 +1178,7 @@ class CloudController(object):
if instance.get('security_groups'):
for security_group in instance['security_groups']:
security_group_names.append(security_group['name'])
result['groupSet'] = CloudController._convert_to_set(
result['groupSet'] = utils.convert_to_list_dict(
security_group_names, 'groupId')
def _format_instances(self, context, instance_id=None, use_v6=False,
@@ -1250,7 +1242,8 @@ class CloudController(object):
i['keyName'] = '%s (%s, %s)' % (i['keyName'],
instance['project_id'],
instance['host'])
i['productCodesSet'] = self._convert_to_set([], 'product_codes')
i['productCodesSet'] = utils.convert_to_list_dict([],
'product_codes')
self._format_instance_type(instance, i)
i['launchTime'] = instance['created_at']
i['amiLaunchIndex'] = instance['launch_index']

View File

@@ -14,18 +14,34 @@
# License for the specific language governing permissions and limitations
# under the License
from nova import utils
from nova.api.openstack import create_instance_helper as helper
from nova.api.openstack import extensions
from nova.api.openstack import servers
from nova.api.openstack import wsgi
class CreateServerController(servers.ControllerV11):
def _build_view(self, req, instance, is_detail=False):
server = super(CreateServerController, self)._build_view(req,
instance,
is_detail)
if is_detail:
self._build_security_groups(server['server'], instance)
return server
def _build_security_groups(self, response, inst):
sg_names = []
sec_groups = inst.get('security_groups')
if sec_groups:
sg_names = [sec_group['name'] for sec_group in sec_groups]
response['security_groups'] = utils.convert_to_list_dict(sg_names,
'name')
class Createserverext(extensions.ExtensionDescriptor):
"""The servers create ext
Exposes addFixedIp and removeFixedIp actions on servers.
"""
"""The servers create ext"""
def get_name(self):
return "Createserverext"
@@ -58,7 +74,7 @@ class Createserverext(extensions.ExtensionDescriptor):
deserializer = wsgi.RequestDeserializer(body_deserializers)
res = extensions.ResourceExtension('os-create-server-ext',
controller=servers.ControllerV11(),
controller=CreateServerController(),
deserializer=deserializer,
serializer=serializer)
resources.append(res)

View File

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

View File

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

View File

@@ -928,6 +928,11 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer):
server['addresses'])
server_node.appendChild(addresses_node)
if 'security_groups' in server:
security_groups_node = self._create_security_groups_node(xml_doc,
server['security_groups'])
server_node.appendChild(security_groups_node)
return server_node
def _server_list_to_xml(self, xml_doc, servers, detailed):
@@ -980,6 +985,19 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer):
server_dict['server'])
return self.to_xml_string(node, True)
def _security_group_to_xml(self, doc, security_group):
node = doc.createElement('security_group')
node.setAttribute('name', str(security_group.get('name')))
return node
def _create_security_groups_node(self, xml_doc, security_groups):
security_groups_node = xml_doc.createElement('security_groups')
if security_groups:
for security_group in security_groups:
node = self._security_group_to_xml(xml_doc, security_group)
security_groups_node.appendChild(node)
return security_groups_node
def create_resource(version='1.0'):
controller = {

View File

@@ -383,10 +383,6 @@ class API(base.Base):
If you are changing this method, be sure to update both
call paths.
"""
instance = dict(launch_index=num, **base_options)
instance = self.db.instance_create(context, instance)
instance_id = instance['id']
elevated = context.elevated()
if security_group is None:
security_group = ['default']
@@ -400,6 +396,10 @@ class API(base.Base):
security_group_name)
security_groups.append(group['id'])
instance = dict(launch_index=num, **base_options)
instance = self.db.instance_create(context, instance)
instance_id = instance['id']
for security_group_id in security_groups:
self.db.instance_add_security_group(elevated,
instance_id,

View File

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

View File

@@ -32,6 +32,12 @@ from nova import exception
from nova import flags
import nova.scheduler
# NOTE(Vek): Even though we don't use filters in here anywhere, we
# depend on default_host_filter being available in FLAGS,
# and that happens only when filters/abstract_filter.py is
# imported.
from nova.scheduler import filters
FLAGS = flags.FLAGS

View File

@@ -93,12 +93,14 @@ class SchedulerManager(manager.Manager):
driver_method = 'schedule_%s' % method
elevated = context.elevated()
try:
host = getattr(self.driver, driver_method)(elevated, *args,
**kwargs)
real_meth = getattr(self.driver, driver_method)
args = (elevated,) + args
except AttributeError, e:
LOG.warning(_("Driver Method %(driver_method)s missing: %(e)s."
"Reverting to schedule()") % locals())
host = self.driver.schedule(elevated, topic, *args, **kwargs)
"Reverting to schedule()") % locals())
real_meth = self.driver.schedule
args = (elevated, topic) + args
host = real_meth(*args, **kwargs)
if not host:
LOG.debug(_("%(topic)s %(method)s handled in Scheduler")

View File

@@ -16,6 +16,7 @@
# under the License.
import base64
import datetime
import json
import unittest
from xml.dom import minidom
@@ -27,15 +28,7 @@ from nova import db
from nova import exception
from nova import flags
from nova import test
from nova import utils
import nova.api.openstack
from nova.api.openstack import servers
from nova.api.openstack.contrib import createserverext
import nova.compute.api
import nova.scheduler.api
import nova.image.fake
import nova.rpc
from nova.tests.api.openstack import fakes
@@ -52,22 +45,45 @@ DUPLICATE_NETWORKS = [('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', '10.0.1.12'),
INVALID_NETWORKS = [('invalid', 'invalid-ip-address')]
INSTANCE = {
"id": 1,
"display_name": "test_server",
"uuid": FAKE_UUID,
"created_at": datetime.datetime(2010, 10, 10, 12, 0, 0),
"updated_at": datetime.datetime(2010, 11, 11, 11, 0, 0),
"security_groups": [{"id": 1, "name": "test"}]
}
def return_server_by_id(context, id, session=None):
INSTANCE['id'] = id
return INSTANCE
def return_security_group_non_existing(context, project_id, group_name):
raise exception.SecurityGroupNotFoundForProject(project_id=project_id,
security_group_id=group_name)
def return_security_group_get_by_name(context, project_id, group_name):
return {'id': 1, 'name': group_name}
def return_security_group_get(context, security_group_id, session):
return {'id': security_group_id}
def return_instance_add_security_group(context, instance_id,
security_group_id):
pass
class CreateserverextTest(test.TestCase):
def setUp(self):
super(CreateserverextTest, self).setUp()
self.stubs = stubout.StubOutForTesting()
fakes.FakeAuthManager.auth_data = {}
fakes.FakeAuthDatabase.data = {}
fakes.stub_out_auth(self.stubs)
fakes.stub_out_image_service(self.stubs)
fakes.stub_out_key_pair_funcs(self.stubs)
self.allow_admin = FLAGS.allow_admin_api
def tearDown(self):
self.stubs.UnsetAll()
FLAGS.allow_admin_api = self.allow_admin
super(CreateserverextTest, self).tearDown()
def _setup_mock_compute_api(self):
@@ -114,6 +130,18 @@ class CreateserverextTest(test.TestCase):
'_get_kernel_ramdisk_from_image', make_stub_method((1, 1)))
return compute_api
def _create_security_group_request_dict(self, security_groups):
server = {}
server['name'] = 'new-server-test'
server['imageRef'] = 1
server['flavorRef'] = 1
if security_groups is not None:
sg_list = []
for name in security_groups:
sg_list.append({'name': name})
server['security_groups'] = sg_list
return {'server': server}
def _create_networks_request_dict(self, networks):
server = {}
server['name'] = 'new-server-test'
@@ -348,3 +376,38 @@ class CreateserverextTest(test.TestCase):
self._create_instance_with_user_data_json(user_data_contents)
self.assertEquals(response.status_int, 400)
self.assertEquals(user_data, None)
def test_create_instance_with_security_group_json(self):
security_groups = ['test', 'test1']
self.stubs.Set(nova.db.api, 'security_group_get_by_name',
return_security_group_get_by_name)
self.stubs.Set(nova.db.api, 'instance_add_security_group',
return_instance_add_security_group)
body_dict = self._create_security_group_request_dict(security_groups)
request = self._get_create_request_json(body_dict)
response = request.get_response(fakes.wsgi_app())
self.assertEquals(response.status_int, 202)
def test_get_server_by_id_verify_security_groups_json(self):
self.stubs.Set(nova.db.api, 'instance_get', return_server_by_id)
req = webob.Request.blank('/v1.1/123/os-create-server-ext/1')
req.headers['Content-Type'] = 'application/json'
response = req.get_response(fakes.wsgi_app())
self.assertEquals(response.status_int, 200)
res_dict = json.loads(response.body)
expected_security_group = [{"name": "test"}]
self.assertEquals(res_dict['server']['security_groups'],
expected_security_group)
def test_get_server_by_id_verify_security_groups_xml(self):
self.stubs.Set(nova.db.api, 'instance_get', return_server_by_id)
req = webob.Request.blank('/v1.1/123/os-create-server-ext/1')
req.headers['Accept'] = 'application/xml'
response = req.get_response(fakes.wsgi_app())
self.assertEquals(response.status_int, 200)
dom = minidom.parseString(response.body)
server = dom.childNodes[0]
sec_groups = server.getElementsByTagName('security_groups')[0]
sec_group = sec_groups.getElementsByTagName('security_group')[0]
self.assertEqual(INSTANCE['security_groups'][0]['name'],
sec_group.getAttribute("name"))

View File

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

View File

@@ -161,6 +161,19 @@ class ComputeTestCase(test.TestCase):
db.security_group_destroy(self.context, group['id'])
db.instance_destroy(self.context, ref[0]['id'])
def test_create_instance_with_invalid_security_group_raises(self):
instance_type = instance_types.get_default_instance_type()
pre_build_len = len(db.instance_get_all(context.get_admin_context()))
self.assertRaises(exception.SecurityGroupNotFoundForProject,
self.compute_api.create,
self.context,
instance_type=instance_type,
image_href=None,
security_group=['this_is_a_fake_sec_group'])
self.assertEqual(pre_build_len,
len(db.instance_get_all(context.get_admin_context())))
def test_create_instance_associates_config_drive(self):
"""Make sure create associates a config drive."""

View File

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

View File

@@ -901,3 +901,12 @@ def monkey_patch():
func = import_class("%s.%s" % (module, key))
setattr(sys.modules[module], key,\
decorator("%s.%s" % (module, key), func))
def convert_to_list_dict(lst, label):
"""Convert a value or list into a list of dicts"""
if not lst:
return None
if not isinstance(lst, list):
lst = [lst]
return [{label: x} for x in lst]