merged trunk

This commit is contained in:
Chris Behrens
2011-07-07 05:56:15 -07:00
7 changed files with 340 additions and 23 deletions

View File

@@ -10,6 +10,7 @@ graft bzrplugins
graft contrib graft contrib
graft po graft po
graft plugins graft plugins
graft nova/api/openstack/schemas
include nova/api/openstack/notes.txt include nova/api/openstack/notes.txt
include nova/auth/*.schema include nova/auth/*.schema
include nova/auth/novarc.template include nova/auth/novarc.template

View File

@@ -726,8 +726,7 @@ class NetworkCommands(object):
network_size = FLAGS.network_size network_size = FLAGS.network_size
subnet = 32 - int(math.log(network_size, 2)) subnet = 32 - int(math.log(network_size, 2))
oversize_msg = _('Subnet(s) too large, defaulting to /%s.' oversize_msg = _('Subnet(s) too large, defaulting to /%s.'
' To override, specify network_size flag.' ' To override, specify network_size flag.') % subnet
) % subnet
print oversize_msg print oversize_msg
else: else:
network_size = fixnet.size network_size = fixnet.size
@@ -1120,10 +1119,12 @@ class InstanceTypeCommands(object):
@args('--name', dest='name', metavar='<name>', @args('--name', dest='name', metavar='<name>',
help='Name of instance type/flavor') help='Name of instance type/flavor')
def delete(self, name, purge=None): @args('--purge', action="store_true", dest='purge', default=False,
help='purge record from database')
def delete(self, name, purge):
"""Marks instance types / flavors as deleted""" """Marks instance types / flavors as deleted"""
try: try:
if purge == "--purge": if purge:
instance_types.purge(name) instance_types.purge(name)
verb = "purged" verb = "purged"
else: else:

View File

@@ -27,6 +27,7 @@ import random
import StringIO import StringIO
import webob import webob
from nova import block_device
from nova import context from nova import context
from nova import exception from nova import exception
from nova import test from nova import test
@@ -147,10 +148,12 @@ class Ec2utilsTestCase(test.TestCase):
properties0 = {'mappings': mappings} properties0 = {'mappings': mappings}
properties1 = {'root_device_name': '/dev/sdb', 'mappings': mappings} properties1 = {'root_device_name': '/dev/sdb', 'mappings': mappings}
root_device_name = ec2utils.properties_root_device_name(properties0) root_device_name = block_device.properties_root_device_name(
properties0)
self.assertEqual(root_device_name, '/dev/sda1') self.assertEqual(root_device_name, '/dev/sda1')
root_device_name = ec2utils.properties_root_device_name(properties1) root_device_name = block_device.properties_root_device_name(
properties1)
self.assertEqual(root_device_name, '/dev/sdb') self.assertEqual(root_device_name, '/dev/sdb')
def test_mapping_prepend_dev(self): def test_mapping_prepend_dev(self):
@@ -184,7 +187,7 @@ class Ec2utilsTestCase(test.TestCase):
'device': '/dev/sdc1'}, 'device': '/dev/sdc1'},
{'virtual': 'ephemeral1', {'virtual': 'ephemeral1',
'device': '/dev/sdc1'}] 'device': '/dev/sdc1'}]
self.assertDictListMatch(ec2utils.mappings_prepend_dev(mappings), self.assertDictListMatch(block_device.mappings_prepend_dev(mappings),
expected_result) expected_result)
@@ -336,6 +339,33 @@ class ApiEc2TestCase(test.TestCase):
self.ec2.delete_security_group(security_group_name) self.ec2.delete_security_group(security_group_name)
def test_group_name_valid_chars_security_group(self):
""" Test that we sanely handle invalid security group names.
API Spec states we should only accept alphanumeric characters,
spaces, dashes, and underscores. """
self.expect_http()
self.mox.ReplayAll()
# Test block group_name of non alphanumeric characters, spaces,
# dashes, and underscores.
security_group_name = "aa #^% -=99"
self.assertRaises(EC2ResponseError, self.ec2.create_security_group,
security_group_name, 'test group')
def test_group_name_valid_length_security_group(self):
"""Test that we sanely handle invalid security group names.
API Spec states that the length should not exceed 255 chars """
self.expect_http()
self.mox.ReplayAll()
# Test block group_name > 255 chars
security_group_name = "".join(random.choice("poiuytrewqasdfghjklmnbvc")
for x in range(random.randint(256, 266)))
self.assertRaises(EC2ResponseError, self.ec2.create_security_group,
security_group_name, 'test group')
def test_authorize_revoke_security_group_cidr(self): def test_authorize_revoke_security_group_cidr(self):
""" """
Test that we can add and remove CIDR based rules Test that we can add and remove CIDR based rules

View File

@@ -17,6 +17,8 @@
# under the License. # under the License.
import mox import mox
import functools
from base64 import b64decode from base64 import b64decode
from M2Crypto import BIO from M2Crypto import BIO
from M2Crypto import RSA from M2Crypto import RSA
@@ -892,13 +894,16 @@ class CloudTestCase(test.TestCase):
def test_modify_image_attribute(self): def test_modify_image_attribute(self):
modify_image_attribute = self.cloud.modify_image_attribute modify_image_attribute = self.cloud.modify_image_attribute
fake_metadata = {'id': 1, 'container_format': 'ami',
'properties': {'kernel_id': 1, 'ramdisk_id': 1,
'type': 'machine'}, 'is_public': False}
def fake_show(meh, context, id): def fake_show(meh, context, id):
return {'id': 1, 'container_format': 'ami', return fake_metadata
'properties': {'kernel_id': 1, 'ramdisk_id': 1,
'type': 'machine'}, 'is_public': False}
def fake_update(meh, context, image_id, metadata, data=None): def fake_update(meh, context, image_id, metadata, data=None):
return metadata fake_metadata.update(metadata)
return fake_metadata
self.stubs.Set(fake._FakeImageService, 'show', fake_show) self.stubs.Set(fake._FakeImageService, 'show', fake_show)
self.stubs.Set(fake._FakeImageService, 'show_by_name', fake_show) self.stubs.Set(fake._FakeImageService, 'show_by_name', fake_show)
@@ -1464,3 +1469,147 @@ class CloudTestCase(test.TestCase):
# TODO(yamahata): clean up snapshot created by CreateImage. # TODO(yamahata): clean up snapshot created by CreateImage.
self._restart_compute_service() self._restart_compute_service()
@staticmethod
def _fake_bdm_get(ctxt, id):
return [{'volume_id': 87654321,
'snapshot_id': None,
'no_device': None,
'virtual_name': None,
'delete_on_termination': True,
'device_name': '/dev/sdh'},
{'volume_id': None,
'snapshot_id': 98765432,
'no_device': None,
'virtual_name': None,
'delete_on_termination': True,
'device_name': '/dev/sdi'},
{'volume_id': None,
'snapshot_id': None,
'no_device': True,
'virtual_name': None,
'delete_on_termination': None,
'device_name': None},
{'volume_id': None,
'snapshot_id': None,
'no_device': None,
'virtual_name': 'ephemeral0',
'delete_on_termination': None,
'device_name': '/dev/sdb'},
{'volume_id': None,
'snapshot_id': None,
'no_device': None,
'virtual_name': 'swap',
'delete_on_termination': None,
'device_name': '/dev/sdc'},
{'volume_id': None,
'snapshot_id': None,
'no_device': None,
'virtual_name': 'ephemeral1',
'delete_on_termination': None,
'device_name': '/dev/sdd'},
{'volume_id': None,
'snapshot_id': None,
'no_device': None,
'virtual_name': 'ephemeral2',
'delete_on_termination': None,
'device_name': '/dev/sd3'},
]
def test_get_instance_mapping(self):
"""Make sure that _get_instance_mapping works"""
ctxt = None
instance_ref0 = {'id': 0,
'root_device_name': None}
instance_ref1 = {'id': 0,
'root_device_name': '/dev/sda1'}
self.stubs.Set(db, 'block_device_mapping_get_all_by_instance',
self._fake_bdm_get)
expected = {'ami': 'sda1',
'root': '/dev/sda1',
'ephemeral0': '/dev/sdb',
'swap': '/dev/sdc',
'ephemeral1': '/dev/sdd',
'ephemeral2': '/dev/sd3'}
self.assertEqual(self.cloud._format_instance_mapping(ctxt,
instance_ref0),
cloud._DEFAULT_MAPPINGS)
self.assertEqual(self.cloud._format_instance_mapping(ctxt,
instance_ref1),
expected)
def test_describe_instance_attribute(self):
"""Make sure that describe_instance_attribute works"""
self.stubs.Set(db, 'block_device_mapping_get_all_by_instance',
self._fake_bdm_get)
def fake_get(ctxt, instance_id):
return {
'id': 0,
'root_device_name': '/dev/sdh',
'security_groups': [{'name': 'fake0'}, {'name': 'fake1'}],
'state_description': 'stopping',
'instance_type': {'name': 'fake_type'},
'kernel_id': 1,
'ramdisk_id': 2,
'user_data': 'fake-user data',
}
self.stubs.Set(self.cloud.compute_api, 'get', fake_get)
def fake_volume_get(ctxt, volume_id, session=None):
if volume_id == 87654321:
return {'id': volume_id,
'attach_time': '13:56:24',
'status': 'in-use'}
raise exception.VolumeNotFound(volume_id=volume_id)
self.stubs.Set(db.api, 'volume_get', fake_volume_get)
get_attribute = functools.partial(
self.cloud.describe_instance_attribute,
self.context, 'i-12345678')
bdm = get_attribute('blockDeviceMapping')
bdm['blockDeviceMapping'].sort()
expected_bdm = {'instance_id': 'i-12345678',
'rootDeviceType': 'ebs',
'blockDeviceMapping': [
{'deviceName': '/dev/sdh',
'ebs': {'status': 'in-use',
'deleteOnTermination': True,
'volumeId': 87654321,
'attachTime': '13:56:24'}}]}
expected_bdm['blockDeviceMapping'].sort()
self.assertEqual(bdm, expected_bdm)
# NOTE(yamahata): this isn't supported
# get_attribute('disableApiTermination')
groupSet = get_attribute('groupSet')
groupSet['groupSet'].sort()
expected_groupSet = {'instance_id': 'i-12345678',
'groupSet': [{'groupId': 'fake0'},
{'groupId': 'fake1'}]}
expected_groupSet['groupSet'].sort()
self.assertEqual(groupSet, expected_groupSet)
self.assertEqual(get_attribute('instanceInitiatedShutdownBehavior'),
{'instance_id': 'i-12345678',
'instanceInitiatedShutdownBehavior': 'stop'})
self.assertEqual(get_attribute('instanceType'),
{'instance_id': 'i-12345678',
'instanceType': 'fake_type'})
self.assertEqual(get_attribute('kernel'),
{'instance_id': 'i-12345678',
'kernel': 'aki-00000001'})
self.assertEqual(get_attribute('ramdisk'),
{'instance_id': 'i-12345678',
'ramdisk': 'ari-00000002'})
self.assertEqual(get_attribute('rootDeviceName'),
{'instance_id': 'i-12345678',
'rootDeviceName': '/dev/sdh'})
# NOTE(yamahata): this isn't supported
# get_attribute('sourceDestCheck')
self.assertEqual(get_attribute('userData'),
{'instance_id': 'i-12345678',
'userData': '}\xa9\x1e\xba\xc7\xabu\xabZ'})

View File

@@ -1333,15 +1333,17 @@ class ComputeTestCase(test.TestCase):
return bdm return bdm
def test_update_block_device_mapping(self): def test_update_block_device_mapping(self):
swap_size = 1
instance_type = {'swap': swap_size}
instance_id = self._create_instance() instance_id = self._create_instance()
mappings = [ mappings = [
{'virtual': 'ami', 'device': 'sda1'}, {'virtual': 'ami', 'device': 'sda1'},
{'virtual': 'root', 'device': '/dev/sda1'}, {'virtual': 'root', 'device': '/dev/sda1'},
{'virtual': 'swap', 'device': 'sdb1'},
{'virtual': 'swap', 'device': 'sdb2'},
{'virtual': 'swap', 'device': 'sdb3'},
{'virtual': 'swap', 'device': 'sdb4'}, {'virtual': 'swap', 'device': 'sdb4'},
{'virtual': 'swap', 'device': 'sdb3'},
{'virtual': 'swap', 'device': 'sdb2'},
{'virtual': 'swap', 'device': 'sdb1'},
{'virtual': 'ephemeral0', 'device': 'sdc1'}, {'virtual': 'ephemeral0', 'device': 'sdc1'},
{'virtual': 'ephemeral1', 'device': 'sdc2'}, {'virtual': 'ephemeral1', 'device': 'sdc2'},
@@ -1383,32 +1385,36 @@ class ComputeTestCase(test.TestCase):
'no_device': True}] 'no_device': True}]
self.compute_api._update_image_block_device_mapping( self.compute_api._update_image_block_device_mapping(
self.context, instance_id, mappings) self.context, instance_type, instance_id, mappings)
bdms = [self._parse_db_block_device_mapping(bdm_ref) bdms = [self._parse_db_block_device_mapping(bdm_ref)
for bdm_ref in db.block_device_mapping_get_all_by_instance( for bdm_ref in db.block_device_mapping_get_all_by_instance(
self.context, instance_id)] self.context, instance_id)]
expected_result = [ expected_result = [
{'virtual_name': 'swap', 'device_name': '/dev/sdb1'}, {'virtual_name': 'swap', 'device_name': '/dev/sdb1',
{'virtual_name': 'swap', 'device_name': '/dev/sdb2'}, 'volume_size': swap_size},
{'virtual_name': 'swap', 'device_name': '/dev/sdb3'},
{'virtual_name': 'swap', 'device_name': '/dev/sdb4'},
{'virtual_name': 'ephemeral0', 'device_name': '/dev/sdc1'}, {'virtual_name': 'ephemeral0', 'device_name': '/dev/sdc1'},
{'virtual_name': 'ephemeral1', 'device_name': '/dev/sdc2'},
{'virtual_name': 'ephemeral2', 'device_name': '/dev/sdc3'}] # NOTE(yamahata): ATM only ephemeral0 is supported.
# they're ignored for now
#{'virtual_name': 'ephemeral1', 'device_name': '/dev/sdc2'},
#{'virtual_name': 'ephemeral2', 'device_name': '/dev/sdc3'}
]
bdms.sort() bdms.sort()
expected_result.sort() expected_result.sort()
self.assertDictListMatch(bdms, expected_result) self.assertDictListMatch(bdms, expected_result)
self.compute_api._update_block_device_mapping( self.compute_api._update_block_device_mapping(
self.context, instance_id, block_device_mapping) self.context, instance_types.get_default_instance_type(),
instance_id, block_device_mapping)
bdms = [self._parse_db_block_device_mapping(bdm_ref) bdms = [self._parse_db_block_device_mapping(bdm_ref)
for bdm_ref in db.block_device_mapping_get_all_by_instance( for bdm_ref in db.block_device_mapping_get_all_by_instance(
self.context, instance_id)] self.context, instance_id)]
expected_result = [ expected_result = [
{'snapshot_id': 0x12345678, 'device_name': '/dev/sda1'}, {'snapshot_id': 0x12345678, 'device_name': '/dev/sda1'},
{'virtual_name': 'swap', 'device_name': '/dev/sdb1'}, {'virtual_name': 'swap', 'device_name': '/dev/sdb1',
'volume_size': swap_size},
{'snapshot_id': 0x23456789, 'device_name': '/dev/sdb2'}, {'snapshot_id': 0x23456789, 'device_name': '/dev/sdb2'},
{'snapshot_id': 0x3456789A, 'device_name': '/dev/sdb3'}, {'snapshot_id': 0x3456789A, 'device_name': '/dev/sdb3'},
{'no_device': True, 'device_name': '/dev/sdb4'}, {'no_device': True, 'device_name': '/dev/sdb4'},
@@ -1430,3 +1436,13 @@ class ComputeTestCase(test.TestCase):
self.context, instance_id): self.context, instance_id):
db.block_device_mapping_destroy(self.context, bdm['id']) db.block_device_mapping_destroy(self.context, bdm['id'])
self.compute.terminate_instance(self.context, instance_id) self.compute.terminate_instance(self.context, instance_id)
def test_ephemeral_size(self):
local_size = 2
inst_type = {'local_gb': local_size}
self.assertEqual(self.compute_api._ephemeral_size(inst_type,
'ephemeral0'),
local_size)
self.assertEqual(self.compute_api._ephemeral_size(inst_type,
'ephemeral1'),
0)

View File

@@ -169,6 +169,7 @@ class LibvirtConnTestCase(test.TestCase):
'project_id': 'fake', 'project_id': 'fake',
'bridge': 'br101', 'bridge': 'br101',
'image_ref': '123456', 'image_ref': '123456',
'local_gb': 20,
'instance_type_id': '5'} # m1.small 'instance_type_id': '5'} # m1.small
def lazy_load_library_exists(self): def lazy_load_library_exists(self):
@@ -744,6 +745,42 @@ class LibvirtConnTestCase(test.TestCase):
ip = conn.get_host_ip_addr() ip = conn.get_host_ip_addr()
self.assertEquals(ip, FLAGS.my_ip) self.assertEquals(ip, FLAGS.my_ip)
def test_volume_in_mapping(self):
conn = connection.LibvirtConnection(False)
swap = {'device_name': '/dev/sdb',
'swap_size': 1}
ephemerals = [{'num': 0,
'virtual_name': 'ephemeral0',
'device_name': '/dev/sdc1',
'size': 1},
{'num': 2,
'virtual_name': 'ephemeral2',
'device_name': '/dev/sdd',
'size': 1}]
block_device_mapping = [{'mount_device': '/dev/sde',
'device_path': 'fake_device'},
{'mount_device': '/dev/sdf',
'device_path': 'fake_device'}]
block_device_info = {
'root_device_name': '/dev/sda',
'swap': swap,
'ephemerals': ephemerals,
'block_device_mapping': block_device_mapping}
def _assert_volume_in_mapping(device_name, true_or_false):
self.assertEquals(conn._volume_in_mapping(device_name,
block_device_info),
true_or_false)
_assert_volume_in_mapping('sda', False)
_assert_volume_in_mapping('sdb', True)
_assert_volume_in_mapping('sdc1', True)
_assert_volume_in_mapping('sdd', True)
_assert_volume_in_mapping('sde', True)
_assert_volume_in_mapping('sdf', True)
_assert_volume_in_mapping('sdg', False)
_assert_volume_in_mapping('sdh1', False)
class NWFilterFakes: class NWFilterFakes:
def __init__(self): def __init__(self):

83
nova/tests/test_virt.py Normal file
View File

@@ -0,0 +1,83 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Isaku Yamahata
# 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 nova import flags
from nova import test
from nova.virt import driver
FLAGS = flags.FLAGS
class TestVirtDriver(test.TestCase):
def test_block_device(self):
swap = {'device_name': '/dev/sdb',
'swap_size': 1}
ephemerals = [{'num': 0,
'virtual_name': 'ephemeral0',
'device_name': '/dev/sdc1',
'size': 1}]
block_device_mapping = [{'mount_device': '/dev/sde',
'device_path': 'fake_device'}]
block_device_info = {
'root_device_name': '/dev/sda',
'swap': swap,
'ephemerals': ephemerals,
'block_device_mapping': block_device_mapping}
empty_block_device_info = {}
self.assertEqual(
driver.block_device_info_get_root(block_device_info), '/dev/sda')
self.assertEqual(
driver.block_device_info_get_root(empty_block_device_info), None)
self.assertEqual(
driver.block_device_info_get_root(None), None)
self.assertEqual(
driver.block_device_info_get_swap(block_device_info), swap)
self.assertEqual(driver.block_device_info_get_swap(
empty_block_device_info)['device_name'], None)
self.assertEqual(driver.block_device_info_get_swap(
empty_block_device_info)['swap_size'], 0)
self.assertEqual(
driver.block_device_info_get_swap({'swap': None})['device_name'],
None)
self.assertEqual(
driver.block_device_info_get_swap({'swap': None})['swap_size'],
0)
self.assertEqual(
driver.block_device_info_get_swap(None)['device_name'], None)
self.assertEqual(
driver.block_device_info_get_swap(None)['swap_size'], 0)
self.assertEqual(
driver.block_device_info_get_ephemerals(block_device_info),
ephemerals)
self.assertEqual(
driver.block_device_info_get_ephemerals(empty_block_device_info),
[])
self.assertEqual(
driver.block_device_info_get_ephemerals(None),
[])
def test_swap_is_usable(self):
self.assertFalse(driver.swap_is_usable(None))
self.assertFalse(driver.swap_is_usable({'device_name': None}))
self.assertFalse(driver.swap_is_usable({'device_name': '/dev/sdb',
'swap_size': 0}))
self.assertTrue(driver.swap_is_usable({'device_name': '/dev/sdb',
'swap_size': 1}))