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"""
44
class VolumeManager(manager.Manager):
45
"""Manages attachable block storage devices"""
51
46
def __init__(self, volume_driver=None, *args, **kwargs):
52
47
if not volume_driver:
53
48
volume_driver = FLAGS.volume_driver
54
49
self.driver = utils.import_object(volume_driver)
55
super(AOEManager, self).__init__(*args, **kwargs)
50
super(VolumeManager, self).__init__(*args, **kwargs)
51
# NOTE(vish): Implementation specific db handling is done
53
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)
56
"""Do any initialization that needs to be run if this is a
59
self.driver.check_for_setup_error()
60
ctxt = context.get_admin_context()
61
volumes = self.db.volume_get_all_by_host(ctxt, self.host)
62
logging.debug("Re-exporting %s volumes", len(volumes))
63
for volume in volumes:
64
self.driver.ensure_export(context, volume)
67
66
@defer.inlineCallbacks
68
67
def create_volume(self, context, volume_id):
69
68
"""Creates and exports the volume"""
70
69
context = context.elevated()
71
logging.info("volume %s: creating", volume_id)
73
70
volume_ref = self.db.volume_get(context, volume_id)
71
logging.info("volume %s: creating", volume_ref['name'])
75
73
self.db.volume_update(context,
77
75
{'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()
76
# NOTE(vish): so we don't have to get volume from db again
77
# before passing it to the driver.
78
volume_ref['host'] = self.host
80
logging.debug("volume %s: creating lv of size %sG",
81
volume_ref['name'], volume_ref['size'])
82
yield self.driver.create_volume(volume_ref)
84
logging.debug("volume %s: creating export", volume_ref['name'])
85
yield self.driver.create_export(context, volume_ref)
98
87
now = datetime.datetime.utcnow()
99
88
self.db.volume_update(context,
100
89
volume_ref['id'], {'status': 'available',
101
90
'launched_at': now})
102
logging.debug("volume %s: created successfully", volume_id)
91
logging.debug("volume %s: created successfully", volume_ref['name'])
103
92
defer.returnValue(volume_id)
105
94
@defer.inlineCallbacks
111
100
raise exception.Error("Volume is still attached")
112
101
if volume_ref['host'] != self.host:
113
102
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'])
103
logging.debug("volume %s: deleting", volume_ref['name'])
104
yield self.driver.delete_volume(volume_ref)
121
105
self.db.volume_destroy(context, volume_id)
106
logging.debug("volume %s: deleted successfully", volume_ref['name'])
122
107
defer.returnValue(True)
124
109
@defer.inlineCallbacks
128
113
Returns path to device.
130
context = context.elevated()
131
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))
115
context = context.admin()
116
volume_ref = self.db.volume_get(context, volume_id)
117
if volume_ref['host'] == self.host:
118
# NOTE(vish): No need to discover local volumes.
119
path = yield self.driver.local_path(volume_ref)
121
path = yield self.driver.discover_volume(volume_ref)
122
defer.returnValue(path)
124
@defer.inlineCallbacks
125
def remove_compute_volume(self, context, volume_id):
126
"""Remove remote volume on compute host """
127
context = context.admin()
128
volume_ref = self.db.volume_get(context, volume_id)
129
if volume_ref['host'] == self.host:
130
# NOTE(vish): No need to undiscover local volumes.
131
defer.returnValue(True)
133
yield self.driver.undiscover_volume(volume_ref)