merge with trunk, resolve conflicts
This commit is contained in:
1
Authors
1
Authors
@@ -1,3 +1,4 @@
|
||||
Adam Gandelman <adamg@canonical.com>
|
||||
Alex Meade <alex.meade@rackspace.com>
|
||||
Alexander Sakhnov <asakhnov@mirantis.com>
|
||||
Andrey Brindeyev <abrindeyev@griddynamics.com>
|
||||
|
||||
@@ -91,7 +91,7 @@ def init_leases(interface):
|
||||
"""Get the list of hosts for an interface."""
|
||||
ctxt = context.get_admin_context()
|
||||
network_ref = db.network_get_by_bridge(ctxt, interface)
|
||||
return linux_net.get_dhcp_leases(ctxt, network_ref['id'])
|
||||
return linux_net.get_dhcp_leases(ctxt, network_ref)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@@ -518,7 +518,7 @@ class ProjectCommands(object):
|
||||
except db.api.NoMoreNetworks:
|
||||
print _('No more networks available. If this is a new '
|
||||
'installation, you need\nto call something like this:\n\n'
|
||||
' nova-manage network create 10.0.0.0/8 10 64\n\n')
|
||||
' nova-manage network create pvt 10.0.0.0/8 10 64\n\n')
|
||||
except exception.ProcessExecutionError, e:
|
||||
print e
|
||||
print _("The above error may show that the certificate db has not "
|
||||
@@ -540,7 +540,7 @@ class FixedIpCommands(object):
|
||||
if host is None:
|
||||
fixed_ips = db.fixed_ip_get_all(ctxt)
|
||||
else:
|
||||
fixed_ips = db.fixed_ip_get_all_by_host(ctxt, host)
|
||||
fixed_ips = db.fixed_ip_get_all_by_instance_host(ctxt, host)
|
||||
except exception.NotFound as ex:
|
||||
print "error: %s" % ex
|
||||
sys.exit(2)
|
||||
@@ -558,7 +558,7 @@ class FixedIpCommands(object):
|
||||
instance = fixed_ip['instance']
|
||||
hostname = instance['hostname']
|
||||
host = instance['host']
|
||||
mac_address = fixed_ip['mac_address']['address']
|
||||
mac_address = fixed_ip['virtual_interface']['address']
|
||||
print "%-18s\t%-15s\t%-17s\t%-15s\t%s" % (
|
||||
fixed_ip['network']['cidr'],
|
||||
fixed_ip['address'],
|
||||
@@ -614,14 +614,10 @@ class NetworkCommands(object):
|
||||
@args('--flat_network_bridge', dest="flat_network_bridge", metavar='<flat network bridge>', help='Flat_network_bridge')
|
||||
@args('--bridge_interface', dest="bridge_interface", metavar='<bridge interface>', help='Bridge_interface')
|
||||
def create(self, label=None, fixed_range=None, num_networks=None,
|
||||
network_size=None, vlan_start=None,
|
||||
network_size=None, multi_host=None, vlan_start=None,
|
||||
vpn_start=None, fixed_range_v6=None, gateway_v6=None,
|
||||
flat_network_bridge=None, bridge_interface=None):
|
||||
"""Creates fixed ips for host by range
|
||||
If you wish to use a later argument fill in the gaps with 0s
|
||||
Ex: network create private 10.0.0.0/8 1 15 0 0 0 0 xenbr1 eth1
|
||||
network create private 10.0.0.0/8 1 15
|
||||
"""
|
||||
"""Creates fixed ips for host by range"""
|
||||
if not label:
|
||||
msg = _('a label (ex: public) is required to create networks.')
|
||||
print msg
|
||||
@@ -635,6 +631,10 @@ class NetworkCommands(object):
|
||||
num_networks = FLAGS.num_networks
|
||||
if not network_size:
|
||||
network_size = FLAGS.network_size
|
||||
if not multi_host:
|
||||
multi_host = FLAGS.multi_host
|
||||
else:
|
||||
multi_host = multi_host == 'T'
|
||||
if not vlan_start:
|
||||
vlan_start = FLAGS.vlan_start
|
||||
if not vpn_start:
|
||||
@@ -653,6 +653,7 @@ class NetworkCommands(object):
|
||||
net_manager.create_networks(context.get_admin_context(),
|
||||
label=label,
|
||||
cidr=fixed_range,
|
||||
multi_host=multi_host,
|
||||
num_networks=int(num_networks),
|
||||
network_size=int(network_size),
|
||||
vlan_start=int(vlan_start),
|
||||
|
||||
@@ -30,13 +30,16 @@ Programming HowTos and Tutorials
|
||||
addmethod.openstackapi
|
||||
|
||||
|
||||
Programming Concepts
|
||||
--------------------
|
||||
Background Concepts for Nova
|
||||
----------------------------
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
distributed_scheduler
|
||||
multinic
|
||||
zone
|
||||
rabbit
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
@@ -29,11 +29,11 @@ FlatDHCP Manager
|
||||
|
||||
.. image:: /images/multinic_dhcp.png
|
||||
|
||||
FlatDHCP manager builds on the the Flat manager adding dnsmask (DNS and DHCP) and radvd (Router Advertisement) servers on the bridge for that network. The services run on the host that is assigned to that nework. The FlatDHCP manager will create its bridge as specified when the network was created on the network-host when the network host starts up or when a new network gets allocated to that host. Compute nodes will also create the bridges as necessary and connect instance VIFs to them.
|
||||
FlatDHCP manager builds on the the Flat manager adding dnsmask (DNS and DHCP) and radvd (Router Advertisement) servers on the bridge for that network. The services run on the host that is assigned to that network. The FlatDHCP manager will create its bridge as specified when the network was created on the network-host when the network host starts up or when a new network gets allocated to that host. Compute nodes will also create the bridges as necessary and connect instance VIFs to them.
|
||||
|
||||
VLAN Manager
|
||||
------------
|
||||
|
||||
.. image:: /images/multinic_vlan.png
|
||||
|
||||
The VLAN manager sets up forwarding to/from a cloudpipe instance in addition to providing dnsmask (DNS and DHCP) and radvd (Router Advertisement) services for each network. The manager will create its bridge as specified when the network was created on the network-host when the network host starts up or when a new network gets allocated to that host. Compute nodes will also create the bridges as necessary and conenct instance VIFs to them.
|
||||
The VLAN manager sets up forwarding to/from a cloudpipe instance in addition to providing dnsmask (DNS and DHCP) and radvd (Router Advertisement) services for each network. The manager will create its bridge as specified when the network was created on the network-host when the network host starts up or when a new network gets allocated to that host. Compute nodes will also create the bridges as necessary and connect instance VIFs to them.
|
||||
|
||||
@@ -78,8 +78,8 @@ def wrap_db_error(f):
|
||||
except Exception, e:
|
||||
LOG.exception(_('DB exception wrapped.'))
|
||||
raise DBError(e)
|
||||
return _wrap
|
||||
_wrap.func_name = f.func_name
|
||||
return _wrap
|
||||
|
||||
|
||||
def wrap_exception(notifier=None, publisher_id=None, event_type=None,
|
||||
@@ -408,6 +408,11 @@ class FixedIpNotFoundForInstance(FixedIpNotFound):
|
||||
message = _("Instance %(instance_id)s has zero fixed ips.")
|
||||
|
||||
|
||||
class FixedIpNotFoundForNetworkHost(FixedIpNotFound):
|
||||
message = _("Network host %(host)s has zero fixed ips "
|
||||
"in network %(network_id)s.")
|
||||
|
||||
|
||||
class FixedIpNotFoundForSpecificInstance(FixedIpNotFound):
|
||||
message = _("Instance %(instance_id)s doesn't have fixed ip '%(ip)s'.")
|
||||
|
||||
|
||||
16
nova/test.py
16
nova/test.py
@@ -31,6 +31,7 @@ import unittest
|
||||
|
||||
import mox
|
||||
import nose.plugins.skip
|
||||
import nova.image.fake
|
||||
import shutil
|
||||
import stubout
|
||||
from eventlet import greenthread
|
||||
@@ -119,6 +120,9 @@ class TestCase(unittest.TestCase):
|
||||
if hasattr(fake.FakeConnection, '_instance'):
|
||||
del fake.FakeConnection._instance
|
||||
|
||||
if FLAGS.image_service == 'nova.image.fake.FakeImageService':
|
||||
nova.image.fake.FakeImageService_reset()
|
||||
|
||||
# Reset any overriden flags
|
||||
self.reset_flags()
|
||||
|
||||
@@ -248,3 +252,15 @@ class TestCase(unittest.TestCase):
|
||||
for d1, d2 in zip(L1, L2):
|
||||
self.assertDictMatch(d1, d2, approx_equal=approx_equal,
|
||||
tolerance=tolerance)
|
||||
|
||||
def assertSubDictMatch(self, sub_dict, super_dict):
|
||||
"""Assert a sub_dict is subset of super_dict."""
|
||||
self.assertTrue(set(sub_dict.keys()).issubset(set(super_dict.keys())))
|
||||
for k, sub_value in sub_dict.items():
|
||||
super_value = super_dict[k]
|
||||
if isinstance(sub_value, dict):
|
||||
self.assertSubDictMatch(sub_value, super_value)
|
||||
elif 'DONTCARE' in (sub_value, super_value):
|
||||
continue
|
||||
else:
|
||||
self.assertEqual(sub_value, super_value)
|
||||
|
||||
@@ -59,6 +59,7 @@ def setup():
|
||||
network.create_networks(ctxt,
|
||||
label='test',
|
||||
cidr=FLAGS.fixed_range,
|
||||
multi_host=FLAGS.multi_host,
|
||||
num_networks=FLAGS.num_networks,
|
||||
network_size=FLAGS.network_size,
|
||||
cidr_v6=FLAGS.fixed_range_v6,
|
||||
@@ -68,7 +69,7 @@ def setup():
|
||||
vpn_start=FLAGS.vpn_start,
|
||||
vlan_start=FLAGS.vlan_start)
|
||||
for net in db.network_get_all(ctxt):
|
||||
network.set_network_host(ctxt, net['id'])
|
||||
network.set_network_host(ctxt, net)
|
||||
|
||||
cleandb = os.path.join(FLAGS.state_path, FLAGS.sqlite_clean_db)
|
||||
shutil.copyfile(testdb, cleandb)
|
||||
|
||||
@@ -92,7 +92,9 @@ class XmlConversionTestCase(test.TestCase):
|
||||
conv = ec2utils._try_convert
|
||||
self.assertEqual(conv('None'), None)
|
||||
self.assertEqual(conv('True'), True)
|
||||
self.assertEqual(conv('true'), True)
|
||||
self.assertEqual(conv('False'), False)
|
||||
self.assertEqual(conv('false'), False)
|
||||
self.assertEqual(conv('0'), 0)
|
||||
self.assertEqual(conv('42'), 42)
|
||||
self.assertEqual(conv('3.14'), 3.14)
|
||||
@@ -107,6 +109,8 @@ class Ec2utilsTestCase(test.TestCase):
|
||||
def test_ec2_id_to_id(self):
|
||||
self.assertEqual(ec2utils.ec2_id_to_id('i-0000001e'), 30)
|
||||
self.assertEqual(ec2utils.ec2_id_to_id('ami-1d'), 29)
|
||||
self.assertEqual(ec2utils.ec2_id_to_id('snap-0000001c'), 28)
|
||||
self.assertEqual(ec2utils.ec2_id_to_id('vol-0000001b'), 27)
|
||||
|
||||
def test_bad_ec2_id(self):
|
||||
self.assertRaises(exception.InvalidEc2Id,
|
||||
@@ -116,6 +120,72 @@ class Ec2utilsTestCase(test.TestCase):
|
||||
def test_id_to_ec2_id(self):
|
||||
self.assertEqual(ec2utils.id_to_ec2_id(30), 'i-0000001e')
|
||||
self.assertEqual(ec2utils.id_to_ec2_id(29, 'ami-%08x'), 'ami-0000001d')
|
||||
self.assertEqual(ec2utils.id_to_ec2_snap_id(28), 'snap-0000001c')
|
||||
self.assertEqual(ec2utils.id_to_ec2_vol_id(27), 'vol-0000001b')
|
||||
|
||||
def test_dict_from_dotted_str(self):
|
||||
in_str = [('BlockDeviceMapping.1.DeviceName', '/dev/sda1'),
|
||||
('BlockDeviceMapping.1.Ebs.SnapshotId', 'snap-0000001c'),
|
||||
('BlockDeviceMapping.1.Ebs.VolumeSize', '80'),
|
||||
('BlockDeviceMapping.1.Ebs.DeleteOnTermination', 'false'),
|
||||
('BlockDeviceMapping.2.DeviceName', '/dev/sdc'),
|
||||
('BlockDeviceMapping.2.VirtualName', 'ephemeral0')]
|
||||
expected_dict = {
|
||||
'block_device_mapping': {
|
||||
'1': {'device_name': '/dev/sda1',
|
||||
'ebs': {'snapshot_id': 'snap-0000001c',
|
||||
'volume_size': 80,
|
||||
'delete_on_termination': False}},
|
||||
'2': {'device_name': '/dev/sdc',
|
||||
'virtual_name': 'ephemeral0'}}}
|
||||
out_dict = ec2utils.dict_from_dotted_str(in_str)
|
||||
|
||||
self.assertDictMatch(out_dict, expected_dict)
|
||||
|
||||
def test_properties_root_defice_name(self):
|
||||
mappings = [{"device": "/dev/sda1", "virtual": "root"}]
|
||||
properties0 = {'mappings': mappings}
|
||||
properties1 = {'root_device_name': '/dev/sdb', 'mappings': mappings}
|
||||
|
||||
root_device_name = ec2utils.properties_root_device_name(properties0)
|
||||
self.assertEqual(root_device_name, '/dev/sda1')
|
||||
|
||||
root_device_name = ec2utils.properties_root_device_name(properties1)
|
||||
self.assertEqual(root_device_name, '/dev/sdb')
|
||||
|
||||
def test_mapping_prepend_dev(self):
|
||||
mappings = [
|
||||
{'virtual': 'ami',
|
||||
'device': 'sda1'},
|
||||
{'virtual': 'root',
|
||||
'device': '/dev/sda1'},
|
||||
|
||||
{'virtual': 'swap',
|
||||
'device': 'sdb1'},
|
||||
{'virtual': 'swap',
|
||||
'device': '/dev/sdb2'},
|
||||
|
||||
{'virtual': 'ephemeral0',
|
||||
'device': 'sdc1'},
|
||||
{'virtual': 'ephemeral1',
|
||||
'device': '/dev/sdc1'}]
|
||||
expected_result = [
|
||||
{'virtual': 'ami',
|
||||
'device': 'sda1'},
|
||||
{'virtual': 'root',
|
||||
'device': '/dev/sda1'},
|
||||
|
||||
{'virtual': 'swap',
|
||||
'device': '/dev/sdb1'},
|
||||
{'virtual': 'swap',
|
||||
'device': '/dev/sdb2'},
|
||||
|
||||
{'virtual': 'ephemeral0',
|
||||
'device': '/dev/sdc1'},
|
||||
{'virtual': 'ephemeral1',
|
||||
'device': '/dev/sdc1'}]
|
||||
self.assertDictListMatch(ec2utils.mappings_prepend_dev(mappings),
|
||||
expected_result)
|
||||
|
||||
|
||||
class ApiEc2TestCase(test.TestCase):
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
# 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 mox
|
||||
|
||||
from base64 import b64decode
|
||||
from M2Crypto import BIO
|
||||
@@ -29,6 +30,7 @@ from nova import db
|
||||
from nova import exception
|
||||
from nova import flags
|
||||
from nova import log as logging
|
||||
from nova import network
|
||||
from nova import rpc
|
||||
from nova import test
|
||||
from nova import utils
|
||||
@@ -45,7 +47,8 @@ LOG = logging.getLogger('nova.tests.cloud')
|
||||
class CloudTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(CloudTestCase, self).setUp()
|
||||
self.flags(connection_type='fake')
|
||||
self.flags(connection_type='fake',
|
||||
stub_network=True)
|
||||
|
||||
self.conn = rpc.Connection.instance()
|
||||
|
||||
@@ -131,6 +134,33 @@ class CloudTestCase(test.TestCase):
|
||||
allocate,
|
||||
self.context)
|
||||
|
||||
def test_release_address(self):
|
||||
address = "10.10.10.10"
|
||||
allocate = self.cloud.allocate_address
|
||||
db.floating_ip_create(self.context,
|
||||
{'address': address,
|
||||
'host': self.network.host})
|
||||
result = self.cloud.release_address(self.context, address)
|
||||
self.assertEqual(result['releaseResponse'], ['Address released.'])
|
||||
|
||||
def test_release_address_still_associated(self):
|
||||
address = "10.10.10.10"
|
||||
fixed_ip = {'instance': {'id': 1}}
|
||||
floating_ip = {'id': 0,
|
||||
'address': address,
|
||||
'fixed_ip_id': 0,
|
||||
'fixed_ip': fixed_ip,
|
||||
'project_id': None,
|
||||
'auto_assigned': False}
|
||||
network_api = network.api.API()
|
||||
self.mox.StubOutWithMock(network_api.db, 'floating_ip_get_by_address')
|
||||
network_api.db.floating_ip_get_by_address(mox.IgnoreArg(),
|
||||
mox.IgnoreArg()).AndReturn(floating_ip)
|
||||
self.mox.ReplayAll()
|
||||
release = self.cloud.release_address
|
||||
# ApiError: Floating ip is in use. Disassociate it before releasing.
|
||||
self.assertRaises(exception.ApiError, release, self.context, address)
|
||||
|
||||
@test.skip_test("Skipping this pending future merge")
|
||||
def test_associate_disassociate_address(self):
|
||||
"""Verifies associate runs cleanly without raising an exception"""
|
||||
@@ -290,7 +320,7 @@ class CloudTestCase(test.TestCase):
|
||||
vol2 = db.volume_create(self.context, {})
|
||||
result = self.cloud.describe_volumes(self.context)
|
||||
self.assertEqual(len(result['volumeSet']), 2)
|
||||
volume_id = ec2utils.id_to_ec2_id(vol2['id'], 'vol-%08x')
|
||||
volume_id = ec2utils.id_to_ec2_vol_id(vol2['id'])
|
||||
result = self.cloud.describe_volumes(self.context,
|
||||
volume_id=[volume_id])
|
||||
self.assertEqual(len(result['volumeSet']), 1)
|
||||
@@ -306,7 +336,7 @@ class CloudTestCase(test.TestCase):
|
||||
snap = db.snapshot_create(self.context, {'volume_id': vol['id'],
|
||||
'volume_size': vol['size'],
|
||||
'status': "available"})
|
||||
snapshot_id = ec2utils.id_to_ec2_id(snap['id'], 'snap-%08x')
|
||||
snapshot_id = ec2utils.id_to_ec2_snap_id(snap['id'])
|
||||
|
||||
result = self.cloud.create_volume(self.context,
|
||||
snapshot_id=snapshot_id)
|
||||
@@ -345,7 +375,7 @@ class CloudTestCase(test.TestCase):
|
||||
snap2 = db.snapshot_create(self.context, {'volume_id': vol['id']})
|
||||
result = self.cloud.describe_snapshots(self.context)
|
||||
self.assertEqual(len(result['snapshotSet']), 2)
|
||||
snapshot_id = ec2utils.id_to_ec2_id(snap2['id'], 'snap-%08x')
|
||||
snapshot_id = ec2utils.id_to_ec2_snap_id(snap2['id'])
|
||||
result = self.cloud.describe_snapshots(self.context,
|
||||
snapshot_id=[snapshot_id])
|
||||
self.assertEqual(len(result['snapshotSet']), 1)
|
||||
@@ -359,7 +389,7 @@ class CloudTestCase(test.TestCase):
|
||||
def test_create_snapshot(self):
|
||||
"""Makes sure create_snapshot works."""
|
||||
vol = db.volume_create(self.context, {'status': "available"})
|
||||
volume_id = ec2utils.id_to_ec2_id(vol['id'], 'vol-%08x')
|
||||
volume_id = ec2utils.id_to_ec2_vol_id(vol['id'])
|
||||
|
||||
result = self.cloud.create_snapshot(self.context,
|
||||
volume_id=volume_id)
|
||||
@@ -376,7 +406,7 @@ class CloudTestCase(test.TestCase):
|
||||
vol = db.volume_create(self.context, {'status': "available"})
|
||||
snap = db.snapshot_create(self.context, {'volume_id': vol['id'],
|
||||
'status': "available"})
|
||||
snapshot_id = ec2utils.id_to_ec2_id(snap['id'], 'snap-%08x')
|
||||
snapshot_id = ec2utils.id_to_ec2_snap_id(snap['id'])
|
||||
|
||||
result = self.cloud.delete_snapshot(self.context,
|
||||
snapshot_id=snapshot_id)
|
||||
@@ -415,6 +445,185 @@ class CloudTestCase(test.TestCase):
|
||||
db.service_destroy(self.context, comp1['id'])
|
||||
db.service_destroy(self.context, comp2['id'])
|
||||
|
||||
def _block_device_mapping_create(self, instance_id, mappings):
|
||||
volumes = []
|
||||
for bdm in mappings:
|
||||
db.block_device_mapping_create(self.context, bdm)
|
||||
if 'volume_id' in bdm:
|
||||
values = {'id': bdm['volume_id']}
|
||||
for bdm_key, vol_key in [('snapshot_id', 'snapshot_id'),
|
||||
('snapshot_size', 'volume_size'),
|
||||
('delete_on_termination',
|
||||
'delete_on_termination')]:
|
||||
if bdm_key in bdm:
|
||||
values[vol_key] = bdm[bdm_key]
|
||||
vol = db.volume_create(self.context, values)
|
||||
db.volume_attached(self.context, vol['id'],
|
||||
instance_id, bdm['device_name'])
|
||||
volumes.append(vol)
|
||||
return volumes
|
||||
|
||||
def _setUpBlockDeviceMapping(self):
|
||||
inst1 = db.instance_create(self.context,
|
||||
{'image_ref': 1,
|
||||
'root_device_name': '/dev/sdb1'})
|
||||
inst2 = db.instance_create(self.context,
|
||||
{'image_ref': 2,
|
||||
'root_device_name': '/dev/sdc1'})
|
||||
|
||||
instance_id = inst1['id']
|
||||
mappings0 = [
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb1',
|
||||
'snapshot_id': '1',
|
||||
'volume_id': '2'},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb2',
|
||||
'volume_id': '3',
|
||||
'volume_size': 1},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb3',
|
||||
'delete_on_termination': True,
|
||||
'snapshot_id': '4',
|
||||
'volume_id': '5'},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb4',
|
||||
'delete_on_termination': False,
|
||||
'snapshot_id': '6',
|
||||
'volume_id': '7'},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb5',
|
||||
'snapshot_id': '8',
|
||||
'volume_id': '9',
|
||||
'volume_size': 0},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb6',
|
||||
'snapshot_id': '10',
|
||||
'volume_id': '11',
|
||||
'volume_size': 1},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb7',
|
||||
'no_device': True},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb8',
|
||||
'virtual_name': 'swap'},
|
||||
{'instance_id': instance_id,
|
||||
'device_name': '/dev/sdb9',
|
||||
'virtual_name': 'ephemeral3'}]
|
||||
|
||||
volumes = self._block_device_mapping_create(instance_id, mappings0)
|
||||
return (inst1, inst2, volumes)
|
||||
|
||||
def _tearDownBlockDeviceMapping(self, inst1, inst2, volumes):
|
||||
for vol in volumes:
|
||||
db.volume_destroy(self.context, vol['id'])
|
||||
for id in (inst1['id'], inst2['id']):
|
||||
for bdm in db.block_device_mapping_get_all_by_instance(
|
||||
self.context, id):
|
||||
db.block_device_mapping_destroy(self.context, bdm['id'])
|
||||
db.instance_destroy(self.context, inst2['id'])
|
||||
db.instance_destroy(self.context, inst1['id'])
|
||||
|
||||
_expected_instance_bdm1 = {
|
||||
'instanceId': 'i-00000001',
|
||||
'rootDeviceName': '/dev/sdb1',
|
||||
'rootDeviceType': 'ebs'}
|
||||
|
||||
_expected_block_device_mapping0 = [
|
||||
{'deviceName': '/dev/sdb1',
|
||||
'ebs': {'status': 'in-use',
|
||||
'deleteOnTermination': False,
|
||||
'volumeId': 2,
|
||||
}},
|
||||
{'deviceName': '/dev/sdb2',
|
||||
'ebs': {'status': 'in-use',
|
||||
'deleteOnTermination': False,
|
||||
'volumeId': 3,
|
||||
}},
|
||||
{'deviceName': '/dev/sdb3',
|
||||
'ebs': {'status': 'in-use',
|
||||
'deleteOnTermination': True,
|
||||
'volumeId': 5,
|
||||
}},
|
||||
{'deviceName': '/dev/sdb4',
|
||||
'ebs': {'status': 'in-use',
|
||||
'deleteOnTermination': False,
|
||||
'volumeId': 7,
|
||||
}},
|
||||
{'deviceName': '/dev/sdb5',
|
||||
'ebs': {'status': 'in-use',
|
||||
'deleteOnTermination': False,
|
||||
'volumeId': 9,
|
||||
}},
|
||||
{'deviceName': '/dev/sdb6',
|
||||
'ebs': {'status': 'in-use',
|
||||
'deleteOnTermination': False,
|
||||
'volumeId': 11, }}]
|
||||
# NOTE(yamahata): swap/ephemeral device case isn't supported yet.
|
||||
|
||||
_expected_instance_bdm2 = {
|
||||
'instanceId': 'i-00000002',
|
||||
'rootDeviceName': '/dev/sdc1',
|
||||
'rootDeviceType': 'instance-store'}
|
||||
|
||||
def test_format_instance_bdm(self):
|
||||
(inst1, inst2, volumes) = self._setUpBlockDeviceMapping()
|
||||
|
||||
result = {}
|
||||
self.cloud._format_instance_bdm(self.context, inst1['id'], '/dev/sdb1',
|
||||
result)
|
||||
self.assertSubDictMatch(
|
||||
{'rootDeviceType': self._expected_instance_bdm1['rootDeviceType']},
|
||||
result)
|
||||
self._assertEqualBlockDeviceMapping(
|
||||
self._expected_block_device_mapping0, result['blockDeviceMapping'])
|
||||
|
||||
result = {}
|
||||
self.cloud._format_instance_bdm(self.context, inst2['id'], '/dev/sdc1',
|
||||
result)
|
||||
self.assertSubDictMatch(
|
||||
{'rootDeviceType': self._expected_instance_bdm2['rootDeviceType']},
|
||||
result)
|
||||
|
||||
self._tearDownBlockDeviceMapping(inst1, inst2, volumes)
|
||||
|
||||
def _assertInstance(self, instance_id):
|
||||
ec2_instance_id = ec2utils.id_to_ec2_id(instance_id)
|
||||
result = self.cloud.describe_instances(self.context,
|
||||
instance_id=[ec2_instance_id])
|
||||
result = result['reservationSet'][0]
|
||||
self.assertEqual(len(result['instancesSet']), 1)
|
||||
result = result['instancesSet'][0]
|
||||
self.assertEqual(result['instanceId'], ec2_instance_id)
|
||||
return result
|
||||
|
||||
def _assertEqualBlockDeviceMapping(self, expected, result):
|
||||
self.assertEqual(len(expected), len(result))
|
||||
for x in expected:
|
||||
found = False
|
||||
for y in result:
|
||||
if x['deviceName'] == y['deviceName']:
|
||||
self.assertSubDictMatch(x, y)
|
||||
found = True
|
||||
break
|
||||
self.assertTrue(found)
|
||||
|
||||
def test_describe_instances_bdm(self):
|
||||
"""Make sure describe_instances works with root_device_name and
|
||||
block device mappings
|
||||
"""
|
||||
(inst1, inst2, volumes) = self._setUpBlockDeviceMapping()
|
||||
|
||||
result = self._assertInstance(inst1['id'])
|
||||
self.assertSubDictMatch(self._expected_instance_bdm1, result)
|
||||
self._assertEqualBlockDeviceMapping(
|
||||
self._expected_block_device_mapping0, result['blockDeviceMapping'])
|
||||
|
||||
result = self._assertInstance(inst2['id'])
|
||||
self.assertSubDictMatch(self._expected_instance_bdm2, result)
|
||||
|
||||
self._tearDownBlockDeviceMapping(inst1, inst2, volumes)
|
||||
|
||||
def test_describe_images(self):
|
||||
describe_images = self.cloud.describe_images
|
||||
|
||||
@@ -445,6 +654,161 @@ class CloudTestCase(test.TestCase):
|
||||
self.assertRaises(exception.ImageNotFound, describe_images,
|
||||
self.context, ['ami-fake'])
|
||||
|
||||
def assertDictListUnorderedMatch(self, L1, L2, key):
|
||||
self.assertEqual(len(L1), len(L2))
|
||||
for d1 in L1:
|
||||
self.assertTrue(key in d1)
|
||||
for d2 in L2:
|
||||
self.assertTrue(key in d2)
|
||||
if d1[key] == d2[key]:
|
||||
self.assertDictMatch(d1, d2)
|
||||
|
||||
def _setUpImageSet(self, create_volumes_and_snapshots=False):
|
||||
mappings1 = [
|
||||
{'device': '/dev/sda1', 'virtual': 'root'},
|
||||
|
||||
{'device': 'sdb0', 'virtual': 'ephemeral0'},
|
||||
{'device': 'sdb1', 'virtual': 'ephemeral1'},
|
||||
{'device': 'sdb2', 'virtual': 'ephemeral2'},
|
||||
{'device': 'sdb3', 'virtual': 'ephemeral3'},
|
||||
{'device': 'sdb4', 'virtual': 'ephemeral4'},
|
||||
|
||||
{'device': 'sdc0', 'virtual': 'swap'},
|
||||
{'device': 'sdc1', 'virtual': 'swap'},
|
||||
{'device': 'sdc2', 'virtual': 'swap'},
|
||||
{'device': 'sdc3', 'virtual': 'swap'},
|
||||
{'device': 'sdc4', 'virtual': 'swap'}]
|
||||
block_device_mapping1 = [
|
||||
{'device_name': '/dev/sdb1', 'snapshot_id': 01234567},
|
||||
{'device_name': '/dev/sdb2', 'volume_id': 01234567},
|
||||
{'device_name': '/dev/sdb3', 'virtual_name': 'ephemeral5'},
|
||||
{'device_name': '/dev/sdb4', 'no_device': True},
|
||||
|
||||
{'device_name': '/dev/sdc1', 'snapshot_id': 12345678},
|
||||
{'device_name': '/dev/sdc2', 'volume_id': 12345678},
|
||||
{'device_name': '/dev/sdc3', 'virtual_name': 'ephemeral6'},
|
||||
{'device_name': '/dev/sdc4', 'no_device': True}]
|
||||
image1 = {
|
||||
'id': 1,
|
||||
'properties': {
|
||||
'kernel_id': 1,
|
||||
'type': 'machine',
|
||||
'image_state': 'available',
|
||||
'mappings': mappings1,
|
||||
'block_device_mapping': block_device_mapping1,
|
||||
}
|
||||
}
|
||||
|
||||
mappings2 = [{'device': '/dev/sda1', 'virtual': 'root'}]
|
||||
block_device_mapping2 = [{'device_name': '/dev/sdb1',
|
||||
'snapshot_id': 01234567}]
|
||||
image2 = {
|
||||
'id': 2,
|
||||
'properties': {
|
||||
'kernel_id': 2,
|
||||
'type': 'machine',
|
||||
'root_device_name': '/dev/sdb1',
|
||||
'mappings': mappings2,
|
||||
'block_device_mapping': block_device_mapping2}}
|
||||
|
||||
def fake_show(meh, context, image_id):
|
||||
for i in [image1, image2]:
|
||||
if i['id'] == image_id:
|
||||
return i
|
||||
raise exception.ImageNotFound(image_id=image_id)
|
||||
|
||||
def fake_detail(meh, context):
|
||||
return [image1, image2]
|
||||
|
||||
self.stubs.Set(fake._FakeImageService, 'show', fake_show)
|
||||
self.stubs.Set(fake._FakeImageService, 'detail', fake_detail)
|
||||
|
||||
volumes = []
|
||||
snapshots = []
|
||||
if create_volumes_and_snapshots:
|
||||
for bdm in block_device_mapping1:
|
||||
if 'volume_id' in bdm:
|
||||
vol = self._volume_create(bdm['volume_id'])
|
||||
volumes.append(vol['id'])
|
||||
if 'snapshot_id' in bdm:
|
||||
snap = db.snapshot_create(self.context,
|
||||
{'id': bdm['snapshot_id'],
|
||||
'volume_id': 76543210,
|
||||
'status': "available",
|
||||
'volume_size': 1})
|
||||
snapshots.append(snap['id'])
|
||||
return (volumes, snapshots)
|
||||
|
||||
def _assertImageSet(self, result, root_device_type, root_device_name):
|
||||
self.assertEqual(1, len(result['imagesSet']))
|
||||
result = result['imagesSet'][0]
|
||||
self.assertTrue('rootDeviceType' in result)
|
||||
self.assertEqual(result['rootDeviceType'], root_device_type)
|
||||
self.assertTrue('rootDeviceName' in result)
|
||||
self.assertEqual(result['rootDeviceName'], root_device_name)
|
||||
self.assertTrue('blockDeviceMapping' in result)
|
||||
|
||||
return result
|
||||
|
||||
_expected_root_device_name1 = '/dev/sda1'
|
||||
# NOTE(yamahata): noDevice doesn't make sense when returning mapping
|
||||
# It makes sense only when user overriding existing
|
||||
# mapping.
|
||||
_expected_bdms1 = [
|
||||
{'deviceName': '/dev/sdb0', 'virtualName': 'ephemeral0'},
|
||||
{'deviceName': '/dev/sdb1', 'ebs': {'snapshotId':
|
||||
'snap-00053977'}},
|
||||
{'deviceName': '/dev/sdb2', 'ebs': {'snapshotId':
|
||||
'vol-00053977'}},
|
||||
{'deviceName': '/dev/sdb3', 'virtualName': 'ephemeral5'},
|
||||
# {'deviceName': '/dev/sdb4', 'noDevice': True},
|
||||
|
||||
{'deviceName': '/dev/sdc0', 'virtualName': 'swap'},
|
||||
{'deviceName': '/dev/sdc1', 'ebs': {'snapshotId':
|
||||
'snap-00bc614e'}},
|
||||
{'deviceName': '/dev/sdc2', 'ebs': {'snapshotId':
|
||||
'vol-00bc614e'}},
|
||||
{'deviceName': '/dev/sdc3', 'virtualName': 'ephemeral6'},
|
||||
# {'deviceName': '/dev/sdc4', 'noDevice': True}
|
||||
]
|
||||
|
||||
_expected_root_device_name2 = '/dev/sdb1'
|
||||
_expected_bdms2 = [{'deviceName': '/dev/sdb1',
|
||||
'ebs': {'snapshotId': 'snap-00053977'}}]
|
||||
|
||||
# NOTE(yamahata):
|
||||
# InstanceBlockDeviceMappingItemType
|
||||
# rootDeviceType
|
||||
# rootDeviceName
|
||||
# blockDeviceMapping
|
||||
# deviceName
|
||||
# virtualName
|
||||
# ebs
|
||||
# snapshotId
|
||||
# volumeSize
|
||||
# deleteOnTermination
|
||||
# noDevice
|
||||
def test_describe_image_mapping(self):
|
||||
"""test for rootDeviceName and blockDeiceMapping"""
|
||||
describe_images = self.cloud.describe_images
|
||||
self._setUpImageSet()
|
||||
|
||||
result = describe_images(self.context, ['ami-00000001'])
|
||||
result = self._assertImageSet(result, 'instance-store',
|
||||
self._expected_root_device_name1)
|
||||
|
||||
self.assertDictListUnorderedMatch(result['blockDeviceMapping'],
|
||||
self._expected_bdms1, 'deviceName')
|
||||
|
||||
result = describe_images(self.context, ['ami-00000002'])
|
||||
result = self._assertImageSet(result, 'ebs',
|
||||
self._expected_root_device_name2)
|
||||
|
||||
self.assertDictListUnorderedMatch(result['blockDeviceMapping'],
|
||||
self._expected_bdms2, 'deviceName')
|
||||
|
||||
self.stubs.UnsetAll()
|
||||
|
||||
def test_describe_image_attribute(self):
|
||||
describe_image_attribute = self.cloud.describe_image_attribute
|
||||
|
||||
@@ -459,6 +823,32 @@ class CloudTestCase(test.TestCase):
|
||||
'launchPermission')
|
||||
self.assertEqual([{'group': 'all'}], result['launchPermission'])
|
||||
|
||||
def test_describe_image_attribute_root_device_name(self):
|
||||
describe_image_attribute = self.cloud.describe_image_attribute
|
||||
self._setUpImageSet()
|
||||
|
||||
result = describe_image_attribute(self.context, 'ami-00000001',
|
||||
'rootDeviceName')
|
||||
self.assertEqual(result['rootDeviceName'],
|
||||
self._expected_root_device_name1)
|
||||
result = describe_image_attribute(self.context, 'ami-00000002',
|
||||
'rootDeviceName')
|
||||
self.assertEqual(result['rootDeviceName'],
|
||||
self._expected_root_device_name2)
|
||||
|
||||
def test_describe_image_attribute_block_device_mapping(self):
|
||||
describe_image_attribute = self.cloud.describe_image_attribute
|
||||
self._setUpImageSet()
|
||||
|
||||
result = describe_image_attribute(self.context, 'ami-00000001',
|
||||
'blockDeviceMapping')
|
||||
self.assertDictListUnorderedMatch(result['blockDeviceMapping'],
|
||||
self._expected_bdms1, 'deviceName')
|
||||
result = describe_image_attribute(self.context, 'ami-00000002',
|
||||
'blockDeviceMapping')
|
||||
self.assertDictListUnorderedMatch(result['blockDeviceMapping'],
|
||||
self._expected_bdms2, 'deviceName')
|
||||
|
||||
def test_modify_image_attribute(self):
|
||||
modify_image_attribute = self.cloud.modify_image_attribute
|
||||
|
||||
@@ -699,7 +1089,7 @@ class CloudTestCase(test.TestCase):
|
||||
def test_update_of_volume_display_fields(self):
|
||||
vol = db.volume_create(self.context, {})
|
||||
self.cloud.update_volume(self.context,
|
||||
ec2utils.id_to_ec2_id(vol['id'], 'vol-%08x'),
|
||||
ec2utils.id_to_ec2_vol_id(vol['id']),
|
||||
display_name='c00l v0lum3')
|
||||
vol = db.volume_get(self.context, vol['id'])
|
||||
self.assertEqual('c00l v0lum3', vol['display_name'])
|
||||
@@ -708,7 +1098,7 @@ class CloudTestCase(test.TestCase):
|
||||
def test_update_of_volume_wont_update_private_fields(self):
|
||||
vol = db.volume_create(self.context, {})
|
||||
self.cloud.update_volume(self.context,
|
||||
ec2utils.id_to_ec2_id(vol['id'], 'vol-%08x'),
|
||||
ec2utils.id_to_ec2_vol_id(vol['id']),
|
||||
mountpoint='/not/here')
|
||||
vol = db.volume_get(self.context, vol['id'])
|
||||
self.assertEqual(None, vol['mountpoint'])
|
||||
@@ -786,11 +1176,13 @@ class CloudTestCase(test.TestCase):
|
||||
|
||||
self._restart_compute_service()
|
||||
|
||||
def _volume_create(self):
|
||||
def _volume_create(self, volume_id=None):
|
||||
kwargs = {'status': 'available',
|
||||
'host': self.volume.host,
|
||||
'size': 1,
|
||||
'attach_status': 'detached', }
|
||||
if volume_id:
|
||||
kwargs['id'] = volume_id
|
||||
return db.volume_create(self.context, kwargs)
|
||||
|
||||
def _assert_volume_attached(self, vol, instance_id, mountpoint):
|
||||
@@ -819,10 +1211,10 @@ class CloudTestCase(test.TestCase):
|
||||
'max_count': 1,
|
||||
'block_device_mapping': [{'device_name': '/dev/vdb',
|
||||
'volume_id': vol1['id'],
|
||||
'delete_on_termination': False, },
|
||||
'delete_on_termination': False},
|
||||
{'device_name': '/dev/vdc',
|
||||
'volume_id': vol2['id'],
|
||||
'delete_on_termination': True, },
|
||||
'delete_on_termination': True},
|
||||
]}
|
||||
ec2_instance_id = self._run_instance_wait(**kwargs)
|
||||
instance_id = ec2utils.ec2_id_to_id(ec2_instance_id)
|
||||
@@ -954,7 +1346,7 @@ class CloudTestCase(test.TestCase):
|
||||
def test_run_with_snapshot(self):
|
||||
"""Makes sure run/stop/start instance with snapshot works."""
|
||||
vol = self._volume_create()
|
||||
ec2_volume_id = ec2utils.id_to_ec2_id(vol['id'], 'vol-%08x')
|
||||
ec2_volume_id = ec2utils.id_to_ec2_vol_id(vol['id'])
|
||||
|
||||
ec2_snapshot1_id = self._create_snapshot(ec2_volume_id)
|
||||
snapshot1_id = ec2utils.ec2_id_to_id(ec2_snapshot1_id)
|
||||
@@ -1013,3 +1405,33 @@ class CloudTestCase(test.TestCase):
|
||||
self.cloud.delete_snapshot(self.context, snapshot_id)
|
||||
greenthread.sleep(0.3)
|
||||
db.volume_destroy(self.context, vol['id'])
|
||||
|
||||
def test_create_image(self):
|
||||
"""Make sure that CreateImage works"""
|
||||
# enforce periodic tasks run in short time to avoid wait for 60s.
|
||||
self._restart_compute_service(periodic_interval=0.3)
|
||||
|
||||
(volumes, snapshots) = self._setUpImageSet(
|
||||
create_volumes_and_snapshots=True)
|
||||
|
||||
kwargs = {'image_id': 'ami-1',
|
||||
'instance_type': FLAGS.default_instance_type,
|
||||
'max_count': 1}
|
||||
ec2_instance_id = self._run_instance_wait(**kwargs)
|
||||
|
||||
# TODO(yamahata): s3._s3_create() can't be tested easily by unit test
|
||||
# as there is no unit test for s3.create()
|
||||
## result = self.cloud.create_image(self.context, ec2_instance_id,
|
||||
## no_reboot=True)
|
||||
## ec2_image_id = result['imageId']
|
||||
## created_image = self.cloud.describe_images(self.context,
|
||||
## [ec2_image_id])
|
||||
|
||||
self.cloud.terminate_instances(self.context, [ec2_instance_id])
|
||||
for vol in volumes:
|
||||
db.volume_destroy(self.context, vol)
|
||||
for snap in snapshots:
|
||||
db.snapshot_destroy(self.context, snap)
|
||||
# TODO(yamahata): clean up snapshot created by CreateImage.
|
||||
|
||||
self._restart_compute_service()
|
||||
|
||||
@@ -424,11 +424,12 @@ class ComputeTestCase(test.TestCase):
|
||||
self.stubs.Set(self.compute.network_api, 'get_instance_nw_info', fake)
|
||||
context = self.context.elevated()
|
||||
instance_id = self._create_instance()
|
||||
self.compute.prep_resize(context, instance_id, 1)
|
||||
instance_ref = db.instance_get(context, instance_id)
|
||||
self.compute.prep_resize(context, instance_ref['uuid'], 1)
|
||||
migration_ref = db.migration_get_by_instance_and_status(context,
|
||||
instance_id, 'pre-migrating')
|
||||
instance_ref['uuid'], 'pre-migrating')
|
||||
try:
|
||||
self.compute.finish_resize(context, instance_id,
|
||||
self.compute.finish_resize(context, instance_ref['uuid'],
|
||||
int(migration_ref['id']), {})
|
||||
except KeyError, e:
|
||||
# Only catch key errors. We want other reasons for the test to
|
||||
@@ -441,14 +442,15 @@ class ComputeTestCase(test.TestCase):
|
||||
"""Ensure notifications on instance migrate/resize"""
|
||||
instance_id = self._create_instance()
|
||||
context = self.context.elevated()
|
||||
inst_ref = db.instance_get(context, instance_id)
|
||||
|
||||
self.compute.run_instance(self.context, instance_id)
|
||||
test_notifier.NOTIFICATIONS = []
|
||||
|
||||
db.instance_update(self.context, instance_id, {'host': 'foo'})
|
||||
self.compute.prep_resize(context, instance_id, 1)
|
||||
self.compute.prep_resize(context, inst_ref['uuid'], 1)
|
||||
migration_ref = db.migration_get_by_instance_and_status(context,
|
||||
instance_id, 'pre-migrating')
|
||||
inst_ref['uuid'], 'pre-migrating')
|
||||
|
||||
self.assertEquals(len(test_notifier.NOTIFICATIONS), 1)
|
||||
msg = test_notifier.NOTIFICATIONS[0]
|
||||
@@ -471,13 +473,15 @@ class ComputeTestCase(test.TestCase):
|
||||
"""Ensure instance can be migrated/resized"""
|
||||
instance_id = self._create_instance()
|
||||
context = self.context.elevated()
|
||||
inst_ref = db.instance_get(context, instance_id)
|
||||
|
||||
self.compute.run_instance(self.context, instance_id)
|
||||
db.instance_update(self.context, instance_id, {'host': 'foo'})
|
||||
self.compute.prep_resize(context, instance_id, 1)
|
||||
db.instance_update(self.context, inst_ref['uuid'],
|
||||
{'host': 'foo'})
|
||||
self.compute.prep_resize(context, inst_ref['uuid'], 1)
|
||||
migration_ref = db.migration_get_by_instance_and_status(context,
|
||||
instance_id, 'pre-migrating')
|
||||
self.compute.resize_instance(context, instance_id,
|
||||
inst_ref['uuid'], 'pre-migrating')
|
||||
self.compute.resize_instance(context, inst_ref['uuid'],
|
||||
migration_ref['id'])
|
||||
self.compute.terminate_instance(context, instance_id)
|
||||
|
||||
@@ -519,6 +523,57 @@ class ComputeTestCase(test.TestCase):
|
||||
|
||||
self.compute.terminate_instance(context, instance_id)
|
||||
|
||||
def test_finish_revert_resize(self):
|
||||
"""Ensure that the flavor is reverted to the original on revert"""
|
||||
context = self.context.elevated()
|
||||
instance_id = self._create_instance()
|
||||
|
||||
def fake(*args, **kwargs):
|
||||
pass
|
||||
|
||||
self.stubs.Set(self.compute.driver, 'finish_resize', fake)
|
||||
self.stubs.Set(self.compute.driver, 'revert_resize', fake)
|
||||
self.stubs.Set(self.compute.network_api, 'get_instance_nw_info', fake)
|
||||
|
||||
self.compute.run_instance(self.context, instance_id)
|
||||
|
||||
# Confirm the instance size before the resize starts
|
||||
inst_ref = db.instance_get(context, instance_id)
|
||||
instance_type_ref = db.instance_type_get(context,
|
||||
inst_ref['instance_type_id'])
|
||||
self.assertEqual(instance_type_ref['flavorid'], 1)
|
||||
|
||||
db.instance_update(self.context, instance_id, {'host': 'foo'})
|
||||
|
||||
self.compute.prep_resize(context, inst_ref['uuid'], 3)
|
||||
|
||||
migration_ref = db.migration_get_by_instance_and_status(context,
|
||||
inst_ref['uuid'], 'pre-migrating')
|
||||
|
||||
self.compute.resize_instance(context, inst_ref['uuid'],
|
||||
migration_ref['id'])
|
||||
self.compute.finish_resize(context, inst_ref['uuid'],
|
||||
int(migration_ref['id']), {})
|
||||
|
||||
# Prove that the instance size is now the new size
|
||||
inst_ref = db.instance_get(context, instance_id)
|
||||
instance_type_ref = db.instance_type_get(context,
|
||||
inst_ref['instance_type_id'])
|
||||
self.assertEqual(instance_type_ref['flavorid'], 3)
|
||||
|
||||
# Finally, revert and confirm the old flavor has been applied
|
||||
self.compute.revert_resize(context, inst_ref['uuid'],
|
||||
migration_ref['id'])
|
||||
self.compute.finish_revert_resize(context, inst_ref['uuid'],
|
||||
migration_ref['id'])
|
||||
|
||||
inst_ref = db.instance_get(context, instance_id)
|
||||
instance_type_ref = db.instance_type_get(context,
|
||||
inst_ref['instance_type_id'])
|
||||
self.assertEqual(instance_type_ref['flavorid'], 1)
|
||||
|
||||
self.compute.terminate_instance(context, instance_id)
|
||||
|
||||
def test_get_by_flavor_id(self):
|
||||
type = instance_types.get_instance_type_by_flavor_id(1)
|
||||
self.assertEqual(type['name'], 'm1.tiny')
|
||||
@@ -818,3 +873,114 @@ class ComputeTestCase(test.TestCase):
|
||||
LOG.info(_("After force-killing instances: %s"), instances)
|
||||
self.assertEqual(len(instances), 1)
|
||||
self.assertEqual(power_state.SHUTOFF, instances[0]['state'])
|
||||
|
||||
@staticmethod
|
||||
def _parse_db_block_device_mapping(bdm_ref):
|
||||
attr_list = ('delete_on_termination', 'device_name', 'no_device',
|
||||
'virtual_name', 'volume_id', 'volume_size', 'snapshot_id')
|
||||
bdm = {}
|
||||
for attr in attr_list:
|
||||
val = bdm_ref.get(attr, None)
|
||||
if val:
|
||||
bdm[attr] = val
|
||||
|
||||
return bdm
|
||||
|
||||
def test_update_block_device_mapping(self):
|
||||
instance_id = self._create_instance()
|
||||
mappings = [
|
||||
{'virtual': 'ami', 'device': 'sda1'},
|
||||
{'virtual': 'root', 'device': '/dev/sda1'},
|
||||
|
||||
{'virtual': 'swap', 'device': 'sdb1'},
|
||||
{'virtual': 'swap', 'device': 'sdb2'},
|
||||
{'virtual': 'swap', 'device': 'sdb3'},
|
||||
{'virtual': 'swap', 'device': 'sdb4'},
|
||||
|
||||
{'virtual': 'ephemeral0', 'device': 'sdc1'},
|
||||
{'virtual': 'ephemeral1', 'device': 'sdc2'},
|
||||
{'virtual': 'ephemeral2', 'device': 'sdc3'}]
|
||||
block_device_mapping = [
|
||||
# root
|
||||
{'device_name': '/dev/sda1',
|
||||
'snapshot_id': 0x12345678,
|
||||
'delete_on_termination': False},
|
||||
|
||||
|
||||
# overwrite swap
|
||||
{'device_name': '/dev/sdb2',
|
||||
'snapshot_id': 0x23456789,
|
||||
'delete_on_termination': False},
|
||||
{'device_name': '/dev/sdb3',
|
||||
'snapshot_id': 0x3456789A},
|
||||
{'device_name': '/dev/sdb4',
|
||||
'no_device': True},
|
||||
|
||||
# overwrite ephemeral
|
||||
{'device_name': '/dev/sdc2',
|
||||
'snapshot_id': 0x456789AB,
|
||||
'delete_on_termination': False},
|
||||
{'device_name': '/dev/sdc3',
|
||||
'snapshot_id': 0x56789ABC},
|
||||
{'device_name': '/dev/sdc4',
|
||||
'no_device': True},
|
||||
|
||||
# volume
|
||||
{'device_name': '/dev/sdd1',
|
||||
'snapshot_id': 0x87654321,
|
||||
'delete_on_termination': False},
|
||||
{'device_name': '/dev/sdd2',
|
||||
'snapshot_id': 0x98765432},
|
||||
{'device_name': '/dev/sdd3',
|
||||
'snapshot_id': 0xA9875463},
|
||||
{'device_name': '/dev/sdd4',
|
||||
'no_device': True}]
|
||||
|
||||
self.compute_api._update_image_block_device_mapping(
|
||||
self.context, instance_id, mappings)
|
||||
|
||||
bdms = [self._parse_db_block_device_mapping(bdm_ref)
|
||||
for bdm_ref in db.block_device_mapping_get_all_by_instance(
|
||||
self.context, instance_id)]
|
||||
expected_result = [
|
||||
{'virtual_name': 'swap', 'device_name': '/dev/sdb1'},
|
||||
{'virtual_name': 'swap', 'device_name': '/dev/sdb2'},
|
||||
{'virtual_name': 'swap', 'device_name': '/dev/sdb3'},
|
||||
{'virtual_name': 'swap', 'device_name': '/dev/sdb4'},
|
||||
{'virtual_name': 'ephemeral0', 'device_name': '/dev/sdc1'},
|
||||
{'virtual_name': 'ephemeral1', 'device_name': '/dev/sdc2'},
|
||||
{'virtual_name': 'ephemeral2', 'device_name': '/dev/sdc3'}]
|
||||
bdms.sort()
|
||||
expected_result.sort()
|
||||
self.assertDictListMatch(bdms, expected_result)
|
||||
|
||||
self.compute_api._update_block_device_mapping(
|
||||
self.context, instance_id, block_device_mapping)
|
||||
bdms = [self._parse_db_block_device_mapping(bdm_ref)
|
||||
for bdm_ref in db.block_device_mapping_get_all_by_instance(
|
||||
self.context, instance_id)]
|
||||
expected_result = [
|
||||
{'snapshot_id': 0x12345678, 'device_name': '/dev/sda1'},
|
||||
|
||||
{'virtual_name': 'swap', 'device_name': '/dev/sdb1'},
|
||||
{'snapshot_id': 0x23456789, 'device_name': '/dev/sdb2'},
|
||||
{'snapshot_id': 0x3456789A, 'device_name': '/dev/sdb3'},
|
||||
{'no_device': True, 'device_name': '/dev/sdb4'},
|
||||
|
||||
{'virtual_name': 'ephemeral0', 'device_name': '/dev/sdc1'},
|
||||
{'snapshot_id': 0x456789AB, 'device_name': '/dev/sdc2'},
|
||||
{'snapshot_id': 0x56789ABC, 'device_name': '/dev/sdc3'},
|
||||
{'no_device': True, 'device_name': '/dev/sdc4'},
|
||||
|
||||
{'snapshot_id': 0x87654321, 'device_name': '/dev/sdd1'},
|
||||
{'snapshot_id': 0x98765432, 'device_name': '/dev/sdd2'},
|
||||
{'snapshot_id': 0xA9875463, 'device_name': '/dev/sdd3'},
|
||||
{'no_device': True, 'device_name': '/dev/sdd4'}]
|
||||
bdms.sort()
|
||||
expected_result.sort()
|
||||
self.assertDictListMatch(bdms, expected_result)
|
||||
|
||||
for bdm in db.block_device_mapping_get_all_by_instance(
|
||||
self.context, instance_id):
|
||||
db.block_device_mapping_destroy(self.context, bdm['id'])
|
||||
self.compute.terminate_instance(self.context, instance_id)
|
||||
|
||||
@@ -58,6 +58,7 @@ def _create_network_info(count=1, ipv6=None):
|
||||
'cidr': fake_ip,
|
||||
'cidr_v6': fake_ip}
|
||||
mapping = {'mac': fake,
|
||||
'dhcp_server': fake,
|
||||
'gateway': fake,
|
||||
'gateway6': fake,
|
||||
'ips': [{'ip': fake_ip}, {'ip': fake_ip}]}
|
||||
|
||||
@@ -45,6 +45,7 @@ class FakeModel(dict):
|
||||
networks = [{'id': 0,
|
||||
'label': 'test0',
|
||||
'injected': False,
|
||||
'multi_host': False,
|
||||
'cidr': '192.168.0.0/24',
|
||||
'cidr_v6': '2001:db8::/64',
|
||||
'gateway_v6': '2001:db8::1',
|
||||
@@ -62,6 +63,7 @@ networks = [{'id': 0,
|
||||
{'id': 1,
|
||||
'label': 'test1',
|
||||
'injected': False,
|
||||
'multi_host': False,
|
||||
'cidr': '192.168.1.0/24',
|
||||
'cidr_v6': '2001:db9::/64',
|
||||
'gateway_v6': '2001:db9::1',
|
||||
@@ -122,34 +124,20 @@ class FlatNetworkTestCase(test.TestCase):
|
||||
self.network = network_manager.FlatManager(host=HOST)
|
||||
self.network.db = db
|
||||
|
||||
def test_set_network_hosts(self):
|
||||
self.mox.StubOutWithMock(db, 'network_get_all')
|
||||
self.mox.StubOutWithMock(db, 'network_set_host')
|
||||
self.mox.StubOutWithMock(db, 'network_update')
|
||||
|
||||
db.network_get_all(mox.IgnoreArg()).AndReturn([networks[0]])
|
||||
db.network_set_host(mox.IgnoreArg(),
|
||||
networks[0]['id'],
|
||||
mox.IgnoreArg()).AndReturn(HOST)
|
||||
db.network_update(mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.network.set_network_hosts(None)
|
||||
|
||||
def test_get_instance_nw_info(self):
|
||||
self.mox.StubOutWithMock(db, 'fixed_ip_get_by_instance')
|
||||
self.mox.StubOutWithMock(db, 'virtual_interface_get_by_instance')
|
||||
self.mox.StubOutWithMock(db, 'instance_type_get_by_id')
|
||||
self.mox.StubOutWithMock(db, 'instance_type_get')
|
||||
|
||||
db.fixed_ip_get_by_instance(mox.IgnoreArg(),
|
||||
mox.IgnoreArg()).AndReturn(fixed_ips)
|
||||
db.virtual_interface_get_by_instance(mox.IgnoreArg(),
|
||||
mox.IgnoreArg()).AndReturn(vifs)
|
||||
db.instance_type_get_by_id(mox.IgnoreArg(),
|
||||
db.instance_type_get(mox.IgnoreArg(),
|
||||
mox.IgnoreArg()).AndReturn(flavor)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
nw_info = self.network.get_instance_nw_info(None, 0, 0)
|
||||
nw_info = self.network.get_instance_nw_info(None, 0, 0, None)
|
||||
|
||||
self.assertTrue(nw_info)
|
||||
|
||||
@@ -164,6 +152,7 @@ class FlatNetworkTestCase(test.TestCase):
|
||||
self.assertDictMatch(nw[0], check)
|
||||
|
||||
check = {'broadcast': '192.168.%s.255' % i,
|
||||
'dhcp_server': '192.168.%s.1' % i,
|
||||
'dns': 'DONTCARE',
|
||||
'gateway': '192.168.%s.1' % i,
|
||||
'gateway6': '2001:db%s::1' % i8,
|
||||
|
||||
@@ -27,8 +27,10 @@ from nova import exception
|
||||
from nova import db
|
||||
from nova import flags
|
||||
from nova import log as logging
|
||||
from nova import rpc
|
||||
from nova import test
|
||||
from nova import utils
|
||||
from nova import volume
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
LOG = logging.getLogger('nova.tests.volume')
|
||||
@@ -43,6 +45,11 @@ class VolumeTestCase(test.TestCase):
|
||||
self.flags(connection_type='fake')
|
||||
self.volume = utils.import_object(FLAGS.volume_manager)
|
||||
self.context = context.get_admin_context()
|
||||
self.instance_id = db.instance_create(self.context, {})['id']
|
||||
|
||||
def tearDown(self):
|
||||
db.instance_destroy(self.context, self.instance_id)
|
||||
super(VolumeTestCase, self).tearDown()
|
||||
|
||||
@staticmethod
|
||||
def _create_volume(size='0', snapshot_id=None):
|
||||
@@ -223,6 +230,30 @@ class VolumeTestCase(test.TestCase):
|
||||
snapshot_id)
|
||||
self.volume.delete_volume(self.context, volume_id)
|
||||
|
||||
def test_create_snapshot_force(self):
|
||||
"""Test snapshot in use can be created forcibly."""
|
||||
|
||||
def fake_cast(ctxt, topic, msg):
|
||||
pass
|
||||
self.stubs.Set(rpc, 'cast', fake_cast)
|
||||
|
||||
volume_id = self._create_volume()
|
||||
self.volume.create_volume(self.context, volume_id)
|
||||
db.volume_attached(self.context, volume_id, self.instance_id,
|
||||
'/dev/sda1')
|
||||
|
||||
volume_api = volume.api.API()
|
||||
self.assertRaises(exception.ApiError,
|
||||
volume_api.create_snapshot,
|
||||
self.context, volume_id,
|
||||
'fake_name', 'fake_description')
|
||||
snapshot_ref = volume_api.create_snapshot_force(self.context,
|
||||
volume_id,
|
||||
'fake_name',
|
||||
'fake_description')
|
||||
db.snapshot_destroy(self.context, snapshot_ref['id'])
|
||||
db.volume_destroy(self.context, volume_id)
|
||||
|
||||
|
||||
class DriverTestCase(test.TestCase):
|
||||
"""Base Test class for Drivers."""
|
||||
|
||||
Reference in New Issue
Block a user