diff options
| author | Vishvananda Ishaya <vishvananda@gmail.com> | 2010-07-02 10:31:44 -0500 |
|---|---|---|
| committer | Vishvananda Ishaya <vishvananda@gmail.com> | 2010-07-02 10:31:44 -0500 |
| commit | 5e8337aec03f5a697c90779eb66a457aae4e7ae0 (patch) | |
| tree | 2bb9c7366430d6c6cb09f486c5e4738ead20b0ad | |
| parent | 7897135ec1f365b70db3df7411058b779005a1fe (diff) | |
| parent | 6d612730c5e57d495dc281326c0169e8116ecd86 (diff) | |
| download | nova-5e8337aec03f5a697c90779eb66a457aae4e7ae0.tar.gz nova-5e8337aec03f5a697c90779eb66a457aae4e7ae0.tar.xz nova-5e8337aec03f5a697c90779eb66a457aae4e7ae0.zip | |
Merge patch 30001
| -rw-r--r-- | nova/tests/storage_unittest.py | 17 | ||||
| -rw-r--r-- | nova/volume/storage.py | 86 |
2 files changed, 62 insertions, 41 deletions
diff --git a/nova/tests/storage_unittest.py b/nova/tests/storage_unittest.py index 73215c5ca..36fcc6f19 100644 --- a/nova/tests/storage_unittest.py +++ b/nova/tests/storage_unittest.py @@ -38,10 +38,7 @@ class StorageTestCase(test.TrialTestCase): self.mystorage = None self.flags(fake_libvirt=True, fake_storage=True) - if FLAGS.fake_storage: - self.mystorage = storage.FakeBlockStore() - else: - self.mystorage = storage.BlockStore() + self.mystorage = storage.BlockStore() def test_run_create_volume(self): vol_size = '0' @@ -65,6 +62,18 @@ class StorageTestCase(test.TrialTestCase): self.mystorage.create_volume, vol_size, user_id, project_id) + def test_too_many_volumes(self): + vol_size = '1' + user_id = 'fake' + project_id = 'fake' + num_shelves = FLAGS.last_shelf_id - FLAGS.first_shelf_id + 1 + total_slots = FLAGS.slots_per_shelf * num_shelves + for i in xrange(total_slots): + self.mystorage.create_volume(vol_size, user_id, project_id) + self.assertRaises(storage.NoMoreVolumes, + self.mystorage.create_volume, + vol_size, user_id, project_id) + def test_run_attach_detach_volume(self): # Create one volume and one node to test with instance_id = "storage-test" diff --git a/nova/volume/storage.py b/nova/volume/storage.py index 9c58358bd..a0c4b0d55 100644 --- a/nova/volume/storage.py +++ b/nova/volume/storage.py @@ -26,9 +26,10 @@ Currently uses Ata-over-Ethernet. import glob import logging -import random +import os import socket -import subprocess +import shutil +import tempfile import time from nova import vendor @@ -38,7 +39,6 @@ from twisted.internet import defer from nova import datastore from nova import exception from nova import flags -from nova import rpc from nova import utils from nova import validate @@ -53,16 +53,27 @@ flags.DEFINE_string('aoe_eth_dev', 'eth0', flags.DEFINE_string('storage_name', socket.gethostname(), 'name of this node') -flags.DEFINE_integer('shelf_id', - utils.last_octet(utils.get_my_ip()), - 'AoE shelf_id for this node') +flags.DEFINE_integer('first_shelf_id', + utils.last_octet(utils.get_my_ip()) * 10, + 'AoE starting shelf_id for this node') +flags.DEFINE_integer('last_shelf_id', + utils.last_octet(utils.get_my_ip()) * 10 + 9, + 'AoE starting shelf_id for this node') +flags.DEFINE_string('aoe_export_dir', + '/var/lib/vblade-persist/vblades', + 'AoE directory where exports are created') +flags.DEFINE_integer('slots_per_shelf', + 16, + 'Number of AoE slots per shelf') flags.DEFINE_string('storage_availability_zone', 'nova', 'availability zone of this node') flags.DEFINE_boolean('fake_storage', False, 'Should we make real storage volumes to attach?') -# TODO(joshua) Index of volumes by project + +class NoMoreVolumes(exception.Error): + pass def get_volume(volume_id): """ Returns a redis-backed volume object """ @@ -83,9 +94,14 @@ class BlockStore(object): super(BlockStore, self).__init__() self.volume_class = Volume if FLAGS.fake_storage: + FLAGS.aoe_export_dir = tempfile.mkdtemp() self.volume_class = FakeVolume self._init_volume_group() + def __del__(self): + if FLAGS.fake_storage: + shutil.rmtree(FLAGS.aoe_export_dir) + def report_state(self): #TODO: aggregate the state of the system pass @@ -139,20 +155,8 @@ class BlockStore(object): utils.runthis("PVCreate returned: %s", "sudo pvcreate %s" % (FLAGS.storage_dev)) utils.runthis("VGCreate returned: %s", "sudo vgcreate %s %s" % (FLAGS.volume_group, FLAGS.storage_dev)) - -class FakeBlockStore(BlockStore): - def __init__(self): - super(FakeBlockStore, self).__init__() - - def _init_volume_group(self): - pass - - def _restart_exports(self): - pass - - class Volume(datastore.RedisModel): - + # TODO(joshua) Index of volumes by project object_type = 'volume' def __init__(self, volume_id=None): @@ -177,7 +181,7 @@ class Volume(datastore.RedisModel): vol['delete_on_termination'] = 'False' vol.save() vol.create_lv() - vol.setup_export() + vol._setup_export() # TODO(joshua) - We need to trigger a fanout message for aoe-discover on all the nodes # TODO(joshua vol['status'] = "available" @@ -229,15 +233,22 @@ class Volume(datastore.RedisModel): def _delete_lv(self): utils.runthis("Removing LV: %s", "sudo lvremove -f %s/%s" % (FLAGS.volume_group, self['volume_id'])) - def setup_export(self): + def _setup_export(self): (shelf_id, blade_id) = get_next_aoe_numbers() self['aoe_device'] = "e%s.%s" % (shelf_id, blade_id) self['shelf_id'] = shelf_id self['blade_id'] = blade_id self.save() + self._exec_export() + + def _exec_export(self): utils.runthis("Creating AOE export: %s", - "sudo vblade-persist setup %s %s %s /dev/%s/%s" % - (shelf_id, blade_id, FLAGS.aoe_eth_dev, FLAGS.volume_group, self['volume_id'])) + "sudo vblade- persist setup %s %s %s /dev/%s/%s" % + (self['shelf_id'], + self['blade_id'], + FLAGS.aoe_eth_dev, + FLAGS.volume_group, + self['volume_id'])) def _remove_export(self): utils.runthis("Stopped AOE export: %s", "sudo vblade-persist stop %s %s" % (self['shelf_id'], self['blade_id'])) @@ -248,13 +259,10 @@ class FakeVolume(Volume): def create_lv(self): pass - def setup_export(self): - # TODO(???): This may not be good enough? - blade_id = ''.join([random.choice('0123456789') for x in xrange(3)]) - self['shelf_id'] = FLAGS.shelf_id - self['blade_id'] = blade_id - self['aoe_device'] = "e%s.%s" % (FLAGS.shelf_id, blade_id) - self.save() + def _exec_export(self): + fname = os.path.join(FLAGS.aoe_export_dir, self['aoe_device']) + f = file(fname, "w") + f.close() def _remove_export(self): pass @@ -263,9 +271,13 @@ class FakeVolume(Volume): pass def get_next_aoe_numbers(): - aoes = glob.glob("/var/lib/vblade-persist/vblades/e*") - aoes.extend(['e0.0']) - blade_id = int(max([int(a.split('.')[1]) for a in aoes])) + 1 - logging.debug("Next blade_id is %s" % (blade_id)) - shelf_id = FLAGS.shelf_id - return (shelf_id, blade_id) + for shelf_id in xrange(FLAGS.first_shelf_id, FLAGS.last_shelf_id + 1): + aoes = glob.glob("%s/e%s.*" % (FLAGS.aoe_export_dir, shelf_id)) + if not aoes: + blade_id = 0 + else: + blade_id = int(max([int(a.rpartition('.')[2]) for a in aoes])) + 1 + if blade_id < FLAGS.slots_per_shelf: + logging.debug("Next shelf.blade is %s.%s", shelf_id, blade_id) + return (shelf_id, blade_id) + raise NoMoreVolumes() |
