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 address,
print vpn['host'], print vpn['host'],
print ec2utils.id_to_ec2_id(vpn['id']), print ec2utils.id_to_ec2_id(vpn['id']),
print vpn['state_description'], print vpn['vm_state'],
print state print state
else: else:
print None print None
@@ -869,7 +869,7 @@ class VmCommands(object):
instance['hostname'], instance['hostname'],
instance['host'], instance['host'],
instance['instance_type'].name, instance['instance_type'].name,
instance['state_description'], instance['vm_state'],
instance['launched_at'], instance['launched_at'],
instance['image_ref'], instance['image_ref'],
instance['kernel_id'], instance['kernel_id'],
@@ -1223,7 +1223,7 @@ class VsaCommands(object):
type=vc['instance_type']['name'], type=vc['instance_type']['name'],
fl_ip=floating_addr, fl_ip=floating_addr,
fx_ip=fixed_addr, fx_ip=fixed_addr,
stat=vc['state_description'], stat=vc['vm_state'],
host=vc['host'], host=vc['host'],
time=str(vc['created_at'])) time=str(vc['created_at']))

View File

@@ -21,7 +21,6 @@ Admin API controller, exposed through http via the api worker.
""" """
import base64 import base64
import datetime
import netaddr import netaddr
import urllib import urllib
@@ -33,6 +32,7 @@ from nova import log as logging
from nova import utils from nova import utils
from nova.api.ec2 import ec2utils from nova.api.ec2 import ec2utils
from nova.auth import manager from nova.auth import manager
from nova.compute import vm_states
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
@@ -273,8 +273,7 @@ class AdminController(object):
"""Get the VPN instance for a project ID.""" """Get the VPN instance for a project ID."""
for instance in db.instance_get_all_by_project(context, project_id): for instance in db.instance_get_all_by_project(context, project_id):
if (instance['image_id'] == str(FLAGS.vpn_image_id) if (instance['image_id'] == str(FLAGS.vpn_image_id)
and not instance['state_description'] in and not instance['vm_state'] in [vm_states.DELETED]):
['shutting_down', 'shutdown']):
return instance return instance
def start_vpn(self, context, project): def start_vpn(self, context, project):

View File

@@ -1020,14 +1020,6 @@ class CloudController(object):
'status': volume['attach_status'], 'status': volume['attach_status'],
'volumeId': ec2utils.id_to_ec2_vol_id(volume_id)} '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): def _format_kernel_id(self, instance_ref, result, key):
kernel_id = instance_ref['kernel_id'] kernel_id = instance_ref['kernel_id']
if kernel_id is None: if kernel_id is None:
@@ -1186,7 +1178,7 @@ class CloudController(object):
if instance.get('security_groups'): if instance.get('security_groups'):
for security_group in instance['security_groups']: for security_group in instance['security_groups']:
security_group_names.append(security_group['name']) security_group_names.append(security_group['name'])
result['groupSet'] = CloudController._convert_to_set( result['groupSet'] = utils.convert_to_list_dict(
security_group_names, 'groupId') security_group_names, 'groupId')
def _format_instances(self, context, instance_id=None, use_v6=False, 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'], i['keyName'] = '%s (%s, %s)' % (i['keyName'],
instance['project_id'], instance['project_id'],
instance['host']) 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) self._format_instance_type(instance, i)
i['launchTime'] = instance['created_at'] i['launchTime'] = instance['created_at']
i['amiLaunchIndex'] = instance['launch_index'] i['amiLaunchIndex'] = instance['launch_index']

View File

