def __call__(self, value): if value is None or value.strip(' ') is '': message = _("Invalid configuration. hpe3par_fpg must be set.") LOG.error(message) raise exception.HPE3ParInvalid(err=message) ips = [] values = value.split(",") # Extract pool name pool_name = values.pop(0).strip() # values will now be ['ip1', ...] if len(values) < self.min_ip: msg = (_("Require at least %s IPs configured per " "pool") % self.min_ip) raise exception.HPE3ParInvalid(err=msg) if len(values) > self.max_ip: msg = (_("Cannot configure IPs more than max supported " "%s IPs per pool") % self.max_ip) raise exception.HPE3ParInvalid(err=msg) for ip_addr in values: ip_addr = types.String.__call__(self, ip_addr.strip()) try: ips.append(types.IPAddress.__call__(self, ip_addr)) except ValueError as verror: raise exception.HPE3ParInvalid(err=verror) fpg = {pool_name: ips} return fpg
def _validate_pool_ips(addresses, conf_pool_ips): # Pool configured IP addresses should be subset of IP addresses # retured from vfs if not set(conf_pool_ips) <= set(addresses): msg = _("Incorrect configuration. " "Configuration pool IP address did not match with " "IP addresses at 3par array") raise exception.HPE3ParInvalid(err=msg)
def do_setup(self, context): """Any initialization the share driver does while starting.""" LOG.info(_LI("Starting share driver %(driver_name)s (%(version)s)"), { 'driver_name': self.__class__.__name__, 'version': self.VERSION }) if not self.driver_handles_share_servers: self.share_ip_address = self.configuration.hpe3par_share_ip_address if not self.share_ip_address: raise exception.HPE3ParInvalid( _("Unsupported configuration. " "hpe3par_share_ip_address must be set when " "driver_handles_share_servers is False.")) mediator = hpe_3par_mediator.HPE3ParMediator( hpe3par_username=self.configuration.hpe3par_username, hpe3par_password=self.configuration.hpe3par_password, hpe3par_api_url=self.configuration.hpe3par_api_url, hpe3par_debug=self.configuration.hpe3par_debug, hpe3par_san_ip=self.configuration.hpe3par_san_ip, hpe3par_san_login=self.configuration.hpe3par_san_login, hpe3par_san_password=self.configuration.hpe3par_san_password, hpe3par_san_ssh_port=self.configuration.hpe3par_san_ssh_port, hpe3par_fstore_per_share=( self.configuration.hpe3par_fstore_per_share), hpe3par_require_cifs_ip=self.configuration.hpe3par_require_cifs_ip, hpe3par_share_ip_address=( self.configuration.hpe3par_share_ip_address), hpe3par_cifs_admin_access_username=( self.configuration.hpe3par_cifs_admin_access_username), hpe3par_cifs_admin_access_password=( self.configuration.hpe3par_cifs_admin_access_password), hpe3par_cifs_admin_access_domain=( self.configuration.hpe3par_cifs_admin_access_domain), hpe3par_share_mount_path=( self.configuration.hpe3par_share_mount_path), my_ip=self.configuration.my_ip, ssh_conn_timeout=self.configuration.ssh_conn_timeout, ) mediator.do_setup() # FPG must be configured and must exist. self.fpg = self.configuration.safe_get('hpe3par_fpg') # Validate the FPG and discover the VFS # This also validates the client, connection, firmware, WSAPI, FPG... self.vfs = mediator.get_vfs_name(self.fpg) # Don't set _hpe3par until it is ready. Otherwise _update_stats fails. self._hpe3par = mediator
def __init__(self, min_ip=0, max_ip=MAX_SUPPORTED_IP_PER_VFS, type_name='FPG'): types.String.__init__(self, type_name=type_name) types.IPAddress.__init__(self, type_name=type_name) if max_ip < min_ip: msg = _("Pool's max acceptable IP cannot be less than min.") raise exception.HPE3ParInvalid(err=msg) if min_ip < 0: msg = _("Pools must be configured with zero or more IPs.") raise exception.HPE3ParInvalid(err=msg) if max_ip > FPG.MAX_SUPPORTED_IP_PER_VFS: msg = (_("Pool's max acceptable IP cannot be greater than " "supported value=%s.") % FPG.MAX_SUPPORTED_IP_PER_VFS) raise exception.HPE3ParInvalid(err=msg) self.min_ip = min_ip self.max_ip = max_ip
def _validate_access_type(protocol, access_type): if access_type not in ('ip', 'user'): msg = (_("Invalid access type. Expected 'ip' or 'user'. " "Actual '%s'.") % access_type) LOG.error(msg) raise exception.InvalidInput(msg) if protocol == 'nfs' and access_type != 'ip': msg = (_("Invalid NFS access type. HPE 3PAR NFS supports 'ip'. " "Actual '%s'.") % access_type) LOG.error(msg) raise exception.HPE3ParInvalid(msg) return protocol
def _construct_fpg(): # FPG must be configured and must exist. # self.configuration.safe_get('hpe3par_fpg') will have value in # following format: # [ {'pool_name':['ip_addr', 'ip_addr', ...]}, ... ] for fpg in self.configuration.safe_get('hpe3par_fpg'): pool_name = list(fpg)[0] conf_pool_ips = fpg[pool_name] # Validate the FPG and discover the VFS # This also validates the client, connection, firmware, WSAPI, # FPG... vfs_info = mediator.get_vfs(pool_name) if self.driver_handles_share_servers: # Use discovered IP(s) from array self.fpgs[pool_name] = { vfs_info['vfsname']: vfs_info['vfsip']['address'] } elif conf_pool_ips == []: # not DHSS and IPs not configured in manila.conf. if not vfs_info['vfsip']['address']: msg = _("Unsupported configuration. " "hpe3par_fpg must have IP address " "or be discoverable at 3PAR") LOG.error(msg) raise exception.HPE3ParInvalid(err=msg) else: # Use discovered pool ips self.fpgs[pool_name] = { vfs_info['vfsname']: vfs_info['vfsip']['address'] } else: # not DHSS and IPs configured in manila.conf _validate_pool_ips(vfs_info['vfsip']['address'], conf_pool_ips) self.fpgs[pool_name] = {vfs_info['vfsname']: conf_pool_ips}
def _change_access(self, plus_or_minus, project_id, share_id, share_proto, access_type, access_to, access_level, fpg, vfs, extra_specs=None): """Allow or deny access to a share. Plus_or_minus character indicates add to allow list (+) or remove from allow list (-). """ readonly = access_level == 'ro' protocol = self.ensure_supported_protocol(share_proto) try: self._validate_access_type(protocol, access_type) except Exception: if plus_or_minus == DENY: # Catch invalid rules for deny. Allow them to be deleted. return else: raise fshare = self._find_fshare(project_id, share_id, protocol, fpg, vfs, readonly=readonly) if not fshare: # Change access might apply to the share with the name that # does not match the access_level prefix. other_fshare = self._find_fshare(project_id, share_id, protocol, fpg, vfs, readonly=not readonly) if other_fshare: if plus_or_minus == DENY: # Try to deny rule from 'other' share for SMB or legacy. fshare = other_fshare elif self._is_share_from_snapshot(other_fshare): # Found a share-from-snapshot from before # "-ro" was added to the name. Use it. fshare = other_fshare elif protocol == 'nfs': # We don't have the RO|RW share we need, but the # opposite one already exists. It is OK to create # the one we need for ALLOW with NFS (not from snapshot). fstore = other_fshare.get('fstoreName') sharedir = other_fshare.get('shareDir') comment = other_fshare.get('comment') fshare = self._create_share(project_id, share_id, protocol, extra_specs, fpg, vfs, fstore=fstore, sharedir=sharedir, readonly=readonly, size=None, comment=comment) else: # SMB only has one share for RO and RW. Try to use it. fshare = other_fshare if not fshare: msg = _('Failed to change (%(change)s) access ' 'to FPG/share %(fpg)s/%(share)s ' 'for %(type)s %(to)s %(level)s): ' 'Share does not exist on 3PAR.') msg_data = { 'change': plus_or_minus, 'fpg': fpg, 'share': share_id, 'type': access_type, 'to': access_to, 'level': access_level, } if plus_or_minus == DENY: LOG.warning(msg, msg_data) return else: raise exception.HPE3ParInvalid(err=msg % msg_data) try: self._validate_access_level(protocol, access_type, access_level, fshare) except exception.InvalidShareAccess as e: if plus_or_minus == DENY: # Allow invalid access rules to be deleted. msg = _('Ignoring deny invalid access rule ' 'for FPG/share %(fpg)s/%(share)s ' 'for %(type)s %(to)s %(level)s): %(e)s') msg_data = { 'change': plus_or_minus, 'fpg': fpg, 'share': share_id, 'type': access_type, 'to': access_to, 'level': access_level, 'e': six.text_type(e), } LOG.info(msg, msg_data) return else: raise share_name = fshare.get('shareName') setfshare_kwargs = { 'fpg': fpg, 'fstore': fshare.get('fstoreName'), 'comment': fshare.get('comment'), } if protocol == 'nfs': access_change = '%s%s' % (plus_or_minus, access_to) setfshare_kwargs['clientip'] = access_change elif protocol == 'smb': if access_type == 'ip': access_change = '%s%s' % (plus_or_minus, access_to) setfshare_kwargs['allowip'] = access_change else: access_str = 'read' if readonly else 'fullcontrol' perm = '%s%s:%s' % (plus_or_minus, access_to, access_str) setfshare_kwargs['allowperm'] = perm try: result = self._client.setfshare(protocol, vfs, share_name, **setfshare_kwargs) result = self.ignore_benign_access_results(plus_or_minus, access_type, access_to, result) except Exception as e: result = six.text_type(e) LOG.debug("setfshare result=%s", result) if result: msg = (_('Failed to change (%(change)s) access to FPG/share ' '%(fpg)s/%(share)s for %(type)s %(to)s %(level)s: ' '%(error)s') % { 'change': plus_or_minus, 'fpg': fpg, 'share': share_id, 'type': access_type, 'to': access_to, 'level': access_level, 'error': result }) raise exception.ShareBackendException(msg=msg)