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

« back to all changes in this revision

Viewing changes to nova/volume/nexenta/volume.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
 
# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
 
#
3
 
# Copyright 2011 Nexenta Systems, Inc.
4
 
# All Rights Reserved.
5
 
#
6
 
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
7
 
#    not use this file except in compliance with the License. You may obtain
8
 
#    a copy of the License at
9
 
#
10
 
#         http://www.apache.org/licenses/LICENSE-2.0
11
 
#
12
 
#    Unless required by applicable law or agreed to in writing, software
13
 
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
 
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
 
#    License for the specific language governing permissions and limitations
16
 
#    under the License.
17
 
"""
18
 
:mod:`nexenta.volume` -- Driver to store volumes on Nexenta Appliance
19
 
=====================================================================
20
 
 
21
 
.. automodule:: nexenta.volume
22
 
.. moduleauthor:: Yuriy Taraday <yorik.sar@gmail.com>
23
 
"""
24
 
 
25
 
from nova import exception
26
 
from nova import flags
27
 
from nova.openstack.common import cfg
28
 
from nova.openstack.common import log as logging
29
 
from nova.volume import driver
30
 
from nova.volume import nexenta
31
 
from nova.volume.nexenta import jsonrpc
32
 
 
33
 
LOG = logging.getLogger(__name__)
34
 
FLAGS = flags.FLAGS
35
 
 
36
 
nexenta_opts = [
37
 
    cfg.StrOpt('nexenta_host',
38
 
              default='',
39
 
              help='IP address of Nexenta SA'),
40
 
    cfg.IntOpt('nexenta_rest_port',
41
 
               default=2000,
42
 
               help='HTTP port to connect to Nexenta REST API server'),
43
 
    cfg.StrOpt('nexenta_rest_protocol',
44
 
               default='auto',
45
 
               help='Use http or https for REST connection (default auto)'),
46
 
    cfg.StrOpt('nexenta_user',
47
 
               default='admin',
48
 
               help='User name to connect to Nexenta SA'),
49
 
    cfg.StrOpt('nexenta_password',
50
 
               default='nexenta',
51
 
               help='Password to connect to Nexenta SA'),
52
 
    cfg.IntOpt('nexenta_iscsi_target_portal_port',
53
 
               default=3260,
54
 
               help='Nexenta target portal port'),
55
 
    cfg.StrOpt('nexenta_volume',
56
 
               default='nova',
57
 
               help='pool on SA that will hold all volumes'),
58
 
    cfg.StrOpt('nexenta_target_prefix',
59
 
               default='iqn.1986-03.com.sun:02:nova-',
60
 
               help='IQN prefix for iSCSI targets'),
61
 
    cfg.StrOpt('nexenta_target_group_prefix',
62
 
               default='nova/',
63
 
               help='prefix for iSCSI target groups on SA'),
64
 
    cfg.StrOpt('nexenta_blocksize',
65
 
               default='',
66
 
               help='block size for volumes (blank=default,8KB)'),
67
 
    cfg.BoolOpt('nexenta_sparse',
68
 
                default=False,
69
 
                help='flag to create sparse volumes'),
70
 
]
71
 
FLAGS.register_opts(nexenta_opts)
72
 
 
73
 
 
74
 
class NexentaDriver(driver.ISCSIDriver):  # pylint: disable=R0921
75
 
    """Executes volume driver commands on Nexenta Appliance."""
76
 
 
77
 
    def __init__(self):
78
 
        super(NexentaDriver, self).__init__()
79
 
 
80
 
    def do_setup(self, context):
81
 
        protocol = FLAGS.nexenta_rest_protocol
82
 
        auto = protocol == 'auto'
83
 
        if auto:
84
 
            protocol = 'http'
85
 
        self.nms = jsonrpc.NexentaJSONProxy(
86
 
            '%s://%s:%s/rest/nms/' % (protocol, FLAGS.nexenta_host,
87
 
                                      FLAGS.nexenta_rest_port),
88
 
            FLAGS.nexenta_user, FLAGS.nexenta_password, auto=auto)
89
 
 
90
 
    def check_for_setup_error(self):
91
 
        """Verify that the volume for our zvols exists.
92
 
 
93
 
        :raise: :py:exc:`LookupError`
94
 
        """