@@ -14,18 +14,34 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License # under the License
from nova import utils
from nova.api.openstack import create_instance_helper as helper from nova.api.openstack import create_instance_helper as helper
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import servers from nova.api.openstack import servers
from nova.api.openstack import wsgi 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): class Createserverext(extensions.ExtensionDescriptor):
"""The servers create ext """The servers create ext"""
Exposes addFixedIp and removeFixedIp actions on servers.
"""
def get_name(self): def get_name(self):
return "Createserverext" return "Createserverext"
@@ -58,7 +74,7 @@ class Createserverext(extensions.ExtensionDescriptor):
deserializer = wsgi.RequestDeserializer(body_deserializers) deserializer = wsgi.RequestDeserializer(body_deserializers)
res = extensions.ResourceExtension('os-create-server-ext', res = extensions.ResourceExtension('os-create-server-ext',
controller=servers.ControllerV11(), controller=CreateServerController(),
deserializer=deserializer, deserializer=deserializer,
serializer=serializer) serializer=serializer)
resources.append(res) resources.append(res)

View File

@@ -116,7 +116,7 @@ class SimpleTenantUsageController(object):
if info['ended_at']: if info['ended_at']:
info['state'] = 'terminated' info['state'] = 'terminated'
else: else:
info['state'] = instance['state_description'] info['state'] = instance['vm_state']
now = datetime.utcnow() now = datetime.utcnow()

View File

