Example #1
0
    def update_access(self, dataset_name, access_rules, add_rules,
                      delete_rules, make_all_ro=False, executor=None):
        """Update access rules for given ZFS dataset exported as NFS share."""
        rw_rules = []
        ro_rules = []
        for rule in access_rules:
            if rule['access_type'].lower() != 'ip':
                msg = _("Only IP access type allowed for NFS protocol.")
                raise exception.InvalidShareAccess(reason=msg)
            if (rule['access_level'] == constants.ACCESS_LEVEL_RW and
                    not make_all_ro):
                rw_rules.append(self._get_parsed_access_to(rule['access_to']))
            elif (rule['access_level'] in (constants.ACCESS_LEVEL_RW,
                                           constants.ACCESS_LEVEL_RO)):
                ro_rules.append(self._get_parsed_access_to(rule['access_to']))
            else:
                msg = _("Unsupported access level provided - "
                        "%s.") % rule['access_level']
                raise exception.InvalidShareAccess(reason=msg)

        rules = []
        if self.is_kernel_version:
            if rw_rules:
                rules.append(
                    "rw=%s,no_root_squash" % ":".join(rw_rules))
            if ro_rules:
                rules.append("ro=%s,no_root_squash" % ":".join(ro_rules))
            rules_str = "sharenfs=" + (','.join(rules) or 'off')
        else:
            for rule in rw_rules:
                rules.append("%s:rw,no_root_squash" % rule)
            for rule in ro_rules:
                rules.append("%s:ro,no_root_squash" % rule)
            rules_str = "sharenfs=" + (' '.join(rules) or 'off')

        out, err = self.zfs(
            'list', '-r', dataset_name.split('/')[0], executor=executor)
        data = self.parse_zfs_answer(out)
        for datum in data:
            if datum['NAME'] == dataset_name:
                self.zfs("set", rules_str, dataset_name)
                break
        else:
            LOG.warning(
                "Dataset with '%(name)s' NAME is absent on backend. "
                "Access rules were not applied.", {'name': dataset_name})

        # NOTE(vponomaryov): Setting of ZFS share options does not remove rules
        # that were added and then removed. So, remove them explicitly.
        if delete_rules and access_rules:
            mountpoint = self.get_zfs_option(dataset_name, 'mountpoint')
            for rule in delete_rules:
                if rule['access_type'].lower() != 'ip':
                    continue
                access_to = self._get_parsed_access_to(rule['access_to'])
                export_location = access_to + ':' + mountpoint
                self.execute(
                    'sudo', 'exportfs', '-u', export_location,
                    executor=executor,
                )
Example #2
0
 def _check_share_access(self, share_proto, access_type):
     if share_proto == 'NFS' and access_type != 'ip':
         reason = _('Only "ip" access type is allowed for ' 'NFS shares.')
         LOG.warning(reason)
         raise exception.InvalidShareAccess(reason=reason)
     elif share_proto != 'NFS':
         reason = _('Invalid NAS protocol: %s') % share_proto
         raise exception.InvalidShareAccess(reason=reason)
Example #3
0
 def _check_share_access(self, share_proto, access_type):
     if share_proto == 'CIFS' and access_type != 'user':
         reason = ('Only USER access type is allowed for ' 'CIFS shares.')
         LOG.warning(reason)
         raise exception.InvalidShareAccess(reason=reason)
     elif share_proto == 'NFS' and access_type not in ('ip', 'user'):
         reason = ('Only IP or USER access types are allowed for '
                   'NFS shares.')
         LOG.warning(reason)
         raise exception.InvalidShareAccess(reason=reason)
     elif share_proto not in ('NFS', 'CIFS'):
         reason = ('Unsupported protocol \"%s\" specified for '
                   'access rule.') % share_proto
         raise exception.InvalidShareAccess(reason=reason)
Example #4
0
    def allow_access(self, context, share, access, share_server=None):
        """Allow access to a share.

        Currently only IP based access control is supported.
        """

        if access['access_type'] != 'ip':
            raise exception.InvalidShareAccess(
                reason=_('only IP access type allowed'))

        httpclient = httplib2.Http(disable_ssl_certificate_validation=True,
                                   timeout=None)
        sop_share_id = self._get_share_id_by_name(httpclient, share['id'])

        if access['access_level'] == 'rw':
            access_level = True
        elif access['access_level'] == 'ro':
            access_level = False
        else:
            raise exception.InvalidShareAccess(
                reason=(_('Unsupported level of access was provided - %s') %
                        access['access_level']))
        payload = {
            'action': 'add-access-rule',
            'all-squash': True,
            'anongid': 65534,
            'anonuid': 65534,
            'host-specification': access['access_to'],
            'description': '',
            'read-write': access_level,
            'root-squash': False,
            'tags': 'nfs',
            'name': '%s-%s' % (share['id'], access['access_to']),
        }
        sopuri = '/shares/'
        headers = dict(Authorization=self.get_sop_auth_header())
        uri = self.sop_target + '/sopapi' + sopuri + sop_share_id
        resp_headers, resp_content = httpclient.request(
            uri, 'POST',
            body=json.dumps(payload),
            headers=headers)
        resp_code = int(resp_headers['status'])
        if resp_code == 202:
            job_loc = resp_headers['location']
            self._wait_for_job_completion(httpclient, job_loc)
        else:
            raise exception.SopAPIError(err=_('received error: %s') %
                                        resp_headers['status'])
