def _zero_volume(path, volume_size): """Write zeros over the specified path :param path: logical volume path :param size: number of zeros to write """ bs = units.Mi direct_flags = ('oflag=direct',) sync_flags = () remaining_bytes = volume_size # The loop efficiently writes zeros using dd, # and caters for versions of dd that don't have # the easier to use iflag=count_bytes option. while remaining_bytes: zero_blocks = remaining_bytes / bs seek_blocks = (volume_size - remaining_bytes) / bs zero_cmd = ('dd', 'bs=%s' % bs, 'if=/dev/zero', 'of=%s' % path, 'seek=%s' % seek_blocks, 'count=%s' % zero_blocks) zero_cmd += direct_flags zero_cmd += sync_flags if zero_blocks: utils.execute(*zero_cmd, run_as_root=True) remaining_bytes %= bs bs /= units.Ki # Limit to 3 iterations # Use O_DIRECT with initial block size and fdatasync otherwise direct_flags = () sync_flags = ('conv=fdatasync',)
def clear_volume(path): """Obfuscate the logical volume. :param path: logical volume path """ volume_clear = CONF.libvirt.volume_clear if volume_clear not in ('none', 'shred', 'zero'): LOG.error(_LE("ignoring unrecognized volume_clear='%s' value"), volume_clear) volume_clear = 'zero' if volume_clear == 'none': return volume_clear_size = int(CONF.libvirt.volume_clear_size) * units.Mi volume_size = get_volume_size(path) if volume_clear_size != 0 and volume_clear_size < volume_size: volume_size = volume_clear_size if volume_clear == 'zero': # NOTE(p-draigbrady): we could use shred to do the zeroing # with -n0 -z, however only versions >= 8.22 perform as well as dd _zero_volume(path, volume_size) elif volume_clear == 'shred': utils.execute('shred', '-n3', '-s%d' % volume_size, path, run_as_root=True) else: raise exception.Invalid( _("volume_clear='%s' is not handled") % volume_clear)
def clear_volume(path): """Obfuscate the logical volume. :param path: logical volume path """ volume_clear = CONF.libvirt.volume_clear if volume_clear not in ('none', 'shred', 'zero'): LOG.error(_LE("ignoring unrecognized volume_clear='%s' value"), volume_clear) volume_clear = 'zero' if volume_clear == 'none': return volume_clear_size = int(CONF.libvirt.volume_clear_size) * units.Mi volume_size = get_volume_size(path) if volume_clear_size != 0 and volume_clear_size < volume_size: volume_size = volume_clear_size if volume_clear == 'zero': # NOTE(p-draigbrady): we could use shred to do the zeroing # with -n0 -z, however only versions >= 8.22 perform as well as dd _zero_volume(path, volume_size) elif volume_clear == 'shred': utils.execute('shred', '-n3', '-s%d' % volume_size, path, run_as_root=True) else: raise exception.Invalid(_("volume_clear='%s' is not handled") % volume_clear)
def clear_volume(path): """Obfuscate the logical volume. :param path: logical volume path """ volume_clear = CONF.libvirt.volume_clear if volume_clear == 'none': return volume_clear_size = int(CONF.libvirt.volume_clear_size) * units.Mi try: volume_size = get_volume_size(path) except exception.VolumeBDMPathNotFound: LOG.warn(_LW('ignoring missing logical volume %(path)s'), {'path': path}) return if volume_clear_size != 0 and volume_clear_size < volume_size: volume_size = volume_clear_size if volume_clear == 'zero': # NOTE(p-draigbrady): we could use shred to do the zeroing # with -n0 -z, however only versions >= 8.22 perform as well as dd _zero_volume(path, volume_size) elif volume_clear == 'shred': utils.execute('shred', '-n3', '-s%d' % volume_size, path, run_as_root=True)
def remove_volumes(paths): """Remove one or more logical volume.""" errors = [] for path in paths: clear_volume(path) lvremove = ('lvremove', '-f', path) try: utils.execute(*lvremove, attempts=3, run_as_root=True) except processutils.ProcessExecutionError as exp: errors.append(six.text_type(exp)) if errors: raise exception.VolumesNotRemoved(reason=(', ').join(errors))
def _deallocate_pcidevice_for_instance(self, instance): """ Remove the UUID from PCI device spec. """ if CONF.pci_passthrough_whitelist and instance: pci_devs = jsonutils.loads(utils.load_file(CONF.fsl_sriov.pci_devices)) for dev in pci_devs: if instance.uuid == dev['instance_uuid']: dev['instance_uuid'] = None pfname = dev['pf_vf_name'] intbridge = CONF.neutron.ovs_bridge utils.execute('ovs-vsctl', '--no-wait', 'del-port', intbridge , pfname , run_as_root=True) utils.write_to_file(CONF.fsl_sriov.pci_devices, jsonutils.dumps(pci_devs))
def create_volume(target, device, cipher, key_size, key): """Sets up a dmcrypt mapping :param target: device mapper logical device name :param device: underlying block device :param cipher: encryption cipher string digestible by cryptsetup :param key_size: encryption key size :param key: encryption key as an array of unsigned bytes """ cmd = ('cryptsetup', 'create', target, device, '--cipher=' + cipher, '--key-size=' + str(key_size), '--key-file=-') key = ''.join(map(lambda byte: "%02x" % byte, key)) utils.execute(*cmd, process_input=key, run_as_root=True)
def _is_pci_device_available(self, instance_uuid): pci_devs = jsonutils.loads(utils.load_file(CONF.fsl_sriov.pci_devices)) assignable_pci_device = None for dev in pci_devs: if dev['instance_uuid'] is None: assignable_pci_device = dev['dev_id'] dev['instance_uuid'] = instance_uuid pfname = dev['pf_vf_name'] intbridge = CONF.neutron.ovs_bridge utils.execute('ovs-vsctl', '--no-wait', 'add-port', intbridge , pfname , '--', 'set', 'interface', pfname, 'type=vf_inic', run_as_root=True) break utils.write_to_file(CONF.fsl_sriov.pci_devices, jsonutils.dumps(pci_devs)) return assignable_pci_device
def create_volume(vg, lv, size, sparse=False): """Create LVM image. Creates a LVM image with given size. :param vg: existing volume group which should hold this image :param lv: name for this image (logical volume) :size: size of image in bytes :sparse: create sparse logical volume """ vg_info = get_volume_group_info(vg) free_space = vg_info['free'] def check_size(vg, lv, size): if size > free_space: raise RuntimeError( _('Insufficient Space on Volume Group %(vg)s.' ' Only %(free_space)db available,' ' but %(size)db required' ' by volume %(lv)s.') % { 'vg': vg, 'free_space': free_space, 'size': size, 'lv': lv }) if sparse: preallocated_space = 64 * units.Mi check_size(vg, lv, preallocated_space) if free_space < size: LOG.warn( _LW('Volume group %(vg)s will not be able' ' to hold sparse volume %(lv)s.' ' Virtual volume size is %(size)db,' ' but free space on volume group is' ' only %(free_space)db.'), { 'vg': vg, 'free_space': free_space, 'size': size, 'lv': lv }) cmd = ('lvcreate', '-L', '%db' % preallocated_space, '--virtualsize', '%db' % size, '-n', lv, vg) else: check_size(vg, lv, size) cmd = ('lvcreate', '-L', '%db' % size, '-n', lv, vg) utils.execute(*cmd, run_as_root=True, attempts=3)
def get_volume_group_info(vg): """Return free/used/total space info for a volume group in bytes :param vg: volume group name :returns: A dict containing: :total: How big the filesystem is (in bytes) :free: How much space is free (in bytes) :used: How much space is used (in bytes) """ out, err = utils.execute('vgs', '--noheadings', '--nosuffix', '--separator', '|', '--units', 'b', '-o', 'vg_size,vg_free', vg, run_as_root=True) info = out.split('|') if len(info) != 2: raise RuntimeError(_("vg %s must be LVM volume group") % vg) return { 'total': int(info[0]), 'free': int(info[1]), 'used': int(info[0]) - int(info[1]) }
def volume_info(path): """Get logical volume info. :param path: logical volume path :returns: Return a dict object including info of given logical volume : Data format example : {'#Seg': '1', 'Move': '', 'Log': '', 'Meta%': '', 'Min': '-1', : ... : 'Free': '9983', 'LV': 'volume-aaa', 'Host': 'xyz.com', : 'Active': 'active', 'Path': '/dev/vg/volume-aaa', '#LV': '3', : 'Maj': '-1', 'VSize': '50.00g', 'VFree': '39.00g', 'Pool': '', : 'VG Tags': '', 'KMaj': '253', 'Convert': '', 'LProfile': '', : '#Ext': '12799', 'Attr': '-wi-a-----', 'VG': 'vg', : ... : 'LSize': '1.00g', '#PV': '1', '#VMdaCps': 'unmanaged'} """ out, err = utils.execute('lvs', '-o', 'vg_all,lv_all', '--separator', '|', path, run_as_root=True) info = [line.split('|') for line in out.splitlines()] if len(info) != 2: raise RuntimeError(_("Path %s must be LVM logical volume") % path) return dict(zip(*info))
def get_volume_openstack_group_info(vg): """Return free/used/total space info for a volume group in bytes :param vg: volume group name :returns: A dict containing: :total: How big the vg is (in bytes) :free: How much space is free (in bytes) :used: How much space is used (in bytes) """ out, err = utils.execute('lvs', '--noheadings', '--nosuffix', '--separator', '|', '--units', 'b', '-o', 'lv_size,lv_name,vg_size', vg, run_as_root=True) lvlist = [line.strip() for line in out.splitlines()] vg_total = 0 vg_used = 0 for lv in lvlist: info = lv.split('|') if len(info) != 3: raise RuntimeError(_("vg %s must be LVM volume group") % vg) if vg_total == 0: vg_total = int(info[2]) if info[1].startswith('volume-') and len(info[1]) == 43: vg_used = vg_used + int(info[0]) else: vg_total = vg_total - int(info[0]) return {'total': vg_total, 'free': vg_total - vg_used, 'used': vg_used}
def get_volume_openstack_group_info(vg): """Return free/used/total space info for a volume group in bytes :param vg: volume group name :returns: A dict containing: :total: How big the vg is (in bytes) :free: How much space is free (in bytes) :used: How much space is used (in bytes) """ out, err = utils.execute('lvs', '--noheadings', '--nosuffix', '--separator', '|', '--units', 'b', '-o', 'lv_size,lv_name,vg_size', vg, run_as_root=True) lvlist = [line.strip() for line in out.splitlines()] vg_total = 0 vg_used = 0 for lv in lvlist: info = lv.split('|') if len(info) != 3: raise RuntimeError(_("vg %s must be LVM volume group") % vg) if vg_total == 0: vg_total = int(info[2]) if info[1].startswith('volume-') and len(info[1]) == 43: vg_used = vg_used + int(info[0]) else: vg_total = vg_total - int(info[0]) return {'total':vg_total, 'free': vg_total - vg_used, 'used': vg_used}
def get_volume_size(path): """Get logical volume size in bytes. :param path: logical volume path """ out, _err = utils.execute('blockdev', '--getsize64', path, run_as_root=True) return int(out)
def create_volume(vg, lv, size, sparse=False): """Create LVM image. Creates a LVM image with given size. :param vg: existing volume group which should hold this image :param lv: name for this image (logical volume) :size: size of image in bytes :sparse: create sparse logical volume """ vg_info = get_volume_group_info(vg) free_space = vg_info['free'] def check_size(vg, lv, size): if size > free_space: raise RuntimeError(_('Insufficient Space on Volume Group %(vg)s.' ' Only %(free_space)db available,' ' but %(size)db required' ' by volume %(lv)s.') % {'vg': vg, 'free_space': free_space, 'size': size, 'lv': lv}) if sparse: preallocated_space = 64 * units.Mi check_size(vg, lv, preallocated_space) if free_space < size: LOG.warn(_LW('Volume group %(vg)s will not be able' ' to hold sparse volume %(lv)s.' ' Virtual volume size is %(size)db,' ' but free space on volume group is' ' only %(free_space)db.'), {'vg': vg, 'free_space': free_space, 'size': size, 'lv': lv}) cmd = ('lvcreate', '-L', '%db' % preallocated_space, '--virtualsize', '%db' % size, '-n', lv, vg) else: check_size(vg, lv, size) cmd = ('lvcreate', '-L', '%db' % size, '-n', lv, vg) utils.execute(*cmd, run_as_root=True, attempts=3)
def delete_volume(target): """Deletes a dmcrypt mapping :param target: name of the mapped logical device """ try: utils.execute('cryptsetup', 'remove', target, run_as_root=True) except processutils.ProcessExecutionError as e: # cryptsetup returns 4 when attempting to destroy a non-existent # dm-crypt device. It indicates that the device is invalid, which # means that the device is invalid (i.e., it has already been # destroyed). if e.exit_code == 4: LOG.debug("Ignoring exit code 4, volume already destroyed") else: with excutils.save_and_reraise_exception(): LOG.error(_LE("Could not disconnect encrypted volume " "%(volume)s. If dm-crypt device is still active " "it will have to be destroyed manually for " "cleanup to succeed."), {'volume': target})
def list_volumes(vg): """List logical volumes paths for given volume group. :param vg: volume group name :returns: Return a logical volume list for given volume group : Data format example : ['volume-aaa', 'volume-bbb', 'volume-ccc'] """ out, err = utils.execute('lvs', '--noheadings', '-o', 'lv_name', vg, run_as_root=True) return [line.strip() for line in out.splitlines()]
def delete_volume(target): """Deletes a dmcrypt mapping :param target: name of the mapped logical device """ try: utils.execute('cryptsetup', 'remove', target, run_as_root=True) except processutils.ProcessExecutionError as e: # cryptsetup returns 4 when attempting to destroy a non-existent # dm-crypt device. It indicates that the device is invalid, which # means that the device is invalid (i.e., it has already been # destroyed). if e.exit_code == 4: LOG.debug("Ignoring exit code 4, volume already destroyed") else: with excutils.save_and_reraise_exception(): LOG.error( "Could not disconnect encrypted volume " "%(volume)s. If dm-crypt device is still active " "it will have to be destroyed manually for " "cleanup to succeed.", {'volume': target})
def get_volume_size(path): """Get logical volume size in bytes. :param path: logical volume path :raises: processutils.ProcessExecutionError if getting the volume size fails in some unexpected way. :raises: exception.VolumeBDMPathNotFound if the volume path does not exist. """ out, _err = utils.execute('blockdev', '--getsize64', path, run_as_root=True) return int(out)
def create_volume(target, device, cipher, key_size, key): """Sets up a dmcrypt mapping :param target: device mapper logical device name :param device: underlying block device :param cipher: encryption cipher string digestible by cryptsetup :param key_size: encryption key size :param key: encoded encryption key bytestring """ cmd = ('cryptsetup', 'create', target, device, '--cipher=' + cipher, '--key-size=' + str(key_size), '--key-file=-') key = binascii.hexlify(key).decode('utf-8') try: utils.execute(*cmd, process_input=key, run_as_root=True) except processutils.ProcessExecutionError as e: with excutils.save_and_reraise_exception(): LOG.error( "Could not start encryption for disk %(device)s: " "%(exception)s", { 'device': device, 'exception': e })
def create_volume(target, device, cipher, key_size, key): """Sets up a dmcrypt mapping :param target: device mapper logical device name :param device: underlying block device :param cipher: encryption cipher string digestible by cryptsetup :param key_size: encryption key size :param key: encryption key as an array of unsigned bytes """ cmd = ('cryptsetup', 'create', target, device, '--cipher=' + cipher, '--key-size=' + str(key_size), '--key-file=-') key = ''.join(map(lambda byte: "%02x" % byte, key)) try: utils.execute(*cmd, process_input=key, run_as_root=True) except processutils.ProcessExecutionError as e: with excutils.save_and_reraise_exception(): LOG.error( _LE("Could not start encryption for disk %(device)s: " "%(exception)s"), { 'device': device, 'exception': e })
def create_volume(target, device, cipher, key_size, key): """Sets up a dmcrypt mapping :param target: device mapper logical device name :param device: underlying block device :param cipher: encryption cipher string digestible by cryptsetup :param key_size: encryption key size :param key: encryption key as an array of unsigned bytes """ cmd = ('cryptsetup', 'create', target, device, '--cipher=' + cipher, '--key-size=' + str(key_size), '--key-file=-') key = ''.join(map(lambda byte: "%02x" % byte, key)) try: utils.execute(*cmd, process_input=key, run_as_root=True) except processutils.ProcessExecutionError as e: with excutils.save_and_reraise_exception(): LOG.error(_LE("Could not start encryption for disk %(device)s: " "%(exception)s"), {'device': device, 'exception': e})
def create_volume(target, device, cipher, key_size, key): """Sets up a dmcrypt mapping :param target: device mapper logical device name :param device: underlying block device :param cipher: encryption cipher string digestible by cryptsetup :param key_size: encryption key size :param key: encoded encryption key bytestring """ cmd = ('cryptsetup', 'create', target, device, '--cipher=' + cipher, '--key-size=' + str(key_size), '--key-file=-') key = binascii.hexlify(key).decode('utf-8') try: utils.execute(*cmd, process_input=key, run_as_root=True) except processutils.ProcessExecutionError as e: with excutils.save_and_reraise_exception(): LOG.error("Could not start encryption for disk %(device)s: " "%(exception)s", {'device': device, 'exception': e})
def get_volume_group_info(vg): """Return free/used/total space info for a volume group in bytes :param vg: volume group name :returns: A dict containing: :total: How big the filesystem is (in bytes) :free: How much space is free (in bytes) :used: How much space is used (in bytes) """ out, err = utils.execute('vgs', '--noheadings', '--nosuffix', '--separator', '|', '--units', 'b', '-o', 'vg_size,vg_free', vg, run_as_root=True) info = out.split('|') if len(info) != 2: raise RuntimeError(_("vg %s must be LVM volume group") % vg) return {'total': int(info[0]), 'free': int(info[1]), 'used': int(info[0]) - int(info[1])}
def snapshot_delete(self): # NOTE (rmk): Snapshot volumes are automatically zeroed by LVM cmd = ('lvremove', '-f', self.snapshot_path) libvirt_utils.execute(*cmd, run_as_root=True, attempts=3)
def snapshot_create(self): size = CONF.libvirt_lvm_snapshot_size cmd = ('lvcreate', '-L', size, '-s', '--name', self.snapshot_name, self.path) libvirt_utils.execute(*cmd, run_as_root=True, attempts=3)
def snapshot_create(self): size = CONF.libvirt_lvm_snapshot_size cmd = ("lvcreate", "-L", size, "-s", "--name", self.snapshot_name, self.path) libvirt_utils.execute(*cmd, run_as_root=True, attempts=3)
def delete_volume(target): """Deletes a dmcrypt mapping :param target: name of the mapped logical device """ utils.execute('cryptsetup', 'remove', target, run_as_root=True)