@@ -94,7 +94,7 @@ class CreateInstanceHelper(object):
try: try:
image_service, image_id = nova.image.get_image_service(image_href) image_service, image_id = nova.image.get_image_service(image_href)
kernel_id, ramdisk_id = self._get_kernel_ramdisk_from_image( 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)]) images = set([str(x['id']) for x in image_service.index(context)])
assert str(image_id) in images assert str(image_id) in images
except Exception, e: except Exception, e:
@@ -247,12 +247,12 @@ class CreateInstanceHelper(object):
msg = _("Server name is an empty string") msg = _("Server name is an empty string")
raise exc.HTTPBadRequest(explanation=msg) 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 """Fetch an image from the ImageService, then if present, return the
associated kernel and ramdisk image IDs. associated kernel and ramdisk image IDs.
""" """
context = req.environ['nova.context'] 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 # NOTE(sirp): extracted to a separate method to aid unit-testing, the
# new method doesn't need a request obj or an ImageService stub # new method doesn't need a request obj or an ImageService stub
kernel_id, ramdisk_id = self._do_get_kernel_ramdisk_from_image( kernel_id, ramdisk_id = self._do_get_kernel_ramdisk_from_image(

View File

@@ -928,6 +928,11 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer):
server['addresses']) server['addresses'])
server_node.appendChild(addresses_node) 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 return server_node
def _server_list_to_xml(self, xml_doc, servers, detailed): def _server_list_to_xml(self, xml_doc, servers, detailed):
@@ -980,6 +985,19 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer):
server_dict['server']) server_dict['server'])
return self.to_xml_string(node, True) 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'): def create_resource(version='1.0'):
controller = { controller = {

View File

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

View File

@@ -280,6 +280,20 @@ class GlanceImageService(service.BaseImageService):
image_meta = _convert_from_string(image_meta) image_meta = _convert_from_string(image_meta)
return 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 # utility functions
def _convert_timestamps_to_datetimes(image_meta): def _convert_timestamps_to_datetimes(image_meta):

View File

@@ -32,6 +32,12 @@ from nova import exception
from nova import flags from nova import flags
import nova.scheduler 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 FLAGS = flags.FLAGS

View File

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

View File

@@ -16,6 +16,7 @@
# under the License. # under the License.
import base64 import base64
import datetime
import json import json
import unittest import unittest
from xml.dom import minidom from xml.dom import minidom
@@ -27,15 +28,7 @@ from nova import db
from nova import exception from nova import exception
from nova import flags from nova import flags
from nova import test from nova import test
from nova import utils
import nova.api.openstack 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 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')] 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): class CreateserverextTest(test.TestCase):
def setUp(self): def setUp(self):
super(CreateserverextTest, self).setUp() 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): def tearDown(self):
self.stubs.UnsetAll()
FLAGS.allow_admin_api = self.allow_admin
super(CreateserverextTest, self).tearDown() super(CreateserverextTest, self).tearDown()
def _setup_mock_compute_api(self): def _setup_mock_compute_api(self):
@@ -114,6 +130,18 @@ class CreateserverextTest(test.TestCase):
'_get_kernel_ramdisk_from_image', make_stub_method((1, 1))) '_get_kernel_ramdisk_from_image', make_stub_method((1, 1)))
return compute_api 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): def _create_networks_request_dict(self, networks):
server = {} server = {}
server['name'] = 'new-server-test' server['name'] = 'new-server-test'
@@ -348,3 +376,38 @@ class CreateserverextTest(test.TestCase):
self._create_instance_with_user_data_json(user_data_contents) self._create_instance_with_user_data_json(user_data_contents)
self.assertEquals(response.status_int, 400) self.assertEquals(response.status_int, 400)
self.assertEquals(user_data, None) 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 import unittest
from nova import context from nova import context
from nova import exception
from nova import test from nova import test
from nova.image import glance from nova.image import glance
@@ -105,6 +106,31 @@ class TestGlanceImageServiceProperties(BaseGlanceTest):
'properties': {'prop1': 'propvalue1', 'foo': 'bar'}} 'properties': {'prop1': 'propvalue1', 'foo': 'bar'}}
self.assertEqual(image_meta, expected) 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): def test_detail_passes_through_to_client(self):
fixtures = {'image1': {'id': '1', 'name': 'image1', 'is_public': True, fixtures = {'image1': {'id': '1', 'name': 'image1', 'is_public': True,
'foo': 'bar', 'foo': 'bar',

View File

@@ -161,6 +161,19 @@ class ComputeTestCase(test.TestCase):
db.security_group_destroy(self.context, group['id']) db.security_group_destroy(self.context, group['id'])
db.instance_destroy(self.context, ref[0]['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): def test_create_instance_associates_config_drive(self):
"""Make sure create associates a config drive.""" """Make sure create associates a config drive."""

View File

@@ -34,6 +34,7 @@ from nova import test
from nova import utils from nova import utils
from nova.api.ec2 import cloud from nova.api.ec2 import cloud
from nova.compute import power_state from nova.compute import power_state
from nova.compute import vm_states
from nova.virt.libvirt import connection from nova.virt.libvirt import connection
from nova.virt.libvirt import firewall from nova.virt.libvirt import firewall
@@ -674,8 +675,9 @@ class LibvirtConnTestCase(test.TestCase):
# Preparing data # Preparing data
self.compute = utils.import_object(FLAGS.compute_manager) self.compute = utils.import_object(FLAGS.compute_manager)
instance_dict = {'host': 'fake', 'state': power_state.RUNNING, instance_dict = {'host': 'fake',
'state_description': 'running'} 'power_state': power_state.RUNNING,
'vm_state': vm_states.ACTIVE}
instance_ref = db.instance_create(self.context, self.test_instance) instance_ref = db.instance_create(self.context, self.test_instance)
instance_ref = db.instance_update(self.context, instance_ref['id'], instance_ref = db.instance_update(self.context, instance_ref['id'],
instance_dict) instance_dict)
@@ -713,8 +715,8 @@ class LibvirtConnTestCase(test.TestCase):
self.compute.rollback_live_migration) self.compute.rollback_live_migration)
instance_ref = db.instance_get(self.context, instance_ref['id']) instance_ref = db.instance_get(self.context, instance_ref['id'])
self.assertTrue(instance_ref['state_description'] == 'running') self.assertTrue(instance_ref['vm_state'] == vm_states.ACTIVE)
self.assertTrue(instance_ref['state'] == power_state.RUNNING) self.assertTrue(instance_ref['power_state'] == power_state.RUNNING)
volume_ref = db.volume_get(self.context, volume_ref['id']) volume_ref = db.volume_get(self.context, volume_ref['id'])
self.assertTrue(volume_ref['status'] == 'in-use') self.assertTrue(volume_ref['status'] == 'in-use')

View File

@@ -901,3 +901,12 @@ def monkey_patch():
func = import_class("%s.%s" % (module, key)) func = import_class("%s.%s" % (module, key))
setattr(sys.modules[module], key,\ setattr(sys.modules[module], key,\
decorator("%s.%s" % (module, key), func)) 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]