Example #5
0
    def allow_access_nfs(self, pool, project, share, access):
        """Allow an IP access to a share through NFS."""
        if access['access_type'] != 'ip':
            reason = _('Only ip access type allowed.')
            raise exception.InvalidShareAccess(reason)

        ip = access['access_to']
        details = self.get_share(pool, project, share)
        sharenfs = details['sharenfs']

        if sharenfs == 'on' or sharenfs == 'rw':
            LOG.debug('Share %s has read/write permission'
                      'open to all.', share)
            return
        if sharenfs == 'off':
            sharenfs = 'sec=sys'
        if ip in sharenfs:
            LOG.debug(
                'Access to share %(share)s via NFS '
                'already granted to %(ip)s.', {
                    'share': share,
                    'ip': ip
                })
            return

        entry = (',rw=@%s' % ip)
        if '/' not in ip:
            entry = "%s/32" % entry
        arg = {'sharenfs': sharenfs + entry}
        self.modify_share(pool, project, share, arg)
Example #6
0
 def update_access(self,
                   context,
                   share,
                   access_rules,
                   add_rules,
                   delete_rules,
                   share_server=None):
     """Update access rules for given share."""
     for access in access_rules:
         if access['access_type'].lower() != 'user':
             msg = _("Only 'user' access type allowed!")
             LOG.error(msg)
             raise exception.InvalidShareAccess(reason=msg)
     volume_name = self._get_volume_name(context, share)
     try:
         # 'update_access' is called before share is removed, so this
         #  method shouldn`t raise exception if share does
         #  not exist actually
         if not self._maprfs_util.volume_exists(volume_name):
             LOG.warning('Can not get share %s.', share['name'])
             return
         # check update
         if add_rules or delete_rules:
             self._maprfs_util.remove_volume_ace_rules(
                 volume_name, delete_rules)
             self._maprfs_util.add_volume_ace_rules(volume_name, add_rules)
         else:
             self._maprfs_util.set_volume_ace(volume_name, access_rules)
     except exception.ProcessExecutionError:
         msg = (_('Failed to update access for share %(name)s.') % {
             'name': share['name']
         })
         LOG.exception(msg)
         raise exception.MapRFSException(msg=msg)
Example #7
0
    def _nfs_allow_access(self, share, access):
        """Allow access to nfs share."""
        access_type = access['access_type']
        if access_type != 'ip':
            message = _('Only "ip" access type allowed for the NFS '
                        'protocol.')
            LOG.error(message)
            raise exception.InvalidShareAccess(reason=message)

        export_path = self._get_container_path(share)
        access_ip = access['access_to']
        access_level = access['access_level']
        share_id = self._isilon_api.lookup_nfs_export(export_path)

        share_access_group = 'clients'
        if access_level == const.ACCESS_LEVEL_RO:
            share_access_group = 'read_only_clients'

        # Get current allowed clients
        export = self._get_existing_nfs_export(share_id)
        current_clients = export[share_access_group]

        # Format of ips could be '10.0.0.2', or '10.0.0.2, 10.0.0.0/24'
        ips = list()
        ips.append(access_ip)
        ips.extend(current_clients)
        export_params = {share_access_group: ips}
        url = '{0}/platform/1/protocols/nfs/exports/{1}'.format(
            self._server_url, share_id)
        resp = self._isilon_api.request('PUT', url, data=export_params)
        resp.raise_for_status()
Example #8
0
    def deny_access(self, context, share, access, share_server=None):
        """Deny access to a share.

        :param context: The `context.RequestContext` object for the request
        :param share: Share to which access will be denied.
        :param access: Information about the access that will be denied, e.g.
        host and type of access denied.
        :param share_server: Data structure with share server information.
        Not used by this driver.
        """
        if ('nfs', 'ip') != (share['share_proto'].lower(),
                             access['access_type'].lower()):
            msg = _("Only NFS protocol and IP access type currently "
                    "supported.")
            raise exception.InvalidShareAccess(reason=msg)

        LOG.debug(
            "Sending HNAS request to deny access to share:"
            " %(shr_id)s.", {'shr_id': six.text_type(share['id'])})

        share_id = self._get_hnas_share_id(share['id'])

        self.hnas.deny_access(share_id, access['access_to'],
                              share['share_proto'], access['access_level'])

        LOG.info(_LI("Access denied successfully to share: %(shr)s."),
                 {'shr': six.text_type(share['id'])})
