~ubuntu-branches/ubuntu/raring/nova/raring-proposed

« back to all changes in this revision

Viewing changes to nova/volume/xensm.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Adam Gandelman, Chuck Short
  • Date: 2012-11-23 09:04:58 UTC
  • mfrom: (1.1.66)
  • Revision ID: package-import@ubuntu.com-20121123090458-91565o7aev1i1h71
Tags: 2013.1~g1-0ubuntu1
[ Adam Gandelman ]
* debian/control: Ensure novaclient is upgraded with nova,
  require python-keystoneclient >= 1:2.9.0. (LP: #1073289)
* debian/patches/{ubuntu/*, rbd-security.patch}: Dropped, applied
  upstream.
* debian/control: Add python-testtools to Build-Depends.

[ Chuck Short ]
* New upstream version.
* Refreshed debian/patches/avoid_setuptools_git_dependency.patch.
* debian/rules: FTBFS if missing binaries.
* debian/nova-scheudler.install: Add missing rabbit-queues and
  nova-rpc-zmq-receiver.
* Remove nova-volume since it doesnt exist anymore, transition to cinder-*.
* debian/rules: install apport hook in the right place.
* debian/patches/ubuntu-show-tests.patch: Display test failures.
* debian/control: Add depends on genisoimage
* debian/control: Suggest guestmount.
* debian/control: Suggest websockify. (LP: #1076442)
* debian/nova.conf: Disable nova-volume service.
* debian/control: Depend on xen-system-* rather than the hypervisor.
* debian/control, debian/mans/nova-conductor.8, debian/nova-conductor.init,
  debian/nova-conductor.install, debian/nova-conductor.logrotate
  debian/nova-conductor.manpages, debian/nova-conductor.postrm
  debian/nova-conductor.upstart.in: Add nova-conductor service.
* debian/control: Add python-fixtures as a build deps.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (c) 2011 Citrix Systems, Inc.
2
 
#
3
 
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
 
#    not use this file except in compliance with the License. You may obtain
5
 
#    a copy of the License at
6
 
#
7
 
#         http://www.apache.org/licenses/LICENSE-2.0
8
 
#
9
 
#    Unless required by applicable law or agreed to in writing, software
10
 
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
 
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
 
#    License for the specific language governing permissions and limitations
13
 
#    under the License.
14
 
 
15
 
from nova import exception
16
 
from nova import flags
17
 
from nova.openstack.common import log as logging
18
 
from nova import utils
19
 
from nova.virt.xenapi import driver as xenapi_conn
20
 
from nova.virt.xenapi import volumeops
21
 
import nova.volume.driver
22
 
 
23
 
LOG = logging.getLogger(__name__)
24
 
FLAGS = flags.FLAGS
25
 
 
26
 
 
27
 
class XenSMDriver(nova.volume.driver.VolumeDriver):
28
 
 
29
 
    def _convert_config_params(self, conf_str):
30
 
        params = dict([item.split("=") for item in conf_str.split()])
31
 
        return params
32
 
 
33
 
    def _get_introduce_sr_keys(self, params):
34
 
        if 'name_label' in params:
35
 
            del params['name_label']
36
 
        keys = params.keys()
37
 
        keys.append('sr_type')
38
 
        return keys
39
 
 
40
 
    def _create_storage_repo(self, context, backend_ref):
41
 
        """Either creates or introduces SR on host
42
 
        depending on whether it exists in xapi db."""
43
 
        params = self._convert_config_params(backend_ref['config_params'])
44
 
        if 'name_label' in params:
45
 
            label = params['name_label']
46
 
            del params['name_label']
47
 
        else:
48
 
            label = 'SR-' + str(backend_ref['id'])
49
 
 
50
 
        params['sr_type'] = backend_ref['sr_type']
51
 
 
52
 
        if backend_ref['sr_uuid'] is None:
53
 
            # run the sr create command
54
 
            try:
55
 
                LOG.debug(_('SR name = %s') % label)
56
 
                LOG.debug(_('Params: %s') % str(params))
57
 
                sr_uuid = self._volumeops.create_sr(label, params)
58
 
            # update sr_uuid and created in db
59
 
            except Exception as ex:
60
 
                LOG.debug(_("Failed to create sr %s...continuing") %
61
 
                          str(backend_ref['id']))
62
 
                msg = _('Create failed')
63
 
                raise exception.VolumeBackendAPIException(data=msg)
64
 
 
65
 
            LOG.debug(_('SR UUID of new SR is: %s') % sr_uuid)
66
 
            try:
67
 
                self.db.sm_backend_conf_update(context,
68
 
                                               backend_ref['id'],
69
 
                                               dict(sr_uuid=sr_uuid))
70
 
            except Exception as ex:
71
 
                LOG.exception(ex)
72
 
                msg = _("Failed to update db")
73
 
                raise exception.VolumeBackendAPIException(data=msg)
74
 
 
75
 
        else:
76
 
            # sr introduce, if not already done
77
 
            try:
78
 
                self._volumeops.introduce_sr(backend_ref['sr_uuid'], label,
79
 
                                              params)
80
 
            except Exception as ex:
81
 
                LOG.exception(ex)
82
 
                LOG.debug(_("Failed to introduce sr %s...continuing")
83
 
                          % str(backend_ref['id']))
84
 
 
85
 
    def _create_storage_repos(self, context):
86
 
        """Create/Introduce storage repositories at start."""
87
 
        backends = self.db.sm_backend_conf_get_all(context)
88
 
        for backend in backends:
89
 
            try:
90
 
                self._create_storage_repo(context, backend)
91
 
            except Exception as ex:
92
 
                LOG.exception(ex)
93
 
                msg = _('Failed to reach backend %d') % backend['id']
94
 
                raise exception.VolumeBackendAPIException(data=msg)
95
 
 
96
 
    def __init__(self, *args, **kwargs):
97
 
        """Connect to the hypervisor."""
98
 
 
99
 
        # This driver leverages Xen storage manager, and hence requires
100
 
        # hypervisor to be Xen
101
 
        if FLAGS.connection_type != 'xenapi':
102
 
            msg = _('XenSMDriver requires xenapi connection')
103
 
            raise exception.VolumeBackendAPIException(data=msg)
104
 
 
105
 
        url = FLAGS.xenapi_connection_url
106
 
        username = FLAGS.xenapi_connection_username
107
 
        password = FLAGS.xenapi_connection_password
108
 
        try:
109
 
            session = xenapi_conn.XenAPISession(url, username, password)
110
 
            self._volumeops = volumeops.VolumeOps(session)
111
 
        except Exception as ex:
112
 
            LOG.exception(ex)
113
 
            msg = _("Failed to initiate session")
114
 
            raise exception.VolumeBackendAPIException(data=msg)
115
 
 
116
 
        super(XenSMDriver, self).__init__(execute=utils.execute,
117
 
                                          sync_exec=utils.execute,
118
 
                                          *args, **kwargs)
119
 
 
120
 
    def do_setup(self, ctxt):
121
 
        """Setup includes creating or introducing storage repos
122
 
           existing in the database and destroying deleted ones."""
123
 
 
124
 
        # TODO(renukaapte) purge storage repos
125
 
        self.ctxt = ctxt
126
 
        self._create_storage_repos(ctxt)
127
 
 
128
 
    def create_volume(self, volume):
129
 
        """Creates a logical volume. Can optionally return a Dictionary of
130
 
        changes to the volume object to be persisted."""
131
 
 
132
 
        # For now the scheduling logic will be to try to fit the volume in
133
 
        # the first available backend.
134
 
        # TODO(renukaapte) better scheduling once APIs are in place
135
 
        sm_vol_rec = None
136
 
        backends = self.db.sm_backend_conf_get_all(self.ctxt)
137
 
        for backend in backends:
138
 
            # Ensure that storage repo exists, if not create.
139
 
            # This needs to be done because if nova compute and
140
 
            # volume are both running on this host, then, as a
141
 
            # part of detach_volume, compute could potentially forget SR
142
 
            self._create_storage_repo(self.ctxt, backend)
143
 
            sm_vol_rec = self._volumeops.create_volume_for_sm(volume,
144
 
                                                  backend['sr_uuid'])
145
 
            if sm_vol_rec:
146
 
                LOG.debug(_('Volume will be created in backend - %d')
147
 
                          % backend['id'])
148
 
                break
149
 
 
150
 
        if sm_vol_rec:
151
 
            # Update db
152
 
            sm_vol_rec['id'] = volume['id']
153
 
            sm_vol_rec['backend_id'] = backend['id']
154
 
            try:
155
 
                self.db.sm_volume_create(self.ctxt, sm_vol_rec)
156
 
            except Exception as ex:
157
 
                LOG.exception(ex)
158
 
                msg = _("Failed to update volume in db")
159
 
                raise exception.VolumeBackendAPIException(data=msg)
160
 
 
161
 
        else:
162
 
            msg = _('Unable to create volume')
163
 
            raise exception.VolumeBackendAPIException(data=msg)
164
 
 
165
 
    def delete_volume(self, volume):
166
 
 
167
 
        vol_rec = self.db.sm_volume_get(self.ctxt, volume['id'])
168
 
        if not vol_rec:
169
 
            raise exception.NotFound(_("Volume %s does not exist"),
170
 
                                     volume['id'])
171
 
        try:
172
 
            # If compute runs on this node, detach could have disconnected SR
173
 
            backend_ref = self.db.sm_backend_conf_get(self.ctxt,
174
 
                                                      vol_rec['backend_id'])
175
 
            self._create_storage_repo(self.ctxt, backend_ref)
176
 
            self._volumeops.delete_volume_for_sm(vol_rec['vdi_uuid'])
177
 
        except Exception as ex:
178
 
            LOG.exception(ex)
179
 
            msg = _("Failed to delete vdi")
180
 
            raise exception.VolumeBackendAPIException(data=msg)
181
 
 
182
 
        try:
183
 
            self.db.sm_volume_delete(self.ctxt, volume['id'])
184
 
        except Exception as ex:
185
 
            LOG.exception(ex)
186
 
            msg = _("Failed to delete volume in db")
187
 
            raise exception.VolumeBackendAPIException(data=msg)
188
 
 
189
 
    def local_path(self, volume):
190
 
        return str(volume['id'])
191
 
 
192
 
    def undiscover_volume(self, volume):
193
 
        """Undiscover volume on a remote host."""
194
 
        pass
195
 
 
196
 
    def discover_volume(self, context, volume):
197
 
        return str(volume['id'])
198
 
 
199
 
    def check_for_setup_error(self):
200
 
        pass
201
 
 
202
 
    def create_export(self, context, volume):
203
 
        """Exports the volume."""
204
 
        pass
205
 
 
206
 
    def remove_export(self, context, volume):
207
 
        """Removes an export for a logical volume."""
208
 
        pass
209
 
 
210
 
    def ensure_export(self, context, volume):
211
 
        """Safely, synchronously recreates an export for a logical volume."""
212
 
        pass
213
 
 
214
 
    def initialize_connection(self, volume, connector):
215
 
        try:
216
 
            xensm_properties = dict(self.db.sm_volume_get(self.ctxt,
217
 
                                                          volume['id']))
218
 
        except Exception as ex:
219
 
            LOG.exception(ex)
220
 
            msg = _("Failed to find volume in db")
221
 
            raise exception.VolumeBackendAPIException(data=msg)
222
 
 
223
 
        # Keep the volume id key consistent with what ISCSI driver calls it
224
 
        xensm_properties['volume_id'] = xensm_properties['id']
225
 
        del xensm_properties['id']
226
 
 
227
 
        try:
228
 
            backend_conf = self.db.sm_backend_conf_get(self.ctxt,
229
 
                                  xensm_properties['backend_id'])
230
 
        except Exception as ex:
231
 
            LOG.exception(ex)
232
 
            msg = _("Failed to find backend in db")
233
 
            raise exception.VolumeBackendAPIException(data=msg)
234
 
 
235
 
        params = self._convert_config_params(backend_conf['config_params'])
236
 
 
237
 
        xensm_properties['flavor_id'] = backend_conf['flavor_id']
238
 
        xensm_properties['sr_uuid'] = backend_conf['sr_uuid']
239
 
        xensm_properties['sr_type'] = backend_conf['sr_type']
240
 
        xensm_properties.update(params)
241
 
        _introduce_sr_keys = self._get_introduce_sr_keys(params)
242
 
        xensm_properties['introduce_sr_keys'] = _introduce_sr_keys
243
 
        return {
244
 
            'driver_volume_type': 'xensm',
245
 
            'data': xensm_properties
246
 
        }
247
 
 
248
 
    def terminate_connection(self, volume, connector):
249
 
        pass