36
37
flags.DEFINE_string('storage_availability_zone',
38
39
'availability zone of this service')
39
flags.DEFINE_string('volume_driver', 'nova.volume.driver.AOEDriver',
40
flags.DEFINE_string('volume_driver', 'nova.volume.driver.ISCSIDriver',
40
41
'Driver to use for volume creation')
41
flags.DEFINE_integer('num_shelves',
43
'Number of vblade shelves')
44
flags.DEFINE_integer('blades_per_shelf',
46
'Number of vblade blades per shelf')
49
class AOEManager(manager.Manager):
50
"""Manages Ata-Over_Ethernet volumes"""
42
flags.DEFINE_boolean('use_local_volumes', True,
43
'if True, will not discover local volumes')
46
class VolumeManager(manager.Manager):
47
"""Manages attachable block storage devices"""
51
48
def __init__(self, volume_driver=None, *args, **kwargs):
52
49
if not volume_driver:
53
50
volume_driver = FLAGS.volume_driver
54
51
self.driver = utils.import_object(volume_driver)
55
super(AOEManager, self).__init__(*args, **kwargs)
52
super(VolumeManager, self).__init__(*args, **kwargs)
53
# NOTE(vish): Implementation specific db handling is done
55
self.driver.db = self.db
57
def _ensure_blades(self, context):
58
"""Ensure that blades have been created in datastore"""
59
total_blades = FLAGS.num_shelves * FLAGS.blades_per_shelf
60
if self.db.export_device_count(context) >= total_blades:
62
for shelf_id in xrange(FLAGS.num_shelves):
63
for blade_id in xrange(FLAGS.blades_per_shelf):
64
dev = {'shelf_id': shelf_id, 'blade_id': blade_id}
65
self.db.export_device_create_safe(context, dev)
58
"""Do any initialization that needs to be run if this is a
61
self.driver.check_for_setup_error()
62
ctxt = context.get_admin_context()
63
volumes = self.db.volume_get_all_by_host(ctxt, self.host)
64
logging.debug("Re-exporting %s volumes", len(volumes))
65
for volume in volumes:
66
self.driver.ensure_export(ctxt, volume)
67
68
@defer.inlineCallbacks
68
69
def create_volume(self, context, volume_id):
69
70
"""Creates and exports the volume"""
70
71
context = context.elevated()
71
logging.info("volume %s: creating", volume_id)
73
72
volume_ref = self.db.volume_get(context, volume_id)
73
logging.info("volume %s: creating", volume_ref['name'])
75
75
self.db.volume_update(context,
77
77
{'host': self.host})
79
size = volume_ref['size']
80
logging.debug("volume %s: creating lv of size %sG", volume_id, size)
81
yield self.driver.create_volume(volume_ref['ec2_id'], size)
83
logging.debug("volume %s: allocating shelf & blade", volume_id)
84
self._ensure_blades(context)
85
rval = self.db.volume_allocate_shelf_and_blade(context, volume_id)
86
(shelf_id, blade_id) = rval
88
logging.debug("volume %s: exporting shelf %s & blade %s", volume_id,
91
yield self.driver.create_export(volume_ref['ec2_id'],
95
logging.debug("volume %s: re-exporting all values", volume_id)
96
yield self.driver.ensure_exports()
78
# NOTE(vish): so we don't have to get volume from db again
79
# before passing it to the driver.
80
volume_ref['host'] = self.host
82
logging.debug("volume %s: creating lv of size %sG",
83
volume_ref['name'], volume_ref['size'])
84
yield self.driver.create_volume(volume_ref)
86
logging.debug("volume %s: creating export", volume_ref['name'])
87
yield self.driver.create_export(context, volume_ref)
98
89
now = datetime.datetime.utcnow()
99
90
self.db.volume_update(context,
100
91
volume_ref['id'], {'status': 'available',
101
92
'launched_at': now})
102
logging.debug("volume %s: created successfully", volume_id)
93
logging.debug("volume %s: created successfully", volume_ref['name'])
103
94
defer.returnValue(volume_id)
105
96
@defer.inlineCallbacks
111
102
raise exception.Error("Volume is still attached")
112
103
if volume_ref['host'] != self.host:
113
104
raise exception.Error("Volume is not local to this node")
114
logging.debug("Deleting volume with id of: %s", volume_id)
115
shelf_id, blade_id = self.db.volume_get_shelf_and_blade(context,
117
yield self.driver.remove_export(volume_ref['ec2_id'],
120
yield self.driver.delete_volume(volume_ref['ec2_id'])
105
logging.debug("volume %s: removing export", volume_ref['name'])
106
yield self.driver.remove_export(context, volume_ref)
107
logging.debug("volume %s: deleting", volume_ref['name'])
108
yield self.driver.delete_volume(volume_ref)
121
109
self.db.volume_destroy(context, volume_id)
110
logging.debug("volume %s: deleted successfully", volume_ref['name'])
122
111
defer.returnValue(True)
124
113
@defer.inlineCallbacks
130
119
context = context.elevated()
131
120
volume_ref = self.db.volume_get(context, volume_id)
132
yield self.driver.discover_volume(volume_ref['ec2_id'])
133
shelf_id, blade_id = self.db.volume_get_shelf_and_blade(context,
135
defer.returnValue("/dev/etherd/e%s.%s" % (shelf_id, blade_id))
121
if volume_ref['host'] == self.host and FLAGS.use_local_volumes:
122
path = yield self.driver.local_path(volume_ref)
124
path = yield self.driver.discover_volume(volume_ref)
125
defer.returnValue(path)
127
@defer.inlineCallbacks
128
def remove_compute_volume(self, context, volume_id):
129
"""Remove remote volume on compute host """
130
context = context.elevated()
131
volume_ref = self.db.volume_get(context, volume_id)
132
if volume_ref['host'] == self.host and FLAGS.use_local_volumes:
133
defer.returnValue(True)
135
yield self.driver.undiscover_volume(volume_ref)