Example #9
0
    def allow_access(self, local_path, share, access_type, access):
        """Allow access to one or more vm instances."""

        if access_type != 'ip':
            raise exception.InvalidShareAccess('Only ip access type '
                                               'supported.')

        # check if present in export
        try:
            out, __ = self._execute('exportfs', run_as_root=True)
        except exception.ProcessExecutionError as e:
            msg = (_('Failed to check exports on the systems. '
                     ' Error: %s.') % e)
            LOG.error(msg)
            raise exception.GPFSException(msg)

        out = re.search(re.escape(local_path) + '[\s\n]*' + re.escape(access),
                        out)
        if out is not None:
            raise exception.ShareAccessExists(access_type=access_type,
                                              access=access)

        export_opts = self._get_export_options(share)

        cmd = ['exportfs', '-o', export_opts,
               ':'.join([access, local_path])]
        try:
            self._publish_access(*cmd)
        except exception.ProcessExecutionError as e:
            msg = (_('Failed to allow access for share %(sharename)s. '
                     'Error: %(excmsg)s.') %
                   {'sharename': share['name'],
                    'excmsg': e})
            LOG.error(msg)
            raise exception.GPFSException(msg)
Example #10
0
    def _cifs_allow_access(self, share, hnas_share_id, add_rules):
        for rule in add_rules:
            if rule['access_type'].lower() != 'user':
                msg = _("Only USER access type currently supported for CIFS. "
                        "Share provided %(share)s with rule %(r_id)s type "
                        "%(type)s allowing permission to %(to)s.") % {
                            'share': share['id'],
                            'type': rule['access_type'],
                            'r_id': rule['id'],
                            'to': rule['access_to']
                        }
                raise exception.InvalidShareAccess(reason=msg)

            if rule['access_level'] == constants.ACCESS_LEVEL_RW:
                # Adding permission acr = Allow Change&Read
                permission = 'acr'
            else:
                # Adding permission ar = Allow Read
                permission = 'ar'

            formatted_user = rule['access_to'].replace('\\', '\\\\')

            self.hnas.cifs_allow_access(hnas_share_id, formatted_user,
                                        permission)

            LOG.debug(
                "Added %(rule)s rule for user/group %(user)s to share "
                "%(share)s.", {
                    'rule': rule['access_level'],
                    'user': rule['access_to'],
                    'share': share['id']
                })
Example #11
0
    def _nfs_update_access(self, share, hnas_share_id, access_rules):
        host_list = []

        for rule in access_rules:
            if rule['access_type'].lower() != 'ip':
                msg = _("Only IP access type currently supported for NFS. "
                        "Share provided %(share)s with rule type "
                        "%(type)s.") % {
                            'share': share['id'],
                            'type': rule['access_type']
                        }
                raise exception.InvalidShareAccess(reason=msg)

            if rule['access_level'] == constants.ACCESS_LEVEL_RW:
                host_list.append(rule['access_to'] + '(' +
                                 rule['access_level'] + ',norootsquash)')
            else:
                host_list.append(rule['access_to'] + '(' +
                                 rule['access_level'] + ')')

        self.hnas.update_nfs_access_rule(hnas_share_id, host_list)

        if host_list:
            LOG.debug("Share %(share)s has the rules: %(rules)s", {
                'share': share['id'],
                'rules': ', '.join(host_list)
            })
        else:
            LOG.debug("Share %(share)s has no rules.", {'share': share['id']})
Example #12
0
File: gpfs.py Project: vkmc/manila
    def allow_access(self, local_path, share, access):
        """Allow access to the host."""

        if access['access_type'] != 'ip':
            raise exception.InvalidShareAccess(reason='Only ip access type '
                                               'supported.')
        err_msg = 'Failed to check exports on the system.'
        out = self._execute_mmnfs_command(('list', '-n', local_path), err_msg)

        options_not_allowed = ['access_type=ro', 'access_type=rw']
        export_opts = self.get_export_options(share, access, 'CES',
                                              options_not_allowed)

        out = re.search(re.escape(local_path), out)

        if out is None:
            cmd = [
                'add', local_path, '-c',
                access['access_to'] + '(' + export_opts + ')'
            ]
        else:
            cmd = [
                'change', local_path, '--nfsadd',
                access['access_to'] + '(' + export_opts + ')'
            ]

        err_msg = ('Failed to allow access for share %s.' % share['name'])
        self._execute_mmnfs_command(cmd, err_msg)
