def _ensure_share_mounted(self, nfs_share): mnt_flags = [] if self.shares.get(nfs_share) is not None: mnt_flags = self.shares[nfs_share].split() num_attempts = max(1, self.configuration.nfs_mount_attempts) for attempt in range(num_attempts): try: self._remotefsclient.mount(nfs_share, mnt_flags) return except Exception as e: if attempt == (num_attempts - 1): LOG.error('Mount failure for %(share)s after ' '%(count)d attempts.', {'share': nfs_share, 'count': num_attempts}) raise exception.NfsException(six.text_type(e)) LOG.debug('Mount attempt %(attempt)d failed: %(exc)s.\n' 'Retrying mount ...', {'attempt': attempt, 'exc': e}) time.sleep(1)
def _do_clone_volume(self, src_vol, src_vol_name, tgt_vol): cnfs_share = src_vol.provider_location tgt_vol_name = tgt_vol.name tgt_vol_path = self._get_local_volume_path(cnfs_share, tgt_vol_name) src_vol_path = self._get_local_volume_path(cnfs_share, src_vol_name) tgt_vol_path_spl = tgt_vol_path + "::snap:vxfs:" self._execute('ln', src_vol_path, tgt_vol_path_spl, run_as_root=True) LOG.debug( "VeritasNFSDriver: do_clone_volume %(src_vol_path)s " "%(tgt_vol_path)s %(tgt_vol_path_spl)s", { 'src_vol_path': src_vol_path, 'tgt_vol_path_spl': tgt_vol_path_spl, 'tgt_vol_path': tgt_vol_path }) if not os.path.exists(tgt_vol_path): self._execute('rm', '-f', tgt_vol_path_spl, run_as_root=True) msg = _("Filesnap over NFS is not supported, " "removing the ::snap:vxfs: file") LOG.error(msg) raise exception.NfsException(msg)
def _ensure_share_unmounted(self, nfs_share, mount_path=None): """Ensure that NFS share is unmounted on the host. :param nfs_share: NFS share name :param mount_path: mount path on the host """ num_attempts = max(1, self.configuration.nfs_mount_attempts) if mount_path is None: mount_path = self._get_mount_point_for_share(nfs_share) if mount_path not in self._remotefsclient._read_mounts(): LOG.info('NFS share %(share)s already unmounted from %(path)s.', { 'share': nfs_share, 'path': mount_path}) return for attempt in range(num_attempts): try: self._execute('umount', mount_path, run_as_root=True) LOG.debug('NFS share %(share)s was successfully unmounted ' 'from %(path)s.', { 'share': nfs_share, 'path': mount_path}) return except Exception as e: msg = six.text_type(e) if attempt == (num_attempts - 1): LOG.error('Unmount failure for %(share)s after ' '%(count)d attempts.', { 'share': nfs_share, 'count': num_attempts}) raise exception.NfsException(msg) LOG.warning('Unmount attempt %(attempt)d failed: %(msg)s. ' 'Retrying unmount %(share)s from %(path)s.', { 'attempt': attempt, 'msg': msg, 'share': nfs_share, 'path': mount_path}) greenthread.sleep(1)
def _ensure_share_mounted(self, nfs_share, mount_path=None): """Ensure that NFS share is mounted on the host. Unlike the parent method this one accepts mount_path as an optional parameter and uses it as a mount point if provided. :param nfs_share: NFS share name :param mount_path: mount path on the host """ mnt_flags = [] if self.shares.get(nfs_share) is not None: mnt_flags = self.shares[nfs_share].split() num_attempts = max(1, self.configuration.nfs_mount_attempts) for attempt in range(num_attempts): try: if mount_path is None: self._remotefsclient.mount(nfs_share, mnt_flags) else: if mount_path in self._remotefsclient._read_mounts(): LOG.info(_LI('Already mounted: %s'), mount_path) return self._execute('mkdir', '-p', mount_path, check_exit_code=False) self._remotefsclient._mount_nfs(nfs_share, mount_path, mnt_flags) return except Exception as e: if attempt == (num_attempts - 1): LOG.error(_LE('Mount failure for %(share)s after ' '%(count)d attempts.'), { 'share': nfs_share, 'count': num_attempts}) raise exception.NfsException(six.text_type(e)) LOG.warning( _LW('Mount attempt %(attempt)d failed: %(error)s. ' 'Retrying mount ...'), { 'attempt': attempt, 'error': e}) greenthread.sleep(1)
def do_setup(self, context): if not self.configuration.max_over_subscription_ratio > 0: msg = _("Config 'max_over_subscription_ratio' invalid. Must be > " "0: %s") % self.configuration.max_over_subscription_ratio LOG.error(msg) raise exception.NfsException(msg) package = 'mount.nfs' try: self._execute(package, check_exit_code=False, run_as_root=True) except OSError as exc: if exc.errno == errno.ENOENT: msg = _('%s is not installed') % package raise exception.NfsException(msg) else: raise lcfg = self.configuration LOG.info(_LI('Connecting to host: %s.'), lcfg.san_ip) host = lcfg.san_ip user = lcfg.san_login password = lcfg.san_password https_port = lcfg.zfssa_https_port credentials = ['san_ip', 'san_login', 'san_password', 'zfssa_data_ip'] for cred in credentials: if not getattr(lcfg, cred, None): exception_msg = _('%s not set in cinder.conf') % cred LOG.error(exception_msg) raise exception.CinderException(exception_msg) self.zfssa = factory_zfssa() self.zfssa.set_host(host, timeout=lcfg.zfssa_rest_timeout) auth_str = base64.encode_as_text('%s:%s' % (user, password)) self.zfssa.login(auth_str) self.zfssa.create_project(lcfg.zfssa_nfs_pool, lcfg.zfssa_nfs_project, compression=lcfg.zfssa_nfs_share_compression, logbias=lcfg.zfssa_nfs_share_logbias) share_args = { 'sharedav': 'rw', 'sharenfs': 'rw', 'root_permissions': '777', 'compression': lcfg.zfssa_nfs_share_compression, 'logbias': lcfg.zfssa_nfs_share_logbias } self.zfssa.create_share(lcfg.zfssa_nfs_pool, lcfg.zfssa_nfs_project, lcfg.zfssa_nfs_share, share_args) share_details = self.zfssa.get_share(lcfg.zfssa_nfs_pool, lcfg.zfssa_nfs_project, lcfg.zfssa_nfs_share) mountpoint = share_details['mountpoint'] self.mount_path = lcfg.zfssa_data_ip + ':' + mountpoint https_path = 'https://' + lcfg.zfssa_data_ip + ':' + https_port + \ '/shares' + mountpoint LOG.debug('NFS mount path: %s', self.mount_path) LOG.debug('WebDAV path to the share: %s', https_path) self.shares = {} mnt_opts = self.configuration.zfssa_nfs_mount_options self.shares[self.mount_path] = mnt_opts if len(mnt_opts) > 1 else None # Initialize the WebDAV client self.zfssa.set_webdav(https_path, auth_str) # Edit http service so that WebDAV requests are always authenticated args = {'https_port': https_port, 'require_login': True} self.zfssa.modify_service('http', args) self.zfssa.enable_service('http') if lcfg.zfssa_enable_local_cache: LOG.debug('Creating local cache directory %s.', lcfg.zfssa_cache_directory) self.zfssa.create_directory(lcfg.zfssa_cache_directory)
def _copy_volume_from_snapshot(self, snapshot, volume, volume_size, src_encryption_key_id=None, new_encryption_key_id=None): """Copy data from snapshot to destination volume. This is done with a qemu-img convert to raw/qcow2 from the snapshot qcow2. """ LOG.debug("Copying snapshot: %(snap)s -> volume: %(vol)s, " "volume_size: %(size)s GB", {'snap': snapshot.id, 'vol': volume.id, 'size': volume_size}) info_path = self._local_path_volume_info(snapshot.volume) snap_info = self._read_info_file(info_path) vol_path = self._local_volume_dir(snapshot.volume) forward_file = snap_info[snapshot.id] forward_path = os.path.join(vol_path, forward_file) # Find the file which backs this file, which represents the point # when this snapshot was created. img_info = self._qemu_img_info(forward_path, snapshot.volume.name) path_to_snap_img = os.path.join(vol_path, img_info.backing_file) path_to_new_vol = self._local_path_volume(volume) LOG.debug("will copy from snapshot at %s", path_to_snap_img) if self.configuration.nfs_qcow2_volumes: out_format = 'qcow2' else: out_format = 'raw' if new_encryption_key_id is not None: if src_encryption_key_id is None: message = _("Can't create an encrypted volume %(format)s " "from an unencrypted source." ) % {'format': out_format} LOG.error(message) # TODO(enriquetaso): handle unencrypted snap->encrypted vol raise exception.NfsException(message) keymgr = key_manager.API(CONF) new_key = keymgr.get(volume.obj_context, new_encryption_key_id) new_passphrase = \ binascii.hexlify(new_key.get_encoded()).decode('utf-8') # volume.obj_context is the owner of this request src_key = keymgr.get(volume.obj_context, src_encryption_key_id) src_passphrase = \ binascii.hexlify(src_key.get_encoded()).decode('utf-8') tmp_dir = volume_utils.image_conversion_dir() with tempfile.NamedTemporaryFile(prefix='luks_', dir=tmp_dir) as src_pass_file: with open(src_pass_file.name, 'w') as f: f.write(src_passphrase) with tempfile.NamedTemporaryFile(prefix='luks_', dir=tmp_dir) as new_pass_file: with open(new_pass_file.name, 'w') as f: f.write(new_passphrase) image_utils.convert_image( path_to_snap_img, path_to_new_vol, 'luks', passphrase_file=new_pass_file.name, src_passphrase_file=src_pass_file.name, run_as_root=self._execute_as_root) else: image_utils.convert_image(path_to_snap_img, path_to_new_vol, out_format, run_as_root=self._execute_as_root) self._set_rw_permissions_for_all(path_to_new_vol)