summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorVishvananda Ishaya <vishvananda@yahoo.com>2010-08-27 23:10:57 -0700
committerVishvananda Ishaya <vishvananda@yahoo.com>2010-08-27 23:10:57 -0700
commit8d0f96432b7b07fa608cae433459645880f4a44c (patch)
treee35990a7ab6a41dd8cc6bebd52174346e3b7ddf2 /nova
parentff72e7baff179bb814e3b9df9fc50659a48249f3 (diff)
downloadnova-8d0f96432b7b07fa608cae433459645880f4a44c.tar.gz
nova-8d0f96432b7b07fa608cae433459645880f4a44c.tar.xz
nova-8d0f96432b7b07fa608cae433459645880f4a44c.zip
split volume into service/manager/driver
Diffstat (limited to 'nova')
-rw-r--r--nova/db/api.py25
-rw-r--r--nova/db/sqlalchemy/api.py32
-rw-r--r--nova/endpoint/cloud.py10
-rw-r--r--nova/manager.py38
-rw-r--r--nova/service.py32
-rw-r--r--nova/utils.py23
-rw-r--r--nova/volume/driver.py120
-rw-r--r--nova/volume/manager.py122
-rw-r--r--nova/volume/service.py155
9 files changed, 359 insertions, 198 deletions
diff --git a/nova/db/api.py b/nova/db/api.py
index 536ef1e25..5e04ee998 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -41,13 +41,6 @@ flags.DEFINE_string('public_range', '4.4.4.0/24', 'Public IP address block')
flags.DEFINE_string('private_range', '10.0.0.0/8', 'Private IP address block')
flags.DEFINE_integer('cnt_vpn_clients', 5,
'Number of addresses reserved for vpn clients')
-flags.DEFINE_integer('num_shelves',
- 100,
- 'Number of vblade shelves')
-flags.DEFINE_integer('blades_per_shelf',
- 16,
- 'Number of vblade blades per shelf')
-
_impl = utils.LazyPluggable(FLAGS['db_backend'],
@@ -376,6 +369,19 @@ def queue_get_for(context, topic, physical_node_id):
###################
+def export_device_count(context):
+ """Return count of export devices."""
+ return _impl.export_device_count(context)
+
+
+def export_device_create(context, values):
+ """Create an export_device from the values dictionary."""
+ return _impl.export_device_create(context, values)
+
+
+###################
+
+
def volume_allocate_shelf_and_blade(context, volume_id):
"""Atomically allocate a free shelf and blade from the pool."""
return _impl.volume_allocate_shelf_and_blade(context, volume_id)
@@ -391,11 +397,6 @@ def volume_create(context, values):
return _impl.volume_create(context, values)
-def volume_ensure_blades(context, num_shelves, blades_per_shelf):
- """Ensure shelves and blades have been created in the datastore."""
- return _impl.volume_ensure_blades(context, num_shelves, blades_per_shelf)
-
-
def volume_destroy(context, volume_id):
"""Destroy the volume or raise if it does not exist."""
return _impl.volume_destroy(context, volume_id)
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index cba85ccb7..1e688495a 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -446,10 +446,22 @@ def queue_get_for(context, topic, physical_node_id):
###################
+def export_device_count(context):
+ return models.ExportDevice.count()
+
+
+def export_device_create(context, values):
+ export_device_ref = models.ExportDevice()
+ for (key, value) in values.iteritems():
+ export_device_ref[key] = value
+ export_device_ref.save()
+ return export_device_ref
+
+
+###################
+
+
def volume_allocate_shelf_and_blade(context, volume_id):
- db.volume_ensure_blades(context,
- FLAGS.num_shelves,
- FLAGS.blades_per_shelf)
session = models.NovaBase.get_session()
query = session.query(models.ExportDevice).filter_by(volume=None)
export_device = query.with_lockmode("update").first()
@@ -477,7 +489,7 @@ def volume_create(context, values):
for (key, value) in values.iteritems():
volume_ref[key] = value
volume_ref.save()
- return volume_ref.id
+ return volume_ref
def volume_destroy(context, volume_id):
@@ -494,18 +506,6 @@ def volume_detached(context, volume_id):
volume_ref.save()
-# NOTE(vish): should this code go up a layer?
-def volume_ensure_blades(context, num_shelves, blades_per_shelf):
- if models.ExportDevice.count() >= num_shelves * blades_per_shelf:
- return
- for shelf_id in xrange(num_shelves):
- for blade_id in xrange(blades_per_shelf):
- export_device = models.ExportDevice()
- export_device.shelf_id = shelf_id
- export_device.blade_id = blade_id
- export_device.save()
-
-
def volume_get(context, volume_id):
return models.Volume.find(volume_id)
diff --git a/nova/endpoint/cloud.py b/nova/endpoint/cloud.py
index ffe3d3cc7..6d59c8225 100644
--- a/nova/endpoint/cloud.py
+++ b/nova/endpoint/cloud.py
@@ -271,7 +271,6 @@ class CloudController(object):
return v
@rbac.allow('projectmanager', 'sysadmin')
- @defer.inlineCallbacks
def create_volume(self, context, size, **kwargs):
vol = {}
vol['size'] = size
@@ -280,13 +279,12 @@ class CloudController(object):
vol['availability_zone'] = FLAGS.storage_availability_zone
vol['status'] = "creating"
vol['attach_status'] = "detached"
- volume_id = db.volume_create(context, vol)
+ volume_ref = db.volume_create(context, vol)
- yield rpc.cast(FLAGS.volume_topic, {"method": "create_volume",
- "args": {"volume_id": volume_id}})
+ rpc.cast(FLAGS.volume_topic, {"method": "create_volume",
+ "args": {"volume_id": volume_ref['id']}})
- volume = db.volume_get(context, volume_id)
- defer.returnValue({'volumeSet': [self._format_volume(context, volume)]})
+ return {'volumeSet': [self._format_volume(context, volume_ref)]}
@rbac.allow('projectmanager', 'sysadmin')
diff --git a/nova/manager.py b/nova/manager.py
new file mode 100644
index 000000000..4f212a41b
--- /dev/null
+++ b/nova/manager.py
@@ -0,0 +1,38 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# 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.
+
+"""
+Base class for managers of different parts of the system
+"""
+
+from nova import utils
+from nova import flags
+
+
+FLAGS = flags.FLAGS
+flags.DEFINE_string('db_driver', 'nova.db.api'
+ 'driver to use for volume creation')
+
+
+class Manager(object):
+ """DB driver is injected in the init method"""
+ def __init__(self, db_driver=None):
+ if not db_driver:
+ db_driver=FLAGS.db_driver
+ self.db = utils.import_object(db_driver)
+
diff --git a/nova/service.py b/nova/service.py
index 9c536c354..59da6f04e 100644
--- a/nova/service.py
+++ b/nova/service.py
@@ -32,6 +32,7 @@ from nova import db
from nova import exception
from nova import flags
from nova import rpc
+from nova import utils
FLAGS = flags.FLAGS
@@ -43,15 +44,29 @@ flags.DEFINE_integer('report_interval', 10,
class Service(object, service.Service):
"""Base class for workers that run on hosts."""
+ def __init__(self, manager, *args, **kwargs):
+ self.manager = manager
+ super(self, Service).__init__(*args, **kwargs)
+
+ def __getattr__(self, key):
+ try:
+ super(Service, self).__getattr__(key)
+ except AttributeError:
+ self.manager.__getattr__(key)
+
@classmethod
- def create(cls, report_interval=None, bin_name=None, topic=None):
+ def create(cls,
+ report_interval=None,
+ bin_name=None,
+ topic=None,
+ manager=None):
"""Instantiates class and passes back application object.
Args:
report_interval, defaults to flag
bin_name, defaults to basename of executable
topic, defaults to basename - "nova-" part
-
+ manager, defaults to FLAGS.<topic>_manager
"""
if not report_interval:
report_interval = FLAGS.report_interval
@@ -61,21 +76,24 @@ class Service(object, service.Service):
bin_name = os.path.basename(inspect.stack()[-1][1])
if not topic:
topic = bin_name.rpartition("nova-")[2]
+ if not manager:
+ manager = FLAGS.get('%s_manager' % topic)
+ manager_ref = utils.import_object(manager)
logging.warn("Starting %s node" % topic)
- node_instance = cls()
+ service_ref = cls(manager_ref)
conn = rpc.Connection.instance()
consumer_all = rpc.AdapterConsumer(
connection=conn,
topic='%s' % topic,
- proxy=node_instance)
+ proxy=service_ref)
consumer_node = rpc.AdapterConsumer(
connection=conn,
topic='%s.%s' % (topic, FLAGS.node_name),
- proxy=node_instance)
+ proxy=service_ref)
- pulse = task.LoopingCall(node_instance.report_state,
+ pulse = task.LoopingCall(service_ref.report_state,
FLAGS.node_name,
bin_name)
pulse.start(interval=report_interval, now=False)
@@ -86,7 +104,7 @@ class Service(object, service.Service):
# This is the parent service that twistd will be looking for when it
# parses this file, return it so that we can get it into globals.
application = service.Application(bin_name)
- node_instance.setServiceParent(application)
+ service_ref.setServiceParent(application)
return application
@defer.inlineCallbacks
diff --git a/nova/utils.py b/nova/utils.py
index c4a8f17e9..392fa8c46 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -46,6 +46,13 @@ def import_class(import_str):
except (ImportError, ValueError, AttributeError):
raise exception.NotFound('Class %s cannot be found' % class_str)
+def import_object(import_str):
+ """Returns an object including a module or module and class"""
+ cls = import_class(import_str)
+ try:
+ return cls()
+ except TypeError:
+ return cls
def fetchfile(url, target):
logging.debug("Fetching %s" % url)
@@ -73,7 +80,7 @@ def execute(cmd, process_input=None, addl_env=None, check_exit_code=True):
if obj.returncode:
logging.debug("Result was %s" % (obj.returncode))
if check_exit_code and obj.returncode <> 0:
- raise Exception( "Unexpected exit code: %s. result=%s"
+ raise Exception( "Unexpected exit code: %s. result=%s"
% (obj.returncode, result))
return result
@@ -105,7 +112,7 @@ def runthis(prompt, cmd, check_exit_code = True):
exit_code = subprocess.call(cmd.split(" "))
logging.debug(prompt % (exit_code))
if check_exit_code and exit_code <> 0:
- raise Exception( "Unexpected exit code: %s from cmd: %s"
+ raise Exception( "Unexpected exit code: %s from cmd: %s"
% (exit_code, cmd))
@@ -150,21 +157,21 @@ def parse_isotime(timestr):
return datetime.datetime.strptime(timestr, TIME_FORMAT)
-
+
class LazyPluggable(object):
"""A pluggable backend loaded lazily based on some value."""
-
+
def __init__(self, pivot, **backends):
self.__backends = backends
self.__pivot = pivot
self.__backend = None
-
+
def __get_backend(self):
if not self.__backend:
backend_name = self.__pivot.value
if backend_name not in self.__backends:
raise exception.Error('Invalid backend: %s' % backend_name)
-
+
backend = self.__backends[backend_name]
if type(backend) == type(tuple()):
name = backend[0]
@@ -172,11 +179,11 @@ class LazyPluggable(object):
else:
name = backend
fromlist = backend
-
+
self.__backend = __import__(name, None, None, fromlist)
logging.error('backend %s', self.__backend)
return self.__backend
-
+
def __getattr__(self, key):
backend = self.__get_backend()
return getattr(backend, key)
diff --git a/nova/volume/driver.py b/nova/volume/driver.py
new file mode 100644
index 000000000..579472047
--- /dev/null
+++ b/nova/volume/driver.py
@@ -0,0 +1,120 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# 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.
+
+"""
+Drivers for volumes
+"""
+
+import logging
+
+from twisted.internet import defer
+
+from nova import flags
+from nova import process
+from nova import utils
+
+
+FLAGS = flags.FLAGS
+flags.DEFINE_string('storage_dev', '/dev/sdb',
+ 'Physical device to use for volumes')
+flags.DEFINE_string('volume_group', 'nova-volumes',
+ 'Name for the VG that will contain exported volumes')
+flags.DEFINE_string('aoe_eth_dev', 'eth0',
+ 'Which device to export the volumes on')
+
+
+class FakeAOEDriver(object):
+ @defer.inlineCallbacks
+ def create_volume(self, volume_id, size):
+ logging.debug("Fake AOE: create_volume %s, %s", volume_id, size)
+
+ @defer.inlineCallbacks
+ def delete_volume(self, volume_id):
+ logging.debug("Fake AOE: delete_volume %s", volume_id)
+
+ @defer.inlineCallbacks
+ def create_export(self, volume_id, shelf_id, blade_id):
+ logging.debug("Fake AOE: create_export %s, %s, %s",
+ volume_id, shelf_id, blade_id)
+
+ @defer.inlineCallbacks
+ def remove_export(self, volume_id, shelf_id, blade_id):
+ logging.debug("Fake AOE: remove_export %s, %s, %s",
+ volume_id, shelf_id, blade_id)
+
+ @defer.inlineCallbacks
+ def ensure_exports(self):
+ logging.debug("Fake AOE: ensure_export")
+
+
+class AOEDriver(object):
+ def __init__(self, *args, **kwargs):
+ super(AOEDriver, self).__init__(*args, **kwargs)
+ # NOTE(vish): no need for thise to be async, but it may be
+ # best to explicitly do them at some other time
+ utils.execute("sudo pvcreate %s" % (FLAGS.storage_dev))
+ utils.execute("sudo vgcreate %s %s" % (FLAGS.volume_group,
+ FLAGS.storage_dev))
+ @defer.inlineCallbacks
+ def create_volume(self, volume_id, size):
+ if int(size) == 0:
+ sizestr = '100M'
+ else:
+ sizestr = '%sG' % size
+ yield process.simple_execute(
+ "sudo lvcreate -L %s -n %s %s" % (sizestr,
+ volume_id,
+ FLAGS.volume_group),
+ terminate_on_stderr=False)
+
+ @defer.inlineCallbacks
+ def delete_volume(self, volume_id):
+ yield process.simple_execute(
+ "sudo lvremove -f %s/%s" % (FLAGS.volume_group,
+ volume_id),
+ terminate_on_stderr=False)
+
+ @defer.inlineCallbacks
+ def create_export(self, volume_id, shelf_id, blade_id):
+ yield process.simple_execute(
+ "sudo vblade-persist setup %s %s %s /dev/%s/%s" %
+ (shelf_id,
+ blade_id,
+ FLAGS.aoe_eth_dev,
+ FLAGS.volume_group,
+ volume_id),
+ terminate_on_stderr=False)
+
+ @defer.inlineCallbacks
+ def remove_export(self, _volume_id, shelf_id, blade_id):
+ yield process.simple_execute(
+ "sudo vblade-persist stop %s %s" % (shelf_id, blade_id),
+ terminate_on_stderr=False)
+ yield process.simple_execute(
+ "sudo vblade-persist destroy %s %s" % (shelf_id, blade_id),
+ terminate_on_stderr=False)
+
+ @defer.inlineCallbacks
+ def ensure_exports(self):
+ # NOTE(ja): wait for blades to appear
+ yield process.simple_execute("sleep 5")
+ yield process.simple_execute("sudo vblade-persist auto all",
+ check_exit_code=False)
+ yield process.simple_execute("sudo vblade-persist start all",
+ check_exit_code=False)
+
diff --git a/nova/volume/manager.py b/nova/volume/manager.py
new file mode 100644
index 000000000..c4686a75c
--- /dev/null
+++ b/nova/volume/manager.py
@@ -0,0 +1,122 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# 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.
+
+"""
+Volume manager manages creating, attaching, detaching, and
+destroying persistent storage volumes, ala EBS.
+"""
+
+import logging
+
+from twisted.internet import defer
+
+from nova import db
+from nova import exception
+from nova import flags
+from nova import manager
+from nova import process
+from nova import service
+from nova import utils
+from nova.volume import driver
+
+
+FLAGS = flags.FLAGS
+flags.DEFINE_string('storage_availability_zone',
+ 'nova',
+ 'availability zone of this service')
+flags.DEFINE_boolean('fake_storage', False,
+ 'Should we make real storage volumes to attach?')
+flags.DEFINE_string('volume_driver', 'nova.volume.driver.AOEDriver'
+ 'Driver to use for volume creation')
+flags.DEFINE_integer('num_shelves',
+ 100,
+ 'Number of vblade shelves')
+flags.DEFINE_integer('blades_per_shelf',
+ 16,
+ 'Number of vblade blades per shelf')
+
+
+class AOEManager(manager.Manager):
+ def __init__(self, volume_driver=None, *args, **kwargs):
+ if not volume_driver:
+ # NOTE(vish): support the legacy fake storage flag
+ if FLAGS.fake_storage:
+ volume_driver='nova.volume.driver.FakeAOEDriver'
+ else:
+ volume_driver=FLAGS.volume_driver
+ self.driver = utils.import_object(volume_driver)
+ super(AOEManager, self).__init__(*args, **kwargs)
+
+ def _ensure_blades(self, context):
+ total_blades = FLAGS.num_shelves, FLAGS.blades_per_shelf
+ if self.db.export_device_count(context) >= total_blades:
+ return
+ for shelf_id in xrange(FLAGS.num_shelves):
+ for blade_id in xrange(FLAGS.blades_per_shelf):
+ dev = {'shelf_id': shelf_id, 'blade_id': blade_id}
+ self.db.export_device_create(context, dev)
+
+ @defer.inlineCallbacks
+ def create_volume(self, volume_id, context=None):
+ """Creates and exports the volume."""
+ logging.info("volume %s: creating" % (volume_id))
+
+ volume_ref = self.db.volume_get(context, volume_id)
+
+ self.db.volume_update(context,
+ volume_id,
+ {'node_name': FLAGS.node_name})
+
+ size = volume_ref['size']
+ logging.debug("volume %s: creating lv of size %sG" % (volume_id, size))
+ yield self.driver.create_volume(volume_id, size)
+
+ logging.debug("volume %s: allocating shelf & blade" % (volume_id))
+ rval = self.db.volume_allocate_shelf_and_blade(context, volume_id)
+ (shelf_id, blade_id) = rval
+
+ logging.debug("volume %s: exporting shelf %s & blade %s" % (volume_id,
+ shelf_id, blade_id))
+
+ yield self.driver.create_export(volume_id, shelf_id, blade_id)
+ # TODO(joshua): We need to trigger a fanout message
+ # for aoe-discover on all the nodes
+
+ self.db.volume_update(context, volume_id, {'status': 'available'})
+
+ logging.debug("volume %s: re-exporting all values" % (volume_id))
+ yield self.driver.ensure_exports()
+
+ logging.debug("volume %s: created successfully" % (volume_id))
+ defer.returnValue(volume_id)
+
+ @defer.inlineCallbacks
+ def delete_volume(self, volume_id, context=None):
+ logging.debug("Deleting volume with id of: %s" % (volume_id))
+ volume_ref = self.db.volume_get(context, volume_id)
+ if volume_ref['attach_status'] == "attached":
+ raise exception.Error("Volume is still attached")
+ if volume_ref['node_name'] != FLAGS.node_name:
+ raise exception.Error("Volume is not local to this node")
+ shelf_id, blade_id = self.db.volume_get_shelf_and_blade(context,
+ volume_id)
+ yield self.driver.remove_export(volume_id, shelf_id, blade_id)
+ yield self.driver.delete_volume(volume_id)
+ self.db.volume_destroy(context, volume_id)
+ defer.returnValue(True)
+
diff --git a/nova/volume/service.py b/nova/volume/service.py
index 7f6747577..423359007 100644
--- a/nova/volume/service.py
+++ b/nova/volume/service.py
@@ -17,164 +17,21 @@
# under the License.
"""
-Nova Storage manages creating, attaching, detaching, and
-destroying persistent storage volumes, ala EBS.
-Currently uses Ata-over-Ethernet.
+Volume service allows rpc calls to the volume manager and reports state
+to the database.
"""
-import logging
-
-from twisted.internet import defer
-
-from nova import db
-from nova import exception
from nova import flags
-from nova import process
from nova import service
FLAGS = flags.FLAGS
-flags.DEFINE_string('storage_dev', '/dev/sdb',
- 'Physical device to use for volumes')
-flags.DEFINE_string('volume_group', 'nova-volumes',
- 'Name for the VG that will contain exported volumes')
-flags.DEFINE_string('aoe_eth_dev', 'eth0',
- 'Which device to export the volumes on')
-flags.DEFINE_string('aoe_export_dir',
- '/var/lib/vblade-persist/vblades',
- 'AoE directory where exports are created')
-flags.DEFINE_string('storage_availability_zone',
- 'nova',
- 'availability zone of this service')
-flags.DEFINE_boolean('fake_storage', False,
- 'Should we make real storage volumes to attach?')
+flags.DEFINE_string('volume_manager', 'nova.volume.manager.AOEManager',
+ 'Manager for volumes')
class VolumeService(service.Service):
"""
- There is one VolumeNode running on each host.
- However, each VolumeNode can report on the state of
- *all* volumes in the cluster.
+ Volume Service automatically passes commands on to the Volume Manager
"""
- def __init__(self):
- super(VolumeService, self).__init__()
- self._exec_init_volumes()
-
- @defer.inlineCallbacks
- def create_volume(self, volume_id, context=None):
- """
- Creates an exported volume (fake or real),
- restarts exports to make it available.
- Volume at this point has size, owner, and zone.
- """
- logging.info("volume %s: creating" % (volume_id))
-
- volume_ref = db.volume_get(context, volume_id)
-
- db.volume_update(context, volume_id, {'node_name': FLAGS.node_name})
-
- size = volume_ref['size']
- logging.debug("volume %s: creating lv of size %sG" % (volume_id, size))
- yield self._exec_create_volume(volume_id, size)
-
- logging.debug("volume %s: allocating shelf & blade" % (volume_id))
- (shelf_id, blade_id) = db.volume_allocate_shelf_and_blade(context,
- volume_id)
-
- logging.debug("volume %s: exporting shelf %s & blade %s" % (volume_id,
- shelf_id, blade_id))
-
- yield self._exec_create_export(volume_id, shelf_id, blade_id)
- # TODO(joshua): We need to trigger a fanout message
- # for aoe-discover on all the nodes
-
- db.volume_update(context, volume_id, {'status': 'available'})
-
- logging.debug("volume %s: re-exporting all values" % (volume_id))
- yield self._exec_ensure_exports()
-
- logging.debug("volume %s: created successfully" % (volume_id))
- defer.returnValue(volume_id)
-
- @defer.inlineCallbacks
- def delete_volume(self, volume_id, context=None):
- logging.debug("Deleting volume with id of: %s" % (volume_id))
- volume_ref = db.volume_get(context, volume_id)
- if volume_ref['attach_status'] == "attached":
- raise exception.Error("Volume is still attached")
- if volume_ref['node_name'] != FLAGS.node_name:
- raise exception.Error("Volume is not local to this node")
- shelf_id, blade_id = db.volume_get_shelf_and_blade(context,
- volume_id)
- yield self._exec_remove_export(volume_id, shelf_id, blade_id)
- yield self._exec_delete_volume(volume_id)
- db.volume_destroy(context, volume_id)
- defer.returnValue(True)
-
- @defer.inlineCallbacks
- def _exec_create_volume(self, volume_id, size):
- if FLAGS.fake_storage:
- defer.returnValue(None)
- if int(size) == 0:
- sizestr = '100M'
- else:
- sizestr = '%sG' % size
- yield process.simple_execute(
- "sudo lvcreate -L %s -n %s %s" % (sizestr,
- volume_id,
- FLAGS.volume_group),
- terminate_on_stderr=False)
-
- @defer.inlineCallbacks
- def _exec_delete_volume(self, volume_id):
- if FLAGS.fake_storage:
- defer.returnValue(None)
- yield process.simple_execute(
- "sudo lvremove -f %s/%s" % (FLAGS.volume_group,
- volume_id),
- terminate_on_stderr=False)
-
- @defer.inlineCallbacks
- def _exec_create_export(self, volume_id, shelf_id, blade_id):
- if FLAGS.fake_storage:
- defer.returnValue(None)
- yield process.simple_execute(
- "sudo vblade-persist setup %s %s %s /dev/%s/%s" %
- (shelf_id,
- blade_id,
- FLAGS.aoe_eth_dev,
- FLAGS.volume_group,
- volume_id),
- terminate_on_stderr=False)
-
- @defer.inlineCallbacks
- def _exec_remove_export(self, _volume_id, shelf_id, blade_id):
- if FLAGS.fake_storage:
- defer.returnValue(None)
- yield process.simple_execute(
- "sudo vblade-persist stop %s %s" % (shelf_id, blade_id),
- terminate_on_stderr=False)
- yield process.simple_execute(
- "sudo vblade-persist destroy %s %s" % (shelf_id, blade_id),
- terminate_on_stderr=False)
-
- @defer.inlineCallbacks
- def _exec_ensure_exports(self):
- if FLAGS.fake_storage:
- defer.returnValue(None)
-
- yield process.simple_execute("sleep 5") # wait for blades to appear
- yield process.simple_execute("sudo vblade-persist auto all",
- check_exit_code=False)
- yield process.simple_execute("sudo vblade-persist start all",
- check_exit_code=False)
-
- @defer.inlineCallbacks
- def _exec_init_volumes(self):
- if FLAGS.fake_storage:
- defer.returnValue(None)
- yield process.simple_execute(
- "sudo pvcreate %s" % (FLAGS.storage_dev))
- yield process.simple_execute(
- "sudo vgcreate %s %s" % (FLAGS.volume_group,
- FLAGS.storage_dev))
+ pass