Example #13
0
    def _allow_access(self, base_path, share, access):
        """Allow access to the share."""
        if access['access_type'] != 'ip':
            raise exception.InvalidShareAccess('Only IP access type allowed')

        access = ganesha_utils.fixup_access_rule(access)

        cf = {}
        accid = access['id']
        name = share['name']
        export_name = "%s--%s" % (name, accid)
        ganesha_utils.patch(
            cf, self.export_template, {
                'EXPORT': {
                    'Export_Id': self.ganesha.get_export_id(),
                    'Path': os.path.join(base_path, name),
                    'Pseudo': os.path.join(base_path, export_name),
                    'Tag': accid,
                    'CLIENT': {
                        'Clients': access['access_to']
                    },
                    'FSAL': self._fsal_hook(base_path, share, access)
                }
            })
        self.ganesha.add_export(export_name, cf)
Example #14
0
    def _allow_access(self, context, share, access, share_server=None):
        if access['access_type'] != CEPHX_ACCESS_TYPE:
            raise exception.InvalidShareAccess(
                reason=_("Only 'cephx' access type allowed."))

        if access['access_level'] == constants.ACCESS_LEVEL_RO:
            raise exception.InvalidShareAccessLevel(
                level=constants.ACCESS_LEVEL_RO)

        ceph_auth_id = access['access_to']

        # We need to check here rather than the API or Manila Client to see
        # if the ceph_auth_id is the same as the one specified for Manila's
        # usage. This is due to the fact that the API and the Manila client
        # cannot read the contents of the Manila configuration file. If it
        # is the same, we need to error out.
        if ceph_auth_id == CONF.cephfs_auth_id:
            error_message = (_('Ceph authentication ID %s must be different '
                             'than the one the Manila service uses.') %
                             ceph_auth_id)
            raise exception.InvalidInput(message=error_message)

        auth_result = self.volume_client.authorize(self._share_path(share),
                                                   ceph_auth_id)

        return auth_result['auth_key']
Example #15
0
    def deny_access(self, context, share, access, share_server=None):
        """Deny access to a share that's using cert based auth.

        Remove the SSL CN (Common Name) that's allowed to access the server.
        """

        if access['access_type'] != ACCESS_TYPE_CERT:
            raise exception.InvalidShareAccess(
                _("Only 'cert' access type "
                  "allowed for access "
                  "removal."))
        exp_locn = share.get('export_location', None)
        gluster_addr = self.gluster_used_vols_dict.get(exp_locn)

        gargs, gkw = gluster_addr.make_gluster_args('volume', 'reset',
                                                    gluster_addr.volume,
                                                    AUTH_SSL_ALLOW)
        try:
            self._execute(*gargs, **gkw)
        except exception.ProcessExecutionError as exc:
            msg = (_("Error in gluster volume reset during deny access. "
                     "Volume: %(volname)s, Option: %(option)s, "
                     "Error: %(error)s"), {
                         'volname': gluster_addr.volume,
                         'option': AUTH_SSL_ALLOW,
                         'error': exc.stderr
                     })
            LOG.error(msg)
            raise exception.GlusterfsException(msg)

        # TODO(deepakcs) Remove this once ssl options can be
        # set dynamically.
        self._restart_gluster_vol(gluster_addr)
Example #16
0
    def deny_access(self, context, share, access, share_server=None):
        """Deny access to a share that's using cert based auth.

        Remove the SSL CN (Common Name) that's allowed to access the server.
        """

        if access['access_type'] != ACCESS_TYPE_CERT:
            raise exception.InvalidShareAccess(
                _("Only 'cert' access type "
                  "allowed for access "
                  "removal."))

        gargs, gkw = self.gluster_address.make_gluster_args(
            'volume', 'reset', self.gluster_address.volume, AUTH_SSL_ALLOW)
        try:
            self._execute(*gargs, **gkw)
        except exception.ProcessExecutionError as exc:
            LOG.error(
                _("Error in gluster volume reset during deny access."
                  "Volume: %(volname)s, Option: %(option)s, "
                  "Error: %(error)s"), {
                      'volname': self.gluster_address.volume,
                      'option': AUTH_SSL_ALLOW,
                      'error': exc.stderr
                  })
            raise
