~soren/nova/logdir-flag

« back to all changes in this revision

Viewing changes to nova/volume/manager.py

  • Committer: Tarmac
  • Author(s): Vishvananda Ishaya
  • Date: 2010-11-03 08:29:03 UTC
  • mfrom: (379.3.10 iscsi-volumes)
  • Revision ID: hudson@openstack.org-20101103082903-ewvisg4duas9gik7
ISCSI Volume support

* Rewrite of Volume code to make VolumeManager more generic
* AoE vs. ISCSI moved to driver layer
* Added db support for target ids
* Added code to re-export volumes on restart of VolumeManager
* Includes a script to create /dev/iscsi volumes on remote hosts
* Change libvirt_conn to use the python connection to attach disks instead of shell
* Changed cloud and compute manager to deal with attaching, detaching, and terminating in
  a saner manner.

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
 
27
27
from twisted.internet import defer
28
28
 
 
29
from nova import context
29
30
from nova import exception
30
31
from nova import flags
31
32
from nova import manager
36
37
flags.DEFINE_string('storage_availability_zone',
37
38
                    'nova',
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',
42
 
                    100,
43
 
                    'Number of vblade shelves')
44
 
flags.DEFINE_integer('blades_per_shelf',
45
 
                    16,
46
 
                    'Number of vblade blades per shelf')
47
 
 
48
 
 
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')
 
44
 
 
45
 
 
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
 
54
        #             by the driver.
 
55
        self.driver.db = self.db
56
56
 
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:
61
 
            return
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)
 
57
    def init_host(self):
 
58
        """Do any initialization that needs to be run if this is a
 
59
           standalone service.
 
60
        """
 
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)
66
67
 
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)
72
 
 
73
72
        volume_ref = self.db.volume_get(context, volume_id)
 
73
        logging.info("volume %s: creating", volume_ref['name'])
74
74
 
75
75
        self.db.volume_update(context,
76
76
                              volume_id,
77
77
                              {'host': self.host})
78
 
 
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)
82
 
 
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
87
 
 
88
 
        logging.debug("volume %s: exporting shelf %s & blade %s", volume_id,
89
 
                      shelf_id, blade_id)
90
 
 
91
 
        yield self.driver.create_export(volume_ref['ec2_id'],
92
 
                                        shelf_id,
93
 
                                        blade_id)
94
 
 
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
 
81
 
 
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)
 
85
 
 
86
        logging.debug("volume %s: creating export", volume_ref['name'])
 
87
        yield self.driver.create_export(context, volume_ref)
97
88
 
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)
104
95
 
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,
116
 
                                                                volume_id)
117
 
        yield self.driver.remove_export(volume_ref['ec2_id'],
118
 
                                        shelf_id,
119
 
                                        blade_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)
123
112
 
124
113
    @defer.inlineCallbacks
129
118
        """
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,
134
 
                                                                volume_id)
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)
 
123
        else:
 
124
            path = yield self.driver.discover_volume(volume_ref)
 
125
        defer.returnValue(path)
 
126
 
 
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)
 
134
        else:
 
135
            yield self.driver.undiscover_volume(volume_ref)