95
 
        if not self.nms.volume.object_exists(FLAGS.nexenta_volume):
96
 
            raise LookupError(_("Volume %s does not exist in Nexenta SA"),
97
 
                                    FLAGS.nexenta_volume)
98
 
 
99
 
    @staticmethod
100
 
    def _get_zvol_name(volume_name):
101
 
        """Return zvol name that corresponds given volume name."""
102
 
        return '%s/%s' % (FLAGS.nexenta_volume, volume_name)
103
 
 
104
 
    @staticmethod
105
 
    def _get_target_name(volume_name):
106
 
        """Return iSCSI target name to access volume."""
107
 
        return '%s%s' % (FLAGS.nexenta_target_prefix, volume_name)
108
 
 
109
 
    @staticmethod
110
 
    def _get_target_group_name(volume_name):
111
 
        """Return Nexenta iSCSI target group name for volume."""
112
 
        return '%s%s' % (FLAGS.nexenta_target_group_prefix, volume_name)
113
 
 
114
 
    def create_volume(self, volume):
115
 
        """Create a zvol on appliance.
116
 
 
117
 
        :param volume: volume reference
118
 
        """
119
 
        self.nms.zvol.create(
120
 
            self._get_zvol_name(volume['name']),
121
 
            '%sG' % (volume['size'],),
122
 
            FLAGS.nexenta_blocksize, FLAGS.nexenta_sparse)
123
 
 
124
 
    def delete_volume(self, volume):
125
 
        """Destroy a zvol on appliance.
126
 
 
127
 
        :param volume: volume reference
128
 
        """
129
 
        try:
130
 
            self.nms.zvol.destroy(self._get_zvol_name(volume['name']), '')
131
 
        except nexenta.NexentaException as exc:
132
 
            if "zvol has children" in exc.args[1]:
133
 
                raise exception.VolumeIsBusy
134
 
            else:
135
 
                raise
136
 
 
137
 
    def create_snapshot(self, snapshot):
138
 
        """Create snapshot of existing zvol on appliance.
139
 
 
140
 
        :param snapshot: shapshot reference
141
 
        """
142
 
        self.nms.zvol.create_snapshot(
143
 
            self._get_zvol_name(snapshot['volume_name']),
144
 
            snapshot['name'], '')
145
 
 
146
 
    def create_volume_from_snapshot(self, volume, snapshot):
147
 
        """Create new volume from other's snapshot on appliance.
148
 
 
149
 
        :param volume: reference of volume to be created
150
 
        :param snapshot: reference of source snapshot
151
 
        """
152
 
        self.nms.zvol.clone(
153
 
            '%s@%s' % (self._get_zvol_name(snapshot['volume_name']),
154
 
                       snapshot['name']),
155
 
            self._get_zvol_name(volume['name']))
156
 
 
157
 
    def delete_snapshot(self, snapshot):
158
 
        """Delete volume's snapshot on appliance.
159
 
 
160
 
        :param snapshot: shapshot reference
161
 
        """
162
 
        try:
163
 
            self.nms.snapshot.destroy(
164
 
                '%s@%s' % (self._get_zvol_name(snapshot['volume_name']),
165
 
                           snapshot['name']),
166
 
                '')
167
 
        except nexenta.NexentaException as exc:
168
 
            if "snapshot has dependent clones" in exc.args[1]:
169
 
                raise exception.SnapshotIsBusy
170
 
            else:
171
 
                raise
172
 
 
173
 
    def local_path(self, volume):
174
 
        """Return local path to existing local volume.
175
 
 
176
 
        We never have local volumes, so it raises NotImplementedError.
177
 
 
178
 
        :raise: :py:exc:`NotImplementedError`
179
 
        """
180
 
        LOG.error(_("Call to local_path should not happen."
181
 
                        " Verify that use_local_volumes flag is turned off."))
182
 
        raise NotImplementedError
183
 
 
184
 
    def _do_export(self, _ctx, volume, ensure=False):
185
 
        """Do all steps to get zvol exported as LUN 0 at separate target.
186
 
 
187
 
        :param volume: reference of volume to be exported
188
 
        :param ensure: if True, ignore errors caused by already existing
189
 
            resources
190
 
        :return: iscsiadm-formatted provider location string
191
 
        """
192
 
        zvol_name = self._get_zvol_name(volume['name'])