Example #17
0
    def allow_access(self, context, share, share_name, access):
        """Allows access to the CIFS share for a given user."""
        if access['access_type'] != 'user':
            msg = _("Cluster Mode supports only 'user' type for share access"
                    " rules with CIFS protocol.")
            raise exception.InvalidShareAccess(reason=msg)

        user_name = access['access_to']

        if access['access_level'] == constants.ACCESS_LEVEL_RW:
            readonly = False
        elif access['access_level'] == constants.ACCESS_LEVEL_RO:
            readonly = True
        else:
            raise exception.InvalidShareAccessLevel(
                level=access['access_level'])

        target, share_name = self._get_export_location(share)
        try:
            self._client.add_cifs_share_access(share_name,
                                               user_name,
                                               readonly)
        except netapp_api.NaApiError as e:
            if e.code == netapp_api.EDUPLICATEENTRY:
                # Duplicate entry, so use specific exception.
                raise exception.ShareAccessExists(
                    access_type=access['access_type'], access=access)
            raise e
Example #18
0
    def extend_share(self, share, new_size, share_server):
        share_proto = share['share_proto']
        share_name = share['name']

        # The unit is in sectors.
        size = int(new_size) * units.Mi * 2
        share_url_type = self.helper._get_share_url_type(share_proto)

        share = self.helper._get_share_by_name(share_name, share_url_type)
        if not share:
            err_msg = (_("Can not get share ID by share %s.")
                       % share_name)
            LOG.error(err_msg)
            raise exception.InvalidShareAccess(reason=err_msg)

        fsid = share['FSID']
        fs_info = self.helper._get_fs_info_by_id(fsid)

        current_size = int(fs_info['CAPACITY']) / units.Mi / 2
        if current_size > new_size:
            err_msg = (_("New size for extend must be equal or bigger than "
                         "current size on array. (current: %(size)s, "
                         "new: %(new_size)s).")
                       % {'size': current_size, 'new_size': new_size})

            LOG.error(err_msg)
            raise exception.InvalidInput(reason=err_msg)
        self.helper._change_share_size(fsid, size)
Example #19
0
    def allow_access(self, context, share, access, share_server=None):
        """Allow access to a share using certs.

        Add the SSL CN (Common Name) that's allowed to access the server.
        """

        if access['access_type'] != ACCESS_TYPE_CERT:
            raise exception.InvalidShareAccess(
                _("Only 'cert' access type "
                  "allowed"))

        gargs, gkw = self.gluster_address.make_gluster_args(
            'volume', 'set', self.gluster_address.volume, AUTH_SSL_ALLOW,
            access['access_to'])
        try:
            self._execute(*gargs, **gkw)
        except exception.ProcessExecutionError as exc:
            LOG.error(
                _("Error in gluster volume set during allow access."
                  "Volume: %(volname)s, Option: %(option)s, "
                  "access_to: %(access_to)s, Error: %(error)s"), {
                      'volname': self.gluster_address.volume,
                      'option': AUTH_SSL_ALLOW,
                      'access_to': access['access_to'],
                      'error': exc.stderr
                  })
            raise
Example #20
0
    def _allow_access(self, context, share, access, share_server=None):
        if access['access_type'] != CEPHX_ACCESS_TYPE:
            raise exception.InvalidShareAccess(
                reason=_("Only 'cephx' access type allowed."))

        ceph_auth_id = access['access_to']

        # We need to check here rather than the API or Manila Client to see
        # if the ceph_auth_id is the same as the one specified for Manila's
        # usage. This is due to the fact that the API and the Manila client
        # cannot read the contents of the Manila configuration file. If it
        # is the same, we need to error out.
        if ceph_auth_id == CONF.cephfs_auth_id:
            error_message = (_('Ceph authentication ID %s must be different '
                             'than the one the Manila service uses.') %
                             ceph_auth_id)
            raise exception.InvalidInput(message=error_message)

        # TODO(rraja): Log the Ceph point release version, once available, in
        # which the volume client can enable read-only access.
        if not getattr(self.volume_client, 'version', None):
            if access['access_level'] == constants.ACCESS_LEVEL_RO:
                raise exception.InvalidShareAccessLevel(
                    level=constants.ACCESS_LEVEL_RO)
            auth_result = self.volume_client.authorize(
                self._share_path(share), ceph_auth_id)
        else:
            readonly = access['access_level'] == constants.ACCESS_LEVEL_RO
            auth_result = self.volume_client.authorize(
                self._share_path(share), ceph_auth_id, readonly=readonly,
                tenant_id=share['project_id'])

        return auth_result['auth_key']
