103
104
run_as_root=True)
104
105
volume_groups = out.split()
105
106
if not FLAGS.volume_group in volume_groups:
106
raise exception.NovaException(_("volume group %s doesn't exist")
107
exception_message = (_("volume group %s doesn't exist")
107
108
% FLAGS.volume_group)
109
raise exception.VolumeBackendAPIException(data=exception_message)
109
111
def _create_volume(self, volume_name, sizestr):
110
112
self._try_execute('lvcreate', '-L', sizestr, '-n',
111
113
volume_name, FLAGS.volume_group, run_as_root=True)
113
115
def _copy_volume(self, srcstr, deststr, size_in_g):
116
# Use O_DIRECT to avoid thrashing the system buffer cache
117
direct_flags = ('iflag=direct', 'oflag=direct')
119
# Check whether O_DIRECT is supported
121
self._execute('dd', 'count=0', 'if=%s' % srcstr, 'of=%s' % deststr,
122
*direct_flags, run_as_root=True)
123
except exception.ProcessExecutionError:
114
127
self._execute('dd', 'if=%s' % srcstr, 'of=%s' % deststr,
115
128
'count=%d' % (size_in_g * 1024), 'bs=1M',
129
*direct_flags, run_as_root=True)
118
131
def _volume_not_present(self, volume_name):
119
132
path_name = '%s/%s' % (FLAGS.volume_group, volume_name)
264
285
def ensure_export(self, context, volume):
265
286
"""Synchronously recreates an export for a logical volume."""
267
iscsi_target = self.db.volume_get_iscsi_target_num(context,
269
except exception.NotFound:
270
LOG.info(_("Skipping ensure_export. No iscsi_target "
271
"provisioned for volume: %s"), volume['id'])
287
# NOTE(jdg): tgtadm doesn't use the iscsi_targets table
288
# TODO(jdg): In the future move all of the dependent stuff into the
289
# cooresponding target admin class
290
if not isinstance(self.tgtadm, iscsi.TgtAdm):
292
iscsi_target = self.db.volume_get_iscsi_target_num(context,
294
except exception.NotFound:
295
LOG.info(_("Skipping ensure_export. No iscsi_target "
296
"provisioned for volume: %s"), volume['id'])
299
iscsi_target = 1 # dummy value when using TgtAdm
274
301
iscsi_name = "%s%s" % (FLAGS.iscsi_target_prefix, volume['name'])
275
302
volume_path = "/dev/%s/%s" % (FLAGS.volume_group, volume['name'])
304
# NOTE(jdg): For TgtAdm case iscsi_name is the ONLY param we need
305
# should clean this all up at some point in the future
277
306
self.tgtadm.create_iscsi_target(iscsi_name, iscsi_target,
278
0, volume_path, check_exit_code=False)
308
check_exit_code=False)
280
310
def _ensure_iscsi_targets(self, context, host):
281
311
"""Ensure that target ids have been created in datastore."""
282
host_iscsi_targets = self.db.iscsi_target_count_by_host(context, host)
283
if host_iscsi_targets >= FLAGS.iscsi_num_targets:
285
# NOTE(vish): Target ids start at 1, not 0.
286
for target_num in xrange(1, FLAGS.iscsi_num_targets + 1):
287
target = {'host': host, 'target_num': target_num}
288
self.db.iscsi_target_create_safe(context, target)
312
# NOTE(jdg): tgtadm doesn't use the iscsi_targets table
313
# TODO(jdg): In the future move all of the dependent stuff into the
314
# cooresponding target admin class
315
if not isinstance(self.tgtadm, iscsi.TgtAdm):
316
host_iscsi_targets = self.db.iscsi_target_count_by_host(context,
318
if host_iscsi_targets >= FLAGS.iscsi_num_targets:
321
# NOTE(vish): Target ids start at 1, not 0.
322
for target_num in xrange(1, FLAGS.iscsi_num_targets + 1):
323
target = {'host': host, 'target_num': target_num}
324
self.db.iscsi_target_create_safe(context, target)
290
326
def create_export(self, context, volume):
291
327
"""Creates an export for a logical volume."""
292
self._ensure_iscsi_targets(context, volume['host'])
293
iscsi_target = self.db.volume_allocate_iscsi_target(context,
296
330
iscsi_name = "%s%s" % (FLAGS.iscsi_target_prefix, volume['name'])
297
331
volume_path = "/dev/%s/%s" % (FLAGS.volume_group, volume['name'])
299
self.tgtadm.create_iscsi_target(iscsi_name, iscsi_target,
302
333
model_update = {}
303
if FLAGS.iscsi_helper == 'tgtadm':
335
# TODO(jdg): In the future move all of the dependent stuff into the
336
# cooresponding target admin class
337
if not isinstance(self.tgtadm, iscsi.TgtAdm):
339
self._ensure_iscsi_targets(context, volume['host'])
340
iscsi_target = self.db.volume_allocate_iscsi_target(context,
344
lun = 1 # For tgtadm the controller is lun 0, dev starts at lun 1
345
iscsi_target = 0 # NOTE(jdg): Not used by tgtadm
347
# NOTE(jdg): For TgtAdm case iscsi_name is the ONLY param we need
348
# should clean this all up at some point in the future
349
tid = self.tgtadm.create_iscsi_target(iscsi_name,
307
353
model_update['provider_location'] = _iscsi_location(
308
FLAGS.iscsi_ip_address, iscsi_target, iscsi_name, lun)
354
FLAGS.iscsi_ip_address, tid, iscsi_name, lun)
309
355
return model_update
311
357
def remove_export(self, context, volume):
312
358
"""Removes an export for a logical volume."""
314
iscsi_target = self.db.volume_get_iscsi_target_num(context,
316
except exception.NotFound:
317
LOG.info(_("Skipping remove_export. No iscsi_target "
318
"provisioned for volume: %s"), volume['id'])
360
location = volume['provider_location'].split(' ')
363
LOG.warning(_("Jacked... didn't get an iqn"))
366
# NOTE(jdg): tgtadm doesn't use the iscsi_targets table
367
# TODO(jdg): In the future move all of the dependent stuff into the
368
# cooresponding target admin class
369
if not isinstance(self.tgtadm, iscsi.TgtAdm):
371
iscsi_target = self.db.volume_get_iscsi_target_num(context,
373
except exception.NotFound:
374
LOG.info(_("Skipping remove_export. No iscsi_target "
375
"provisioned for volume: %s"), volume['id'])
322
381
# ietadm show will exit with an error
323
382
# this export has already been removed
324
self.tgtadm.show_target(iscsi_target)
383
self.tgtadm.show_target(iscsi_target, iqn=iqn)
325
384
except Exception as e:
326
385
LOG.info(_("Skipping remove_export. No iscsi_target "
327
386
"is presently exported for volume: %s"), volume['id'])
454
513
def check_for_export(self, context, volume_id):
455
514
"""Make sure volume is exported."""
457
tid = self.db.volume_get_iscsi_target_num(context, volume_id)
515
vol_uuid_file = 'volume-%s' % volume_id
516
volume_path = os.path.join(FLAGS.volumes_dir, vol_uuid_file)
517
if os.path.isfile(volume_path):
518
iqn = '%s%s' % (FLAGS.iscsi_target_prefix,
521
raise exception.PersistentVolumeFileNotFound(volume_id=volume_id)
523
# TODO(jdg): In the future move all of the dependent stuff into the
524
# cooresponding target admin class
525
if not isinstance(self.tgtadm, iscsi.TgtAdm):
526
tid = self.db.volume_get_iscsi_target_num(context, volume_id)
459
self.tgtadm.show_target(tid)
531
self.tgtadm.show_target(tid, iqn=iqn)
460
532
except exception.ProcessExecutionError, e:
461
533
# Instances remount read-only in this case.
462
534
# /etc/init.d/iscsitarget restart and rebooting nova-volume