193
 
        target_name = self._get_target_name(volume['name'])
194
 
        target_group_name = self._get_target_group_name(volume['name'])
195
 
 
196
 
        try:
197
 
            self.nms.iscsitarget.create_target({'target_name': target_name})
198
 
        except nexenta.NexentaException as exc:
199
 
            if not ensure or 'already configured' not in exc.args[1]:
200
 
                raise
201
 
            else:
202
 
                LOG.info(_('Ignored target creation error "%s"'
203
 
                                             ' while ensuring export'), exc)
204
 
        try:
205
 
            self.nms.stmf.create_targetgroup(target_group_name)
206
 
        except nexenta.NexentaException as exc:
207
 
            if not ensure or 'already exists' not in exc.args[1]:
208
 
                raise
209
 
            else:
210
 
                LOG.info(_('Ignored target group creation error "%s"'
211
 
                                             ' while ensuring export'), exc)
212
 
        try:
213
 
            self.nms.stmf.add_targetgroup_member(target_group_name,
214
 
                                                 target_name)
215
 
        except nexenta.NexentaException as exc:
216
 
            if not ensure or 'already exists' not in exc.args[1]:
217
 
                raise
218
 
            else:
219
 
                LOG.info(_('Ignored target group member addition error "%s"'
220
 
                                             ' while ensuring export'), exc)
221
 
        try:
222
 
            self.nms.scsidisk.create_lu(zvol_name, {})
223
 
        except nexenta.NexentaException as exc:
224
 
            if not ensure or 'in use' not in exc.args[1]:
225
 
                raise
226
 
            else:
227
 
                LOG.info(_('Ignored LU creation error "%s"'
228
 
                                             ' while ensuring export'), exc)
229
 
        try:
230
 
            self.nms.scsidisk.add_lun_mapping_entry(zvol_name, {
231
 
                'target_group': target_group_name,
232
 
                'lun': '0'})
233
 
        except nexenta.NexentaException as exc:
234
 
            if not ensure or 'view entry exists' not in exc.args[1]:
235
 
                raise
236
 
            else:
237
 
                LOG.info(_('Ignored LUN mapping entry addition error "%s"'
238
 
                                             ' while ensuring export'), exc)
239
 
        return '%s:%s,1 %s' % (FLAGS.nexenta_host,
240
 
                               FLAGS.nexenta_iscsi_target_portal_port,
241
 
                               target_name)
242
 
 
243
 
    def create_export(self, _ctx, volume):
244
 
        """Create new export for zvol.
245
 
 
246
 
        :param volume: reference of volume to be exported
247
 
        :return: iscsiadm-formatted provider location string
248
 
        """
249
 
        loc = self._do_export(_ctx, volume, ensure=False)
250
 
        return {'provider_location': loc}
251
 
 
252
 
    def ensure_export(self, _ctx, volume):
253
 
        """Recreate parts of export if necessary.
254
 
 
255
 
        :param volume: reference of volume to be exported
256
 
        """
257
 
        self._do_export(_ctx, volume, ensure=True)
258
 
 
259
 
    def remove_export(self, _ctx, volume):
260
 
        """Destroy all resources created to export zvol.
261
 
 
262
 
        :param volume: reference of volume to be unexported
263
 
        """
264
 
        zvol_name = self._get_zvol_name(volume['name'])
265
 
        target_name = self._get_target_name(volume['name'])
266
 
        target_group_name = self._get_target_group_name(volume['name'])
267
 
        self.nms.scsidisk.delete_lu(zvol_name)
268
 
 
269
 
        try:
270
 
            self.nms.stmf.destroy_targetgroup(target_group_name)
271
 
        except nexenta.NexentaException as exc:
272
 
            # We assume that target group is already gone
273
 
            LOG.warn(_('Got error trying to destroy target group'
274
 
                ' %(target_group)s, assuming it is already gone: %(exc)s'),
275
 
                {'target_group': target_group_name, 'exc': exc})
276
 
        try:
277
 
            self.nms.iscsitarget.delete_target(target_name)
278
 
        except nexenta.NexentaException as exc:
279
 
            # We assume that target is gone as well
280
 
            LOG.warn(_('Got error trying to delete target %(target)s,'
281
 
                ' assuming it is already gone: %(exc)s'),
282
 
                {'target': target_name, 'exc': exc})