Example #21
0
 def allow_access(self,
                  ctx,
                  share,
                  access_type,
                  access_to,
                  access_level=None):
     """Allow access to share."""
     if not share['host']:
         msg = _("Share host is None")
         raise exception.InvalidShare(reason=msg)
     if share['status'] not in ["available"]:
         msg = _("Share status must be available")
         raise exception.InvalidShare(reason=msg)
     policy.check_policy(ctx, 'share', 'allow_access')
     values = {
         'share_id': share['id'],
         'access_type': access_type,
         'access_to': access_to,
         'access_level': access_level,
     }
     access = [
         a for a in self.db.share_access_get_all_by_type_and_access(
             ctx, share['id'], access_type, access_to)
         if a['state'] != 'error'
     ]
     if access:
         raise exception.ShareAccessExists(access_type=access_type,
                                           access=access_to)
     if access_level not in constants.ACCESS_LEVELS + (None, ):
         msg = _("Invalid share access level: %s.") % access_level
         raise exception.InvalidShareAccess(reason=msg)
     access = self.db.share_access_create(ctx, values)
     self.share_rpcapi.allow_access(ctx, share, access)
     return access
Example #22
0
    def allow_access(self, local_path, share, access, error_on_exists=True):
        """Allow access to one or more vm instances."""

        if access['access_type'] != 'ip':
            raise exception.InvalidShareAccess(reason='Only ip access type '
                                                      'supported.')

        if error_on_exists:
            # check if present in export
            out = re.search(
                re.escape(local_path) + '[\s\n]*'
                + re.escape(access['access_to']), self._get_exports())

            if out is not None:
                access_type = access['access_type']
                access_to = access['access_to']
                raise exception.ShareAccessExists(access_type=access_type,
                                                  access=access_to)

        export_opts = self.get_export_options(share, access, 'KNFS')
        cmd = ['exportfs', '-o', export_opts,
               ':'.join([access['access_to'], local_path])]
        try:
            self._publish_access(*cmd)
        except exception.ProcessExecutionError:
            msg = _('Failed to allow access for share %s.') % share['name']
            LOG.exception(msg)
            raise exception.GPFSException(msg)
Example #23
0
    def _cifs_deny_access(self, share, access, share_server):
        """Deny access to CIFS share."""
        vdm_name = self._get_share_server_name(share_server)
        share_name = share['id']

        if access['access_type'] != 'user':
            reason = _('Only user access type allowed for CIFS share')
            raise exception.InvalidShareAccess(reason=reason)

        user_name = access['access_to']

        access_level = access['access_level']
        if access_level == const.ACCESS_LEVEL_RW:
            cifs_access = constants.CIFS_ACL_FULLCONTROL
        else:
            cifs_access = constants.CIFS_ACL_READ

        # Check if CIFS server exists.
        server_name = vdm_name
        status, server = self._get_context('CIFSServer').get(
            server_name, vdm_name)
        if status != constants.STATUS_OK:
            message = (_("CIFS server %s not found.") % server_name)
            LOG.error(message)
            raise exception.EMCVnxXMLAPIError(err=message)

        self._get_context('CIFSShare').deny_share_access(vdm_name,
                                                         share_name,
                                                         user_name,
                                                         server['domain'],
                                                         access=cifs_access)
Example #24
0
    def _manage_access(self, access_type, access_to, cbk):
        """Manage share access with cbk.

        Adjust the exports of the Gluster-NFS server using cbk.

        :param access_type: type of access allowed in Manila
        :type access_type: string
        :param access_to: ip of the guest whose share access is managed
        :type access_to: string
        :param cbk: callback to adjust the exports of NFS server

        Following is the description of cbk(explist, host).

        :param explist: list of hosts that have access to the share
        :type explist: list
        :param host: ip address derived from the access object
        :type host: string
        :returns: bool (cbk leaves ddict intact) or None (cbk modifies ddict)
        """

        if access_type != 'ip':
            raise exception.InvalidShareAccess('only ip access type allowed')
        export_vol_list = self._get_vol_exports()
        if cbk(export_vol_list, access_to):
            return

        if export_vol_list:
            argseq = ((NFS_RPC_AUTH_ALLOW, ','.join(export_vol_list)),
                      (NFS_RPC_AUTH_REJECT, None))
        else:
            argseq = ((NFS_RPC_AUTH_ALLOW, None),
                      (NFS_RPC_AUTH_REJECT, '*'))
        for args in argseq:
            self.gluster_manager.set_vol_option(*args)
Example #25
0
    def update_access(self, share_name, access_rules):
        """Update access to the share."""
        rw_list = []
        ro_list = []
        for rule in access_rules:
            if rule['access_type'].lower() != 'ip':
                msg = _('Only IP access type is supported.')
                raise exception.InvalidShareAccess(reason=msg)
            else:
                if rule['access_level'] == common.ACCESS_LEVEL_RW:
                    rw_list.append(rule['access_to'])
                else:
                    ro_list.append(rule['access_to'])

        share_opts = {
            'auth_type': 'none',
            'read_write': ':'.join(rw_list),
            'read_only': ':'.join(ro_list),
            'recursive': 'true',
            'anonymous_rw': 'true',
            'anonymous': 'true',
            'extra_options': 'anon=0',
        }
        self.nms.netstorsvc.share_folder(
            'svc:/network/nfs/server:default',
            self._get_share_path(share_name), share_opts)
