Ejemplo n.º 1
0
    def set_nas_security_options(self, is_new_cinder_install):
        """Determine the setting to use for Secure NAS options.

        Value of each NAS Security option is checked and updated. If the
        option is currently 'auto', then it is set to either true or false
        based upon if this is a new Cinder installation. The RemoteFS variable
        '_execute_as_root' will be updated for this driver.

        :param is_new_cinder_install: bool indication of new Cinder install
        """
        doc_html = "https://docs.openstack.org/cinder/latest" \
                   "/admin/blockstorage-nfs-backend.html"

        self._ensure_shares_mounted()
        if not self._mounted_shares:
            raise exception.NfsNoSharesMounted()

        nfs_mount = self._get_mount_point_for_share(self._mounted_shares[0])

        self.configuration.nas_secure_file_permissions = \
            self._determine_nas_security_option_setting(
                self.configuration.nas_secure_file_permissions,
                nfs_mount, is_new_cinder_install)

        LOG.debug('NAS variable secure_file_permissions setting is: %s',
                  self.configuration.nas_secure_file_permissions)

        if self.configuration.nas_secure_file_permissions == 'false':
            LOG.warning(
                "The NAS file permissions mode will be 666 "
                "(allowing other/world read & write access). "
                "This is considered an insecure NAS environment. "
                "Please see %s for information on a secure "
                "NFS configuration.", doc_html)

        self.configuration.nas_secure_file_operations = \
            self._determine_nas_security_option_setting(
                self.configuration.nas_secure_file_operations,
                nfs_mount, is_new_cinder_install)

        # If secure NAS, update the '_execute_as_root' flag to not
        # run as the root user; run as process' user ID.

        # TODO(eharney): need to separate secure NAS vs. execute as root.
        # There are requirements to run some commands as root even
        # when running in secure NAS mode. (i.e. read volume file
        # attached to an instance and owned by qemu:qemu)
        if self.configuration.nas_secure_file_operations == 'true':
            self._execute_as_root = False

        LOG.debug('NAS secure file operations setting is: %s',
                  self.configuration.nas_secure_file_operations)

        if self.configuration.nas_secure_file_operations == 'false':
            LOG.warning(
                "The NAS file operations will be run as "
                "root: allowing root level access at the storage "
                "backend. This is considered an insecure NAS "
                "environment. Please see %s "
                "for information on a secure NAS configuration.", doc_html)
Ejemplo n.º 2
0
    def _find_share(self, volume_size_in_gib):
        """Choose NFS share among available ones for given volume size.

        For instances with more than one share that meets the criteria, the
        share with the least "allocated" space will be selected.

        :param volume_size_in_gib: int size in GB
        """

        if not self._mounted_shares:
            raise exception.NfsNoSharesMounted()

        target_share = None
        target_share_reserved = 0

        for nfs_share in self._mounted_shares:
            if not self._is_share_eligible(nfs_share, volume_size_in_gib):
                continue
            _total_size, _total_available, total_allocated = \
                self._get_capacity_info(nfs_share)
            if target_share is not None:
                if target_share_reserved > total_allocated:
                    target_share = nfs_share
                    target_share_reserved = total_allocated
            else:
                target_share = nfs_share
                target_share_reserved = total_allocated

        if target_share is None:
            raise exception.NfsNoSuitableShareFound(
                volume_size=volume_size_in_gib)

        LOG.debug('Selected %s as target nfs share.', target_share)

        return target_share
Ejemplo n.º 3
0
    def set_nas_security_options(self, is_new_cinder_install):
        """Determine the setting to use for Secure NAS options.

        Value of each NAS Security option is checked and updated. If the
        option is currently 'auto', then it is set to either true or false
        based upon if this is a new Cinder installation. The RemoteFS variable
        '_execute_as_root' will be updated for this driver.

        :param is_new_cinder_install: bool indication of new Cinder install
        """
        doc_html = "http://docs.openstack.org/admin-guide-cloud/content" \
                   "/nfs_backend.html"

        self._ensure_shares_mounted()
        if not self._mounted_shares:
            raise exception.NfsNoSharesMounted()

        nfs_mount = self._get_mount_point_for_share(self._mounted_shares[0])

        self.configuration.nas_secure_file_permissions = \
            self._determine_nas_security_option_setting(
                self.configuration.nas_secure_file_permissions,
                nfs_mount, is_new_cinder_install)

        LOG.debug('NAS variable secure_file_permissions setting is: %s',
                  self.configuration.nas_secure_file_permissions)

        if self.configuration.nas_secure_file_permissions == 'false':
            LOG.warning(
                _LW("The NAS file permissions mode will be 666 "
                    "(allowing other/world read & write access). "
                    "This is considered an insecure NAS environment. "
                    "Please see %s for information on a secure "
                    "NFS configuration."), doc_html)

        self.configuration.nas_secure_file_operations = \
            self._determine_nas_security_option_setting(
                self.configuration.nas_secure_file_operations,
                nfs_mount, is_new_cinder_install)

        # If secure NAS, update the '_execute_as_root' flag to not
        # run as the root user; run as process' user ID.
        if self.configuration.nas_secure_file_operations == 'true':
            self._execute_as_root = False

        LOG.debug('NAS variable secure_file_operations setting is: %s',
                  self.configuration.nas_secure_file_operations)

        if self.configuration.nas_secure_file_operations == 'false':
            LOG.warning(
                _LW("The NAS file operations will be run as "
                    "root: allowing root level access at the storage "
                    "backend. This is considered an insecure NAS "
                    "environment. Please see %s "
                    "for information on a secure NAS configuration."),
                doc_html)