Example #26
0
    def _allow_access(self, context, share, access, share_server=None):
        """Allow access to the share."""
        share_proto = share['share_proto']
        access_type = access['access_type']
        access_level = access['access_level']
        access_to = access['access_to']
        LOG.debug(
            'share_proto: %(share_proto)s '
            'access_type: %(access_type)s '
            'access_level: %(access_level)s '
            'access_to: %(access_to)s', {
                'share_proto': share_proto,
                'access_type': access_type,
                'access_level': access_level,
                'access_to': access_to
            })

        self._check_share_access(share_proto, access_type)

        vol_name = self.private_storage.get(share['id'], 'volName')
        vol_name_timestamp = self._get_timestamp_from_vol_name(vol_name)
        host_name = self._gen_host_name(vol_name_timestamp, access_level)

        host_list = self.api_executor.get_host_list()
        LOG.debug(
            'vol_name: %(vol_name)s '
            'access_level: %(access_level)s '
            'host_name: %(host_name)s '
            'host_list: %(host_list)s ', {
                'vol_name': vol_name,
                'access_level': access_level,
                'host_name': host_name,
                'host_list': host_list
            })
        filter_host_list = self._get_vol_host(host_list, vol_name_timestamp)
        if len(filter_host_list) == 0:
            # if host does not exist, create a host for the share
            self.api_executor.add_host(host_name, access_to)
        elif (len(filter_host_list) == 1
              and filter_host_list[0]['name'] == host_name):
            # if the host exist, and this host is for the same access right,
            # add ip to the host.
            ipv4_list = filter_host_list[0]['ipv4']
            if access_to not in ipv4_list:
                ipv4_list.append(access_to)
            LOG.debug('vol_host["ipv4"]: %s', filter_host_list[0]['ipv4'])
            LOG.debug('ipv4_list: %s', ipv4_list)
            self.api_executor.edit_host(host_name, ipv4_list)
        else:
            # Until now, share of QNAP NAS can only apply one access level for
            # all ips. "rw" for some ips and "ro" for else is not allowed.
            support_level = (constants.ACCESS_LEVEL_RW
                             if access_level == constants.ACCESS_LEVEL_RO else
                             constants.ACCESS_LEVEL_RO)
            reason = _('Share only supports one access '
                       'level: %s') % support_level
            LOG.error(reason)
            raise exception.InvalidShareAccess(reason=reason)
        access = 1 if access_level == constants.ACCESS_LEVEL_RO else 0
        self.api_executor.set_nfs_access(vol_name, access, host_name)
Example #27
0
    def update_access(self,
                      context,
                      share,
                      access_rules,
                      add_rules,
                      delete_rules,
                      share_server=None):

        if share['share_proto'] != 'NFS':
            return

        validate_access_rules(access_rules)

        share_id = share['id']

        export = self._to_volume_path(share)
        LOG.info("Changing access on %s", share_server)
        levels = {rule['access_level'] for rule in access_rules if rule}
        if not levels:
            return

        if len(levels) > 1:
            raise exception.InvalidShareAccess(
                reason=
                "Mixing access levels on the same share is not supported: %s" %
                levels)

        access_type = _MANILA_TO_VAST_ACCESS_LEVEL[levels.pop()]

        def reverse_lookup(dns):
            if RE_IS_IP.match(dns):
                return [dns]
            try:
                hostname, aliaslist, ipaddrlist = socket.gethostbyname_ex(dns)
            except socket.gaierror as exc:
                LOG.error("Failed to resolve host '%s': %s (ignoring)", dns,
                          exc)
                return []

            LOG.info("resolved %s: %s", hostname, ", ".join(ipaddrlist))
            return ipaddrlist

        allowed_hosts = ",".join(
            sorted(ip for rule in access_rules if rule
                   for ip in reverse_lookup(rule['access_to'])))

        LOG.info("Changing access on %s -> %s (%s)", export, allowed_hosts,
                 access_type)

        data = dict(name=share_id,
                    squash="ROOT_SQUASH",
                    access_type=access_type,
                    allowed_hosts=allowed_hosts)
        policy = self._get_policy(share_id)
        if policy:
            self.vms_session.patch("viewpolicies/{}".format(policy.id),
                                   data=data)
        else:
            self.vms_session.post("viewpolicies", data=data)