Ejemplo n.º 4
0
    def _find_share(self, volume_size_in_gib):
        """Choose NFS share among available ones for given volume size.

        For instances with more than one share that meets the criteria, the
        share with the least "allocated" space will be selected.

        :param volume_size_in_gib: int size in GB
        """

        if not self._mounted_shares:
            raise exception.NfsNoSharesMounted()

        target_share = None
        if self.configuration.nfs_round_robin:
            # Round Robin volume placement on shares

            LOG.debug(_("_find_share using round robin"))

            for nfs_share, pos in self._round_robin(self._mounted_shares):
                if not self._is_share_eligible(nfs_share, volume_size_in_gib):
                    continue
                target_share = nfs_share
                self.last_rr_pos = pos
                break
        else:
            # Place volume on share with the most free space.

            LOG.debug(_("_find_share using select most free"))

            target_share_reserved = 0

            for nfs_share in self._mounted_shares:
                if not self._is_share_eligible(nfs_share, volume_size_in_gib):
                    continue
                total_size, total_available, total_allocated = \
                    self._get_capacity_info(nfs_share)
                if target_share is not None:
                    if target_share_reserved > total_allocated:
                        target_share = nfs_share
                        target_share_reserved = total_allocated
                else:
                    target_share = nfs_share
                    target_share_reserved = total_allocated

        if target_share is None:
            raise exception.NfsNoSuitableShareFound(
                volume_size=volume_size_in_gib)

        LOG.debug('Selected %s as target nfs share.', target_share)

        return target_share
Ejemplo n.º 5
0
    def _find_share(self, volume_size_for):
        """Choose NFS share among available ones for given volume size. Current
        implementation looks for greatest capacity
        :param volume_size_for: int size in Gb
        """

        if not self._mounted_shares:
            raise exception.NfsNoSharesMounted()

        greatest_size = 0
        greatest_share = None

        for nfs_share in self._mounted_shares:
            capacity = self._get_available_capacity(nfs_share)[0]
            if capacity > greatest_size:
                greatest_share = nfs_share
                greatest_size = capacity

        if volume_size_for * 1024 * 1024 * 1024 > greatest_size:
            raise exception.NfsNoSuitableShareFound(
                volume_size=volume_size_for)
        return greatest_share
Ejemplo n.º 6
0
    def _find_share(self, volume_size_in_gib):
        """Choose NFS share among available ones for given volume size.

        First validation step: ratio of actual space (used_space / total_space)
        is less than 'nfs_used_ratio'.

        Second validation step: apparent space allocated (differs from actual
        space used when using sparse files) and compares the apparent available
        space (total_available * nfs_oversub_ratio) to ensure enough space is
        available for the new volume.

        For instances with more than one share that meets the criteria, the
        share with the least "allocated" space will be selected.

        :param volume_size_in_gib: int size in GB
        """

        if not self._mounted_shares:
            raise exception.NfsNoSharesMounted()

        target_share = None
        target_share_reserved = 0

        used_ratio = self.configuration.nfs_used_ratio
        oversub_ratio = self.configuration.nfs_oversub_ratio

        requested_volume_size = volume_size_in_gib * units.GiB

        for nfs_share in self._mounted_shares:
            total_size, total_available, total_allocated = \
                self._get_capacity_info(nfs_share)
            apparent_size = max(0, total_size * oversub_ratio)
            apparent_available = max(0, apparent_size - total_allocated)
            used = (total_size - total_available) / total_size
            if used > used_ratio:
                # NOTE(morganfainberg): We check the used_ratio first since
                # with oversubscription it is possible to not have the actual
                # available space but be within our oversubscription limit
                # therefore allowing this share to still be selected as a valid
                # target.
                LOG.debug(_('%s is above nfs_used_ratio'), nfs_share)
                continue
            if apparent_available <= requested_volume_size:
                LOG.debug(_('%s is above nfs_oversub_ratio'), nfs_share)
                continue
            if total_allocated / total_size >= oversub_ratio:
                LOG.debug(_('%s reserved space is above nfs_oversub_ratio'),
                          nfs_share)
                continue

            if target_share is not None:
                if target_share_reserved > total_allocated:
                    target_share = nfs_share
                    target_share_reserved = total_allocated
            else:
                target_share = nfs_share
                target_share_reserved = total_allocated

        if target_share is None:
            raise exception.NfsNoSuitableShareFound(
                volume_size=volume_size_in_gib)

        LOG.debug(_('Selected %s as target nfs share.'), target_share)

        return target_share