Example #28
0
    def _allow_access(self, context, share, access, share_server=None):
        if access['access_type'] != CEPHX_ACCESS_TYPE:
            raise exception.InvalidShareAccessType(type=access['access_type'])

        ceph_auth_id = access['access_to']

        # We need to check here rather than the API or Manila Client to see
        # if the ceph_auth_id is the same as the one specified for Manila's
        # usage. This is due to the fact that the API and the Manila client
        # cannot read the contents of the Manila configuration file. If it
        # is the same, we need to error out.
        if ceph_auth_id == CONF.cephfs_auth_id:
            error_message = (_('Ceph authentication ID %s must be different '
                               'than the one the Manila service uses.') %
                             ceph_auth_id)
            raise exception.InvalidShareAccess(reason=error_message)

        argdict = {
            "vol_name": self.volname,
            "sub_name": share["id"],
            "auth_id": ceph_auth_id,
            "tenant_id": share["project_id"],
        }
        if share["share_group_id"] is not None:
            argdict.update({"group_name": share["share_group_id"]})

        readonly = access['access_level'] == constants.ACCESS_LEVEL_RO

        if readonly:
            argdict.update({"access_level": "r"})
        else:
            argdict.update({"access_level": "rw"})

        try:
            auth_result = rados_command(self.rados_client,
                                        "fs subvolume authorize", argdict)
        except exception.ShareBackendException as e:
            if 'not allowed' in str(e).lower():
                msg = ("Access to client %(client)s is not allowed. "
                       "Reason: %(reason)s")
                msg_payload = {'client': ceph_auth_id, 'reason': e}
                raise exception.InvalidShareAccess(reason=msg % msg_payload)
            raise

        return auth_result
Example #29
0
    def _validate_access_level(protocol, access_type, access_level, fshare):

        readonly = access_level == 'ro'
        snapshot = HPE3ParMediator._is_share_from_snapshot(fshare)

        if snapshot and not readonly:
            reason = _('3PAR shares from snapshots require read-only access')
            LOG.error(reason)
            raise exception.InvalidShareAccess(reason=reason)

        if protocol == 'smb' and access_type == 'ip' and snapshot != readonly:
            msg = (_("Invalid CIFS access rule. HPE 3PAR optionally supports "
                     "IP access rules for CIFS shares, but they must be "
                     "read-only for shares from snapshots and read-write for "
                     "other shares. Use the required CIFS 'user' access rules "
                     "to refine access."))
            LOG.error(msg)
            raise exception.InvalidShareAccess(reason=msg)
Example #30
0
    def update_access(self, context, share, access_rules, add_rules,
                      delete_rules, share_server=None):
        """Update access rules for given share.

        Using access_rules list for both adding and deleting rules.
        :param context: The `context.RequestContext` object for the request
        :param share: Share that will have its access rules updated.
        :param access_rules: All access rules for given share. This list
        is enough to update the access rules for given share.
        :param add_rules: Empty List or List of access rules which should be
        added. access_rules already contains these rules. Not used by this
        driver.
        :param delete_rules: Empty List or List of access rules which should be
        removed. access_rules doesn't contain these rules. Not used by
        this driver.
        :param share_server: Data structure with share server information.
        Not used by this driver.
        """
        LOG.debug('Updating access to share %s.', share)
        rw_list = []
        ro_list = []
        security_contexts = []
        for rule in access_rules:
            if rule['access_type'].lower() != 'ip':
                msg = _('Only IP access type is supported.')
                raise exception.InvalidShareAccess(reason=msg)
            else:
                if rule['access_level'] == common.ACCESS_LEVEL_RW:
                    rw_list.append(rule['access_to'])
                else:
                    ro_list.append(rule['access_to'])

        def append_sc(addr_list, sc_type):
            for addr in addr_list:
                address_mask = addr.strip().split('/', 1)
                address = address_mask[0]
                ls = [{"allow": True, "etype": "network", "entity": address}]
                if len(address_mask) == 2:
                    try:
                        mask = int(address_mask[1])
                        if mask != 32:
                            ls[0]['mask'] = mask
                    except Exception:
                        raise exception.InvalidInput(
                            reason=_(
                                '<{}> is not a valid access parameter').format(
                                    addr))
                new_sc = {"securityModes": ["sys"]}
                new_sc[sc_type] = ls
                security_contexts.append(new_sc)

        append_sc(rw_list, 'readWriteList')
        append_sc(ro_list, 'readOnlyList')
        data = {"securityContexts": security_contexts}
        url = 'nas/nfs/' + PATH_DELIMITER.join(
            (self.pool_name, self.fs_prefix, share['name']))
        self.nef.put(url, data)