def _validate_required_keys(section): for required_key in ['host', 'backend']: if required_key not in call_parameters[section]: raise HttpNotAcceptableException(error_description='Invalid data passed: "{0}" misses information about {1}'.format(section, required_key), error='invalid_data') for sub_required_key in ['backend', 'metadata']: if sub_required_key not in call_parameters[section]['backend']: raise HttpNotAcceptableException(error_description='Invalid data passed: "{0}" missing information about {1}'.format(section, sub_required_key), error='invalid_data')
def delete_vtemplate(self, vdisk): """ Deletes a vDisk (template) :param vdisk: the vDisk (template) to delete :type vdisk: VDisk """ if not vdisk.is_vtemplate: raise HttpNotAcceptableException( error_description='vDisk should be a vTemplate', error='impossible_request') if len(vdisk.child_vdisks) > 0: raise HttpNotAcceptableException( error_description='vTemplate has clones', error='impossible_request') return VDiskController.delete.delay(vdisk_guid=vdisk.guid)
def devicename_exists(self, vpool, name=None, names=None): """ Checks whether a given name can be created on the vpool :param vpool: vPool object :type vpool: VPool :param name: Candidate name :type name: str :param names: Candidate names :type names: list :return: Whether the devicename exists :rtype: bool """ error_message = None if not (name is None) ^ (names is None): error_message = 'Either the name (string) or the names (list of strings) parameter must be passed' if name is not None and not isinstance(name, basestring): error_message = 'The name parameter must be a string' if names is not None and not isinstance(names, list): error_message = 'The names parameter must be a list of strings' if error_message is not None: raise HttpNotAcceptableException(error_description=error_message, error='impossible_request') if name is not None: devicename = VDiskController.clean_devicename(name) return VDiskList.get_by_devicename_and_vpool(devicename, vpool) is not None for name in names: devicename = VDiskController.clean_devicename(name) if VDiskList.get_by_devicename_and_vpool(devicename, vpool) is not None: return True return False
def set_config_params(self, vdisk, new_config_params, version): """ Sets configuration parameters to a given vdisk. :param vdisk: Guid of the virtual disk to configure :type vdisk: VDisk :param new_config_params: Configuration settings for the virtual disk :type new_config_params: dict :param version: Client version :type version: int """ if version == 1 and 'dtl_target' in new_config_params: storage_router = StorageRouterList.get_by_ip( new_config_params['dtl_target']) if storage_router is None: raise HttpNotAcceptableException( error_description= 'API version 1 requires a Storage Router IP', error='invalid_version') new_config_params['dtl_target'] = [ junction.domain_guid for junction in storage_router.domains ] new_config_params.pop('dedupe_mode', None) new_config_params.pop('cache_strategy', None) new_config_params.pop('readcache_limit', None) return VDiskController.set_config_params.delay( vdisk_guid=vdisk.guid, new_config_params=new_config_params)
def create(self, name, size, vpool_guid, storagerouter_guid, pagecache_ratio=1.0, cache_quota=None): """ Create a new vdisk :param name: Name of the new vdisk :type name: str :param size: Size of virtual disk in bytes :type size: int :param vpool_guid: Guid of vPool to create new vdisk on :type vpool_guid: str :param storagerouter_guid: Guid of the storagerouter to assign disk to :type storagerouter_guid: str :param pagecache_ratio: Ratio (0 < x <= 1) of the pagecache size related to the size :type pagecache_ratio: float :param cache_quota: Maximum caching space(s) the new volume can consume (in Bytes) per cache type. :type cache_quota: dict :return: Asynchronous result of a CeleryTask :rtype: celery.result.AsyncResult """ storagerouter = StorageRouter(storagerouter_guid) for storagedriver in storagerouter.storagedrivers: if storagedriver.vpool_guid == vpool_guid: return VDiskController.create_new.delay(volume_name=name, volume_size=size, storagedriver_guid=storagedriver.guid, pagecache_ratio=pagecache_ratio, cache_quota=cache_quota) raise HttpNotAcceptableException(error_description='No storagedriver found for vPool: {0} and StorageRouter: {1}'.format(vpool_guid, storagerouter_guid), error='impossible_request')
def delete(self, vdisk): """ Delete a given vDisk :param vdisk: The vDisk to delete :type vdisk: VDisk """ if len(vdisk.child_vdisks) > 0: raise HttpNotAcceptableException( error_description='vDisk has clones', error='impossible_request') return VDiskController.delete.delay(vdisk_guid=vdisk.guid)
def set_as_template(self, vdisk): """ Sets a vDisk as template :param vdisk: Guid of the virtual disk to set as template :type vdisk: VDisk """ if len(vdisk.child_vdisks) > 0: raise HttpNotAcceptableException( error_description='vDisk has clones', error='impossible_request') return VDiskController.set_as_template.delay(vdisk_guid=vdisk.guid)
def destroy(self, domain): """ Deletes a Domain :param domain: The domain to return :type domain: Domain :return: None :rtype: None """ if len(domain.storagerouters) > 0 or len(domain.backends) > 0 or len(domain.vdisks_dtl) > 0: raise HttpNotAcceptableException(error_description='The given Domain is still in use', error='in_use') domain.delete()
def create(self, request): """ Creates a Backend :param request: The raw request :type request: Request """ serializer = FullSerializer(Backend, instance=Backend(), data=request.DATA) backend = serializer.deserialize() duplicate = BackendList.get_by_name(backend.name) if duplicate is None: backend.save() return backend raise HttpNotAcceptableException(error_description='Backend with this name already exists', error='duplicate')
def can_be_deleted(self, storagedriver, version): """ Checks whether a Storage Driver can be deleted :param storagedriver: StorageDriver to verify :type storagedriver: StorageDriver :param version: Client version :type version: int :return: Whether the StorageDriver can be deleted :rtype: bool """ if version > 4: raise HttpNotAcceptableException( error_description='Only available in API versions 1 to 4', error='invalid_version') return not any( vdisk for vdisk in storagedriver.vpool.vdisks if vdisk.storagedriver_id == storagedriver.storagedriver_id)
def create(self, request, contents=None): """ Creates a new Domain :param request: The raw request: :type request: Request :param contents: Requested contents (serializer hint) :type contents: str """ contents = None if contents is None else contents.split(',') serializer = FullSerializer(Domain, contents=contents, instance=Domain(), data=request.DATA) domain = serializer.deserialize() current_domains = DomainList.get_by_name(domain.name) if len(current_domains) > 0: raise HttpNotAcceptableException(error_description='A Domain with the given name already exists', error='duplicate') domain.save() return domain
def shrink_vpool(self, vpool, storagerouter_guid): """ Remove the storagedriver linking the specified vPool and storagerouter_guid :param vpool: vPool to shrink (or delete if its the last storagerouter linked to it) :type vpool: VPool :param storagerouter_guid: Guid of the Storage Router :type storagerouter_guid: str """ sr = StorageRouter(storagerouter_guid) intersection = set(vpool.storagedrivers_guids).intersection( set(sr.storagedrivers_guids)) if not intersection: raise HttpNotAcceptableException( error_description= 'Storage Router {0} is not a member of vPool {1}'.format( sr.name, vpool.name), error='impossible_request') return StorageRouterController.remove_storagedriver.delay( list(intersection)[0])
def scrub_multiple_vdisks(self, vpool, vdisk_guids=None): """ Scrubs the specified vDisks or all vDisks of the vPool is no guids are passed in :param vpool: The vPool to which the vDisks belong to scrub :type vpool: ovs.dal.hybrids.vpool.VPool :param vdisk_guids: The guids of the vDisks to scrub :type vdisk_guids: list :return: Asynchronous result of a CeleryTask :rtype: celery.result.AsyncResult """ if vdisk_guids is None: vdisk_guids = [] if set(vdisk_guids).difference(set(vpool.vdisks_guids)): raise HttpNotAcceptableException( error_description= 'Some of the vDisks specified do not belong to this vPool', error='invalid_data') return GenericController.execute_scrub.delay( vdisk_guids=vdisk_guids or vpool.vdisks_guids)
def create(self, request, role_guids=None): """ Creates a Client :param request: Raw request :type request: Request :param role_guids: The GUIDs of the roles where the client should get access to :type role_guids: str """ if 'role_guids' in request.DATA: del request.DATA['role_guids'] serializer = FullSerializer(Client, instance=Client(), data=request.DATA) client = serializer.deserialize() if client.user is not None: if client.user_guid == request.client.user_guid or Toolbox.is_client_in_roles( request.client, ['manage']): client.grant_type = 'CLIENT_CREDENTIALS' client.client_secret = OAuth2Toolbox.create_hash(64) client.save() if not role_guids: roles = [ junction.role for junction in client.user.group.roles ] else: possible_role_guids = [ junction.role_guid for junction in client.user.group.roles ] roles = [ Role(guid) for guid in role_guids if guid in possible_role_guids ] for role in roles: roleclient = RoleClient() roleclient.client = client roleclient.role = role roleclient.save() return client raise HttpNotAcceptableException( error_description='A client must have a user', error='invalid_data')
def shrink_vpool(self, vpool, storagerouter_guid): """ Remove the storagedriver linking the specified vPool and storagerouter_guid :param vpool: vPool to shrink (or delete if its the last storagerouter linked to it) :type vpool: VPool :param storagerouter_guid: Guid of the Storage Router :type storagerouter_guid: str """ sr = StorageRouter(storagerouter_guid) sd_guid = None sd_guids = [ storagedriver.guid for storagedriver in vpool.storagedrivers ] for storagedriver in sr.storagedrivers: if storagedriver.guid in sd_guids: sd_guid = storagedriver.guid break if sd_guid is None: raise HttpNotAcceptableException( error_description= 'Storage Router {0} is not a member of vPool {1}'.format( sr.name, vpool.name), error='impossible_request') return StorageRouterController.remove_storagedriver.delay(sd_guid)
def create(self, name, size, vpool_guid, storagerouter_guid): """ Create a new vdisk :param name: Name of the new vdisk :type name: str :param size: Size of virtual disk in bytes :type size: int :param vpool_guid: Guid of vPool to create new vdisk on :type vpool_guid: str :param storagerouter_guid: Guid of the storagerouter to assign disk to :type storagerouter_guid: str """ storagerouter = StorageRouter(storagerouter_guid) for storagedriver in storagerouter.storagedrivers: if storagedriver.vpool_guid == vpool_guid: return VDiskController.create_new.delay( volume_name=name, volume_size=size, storagedriver_guid=storagedriver.guid) raise HttpNotAcceptableException( error_description= 'No storagedriver found for vPool: {0} and StorageRouter: {1}'. format(vpool_guid, storagerouter_guid), error='impossible_request')
def create(self, request): """ Creates a User :param request: The raw request :type request: Request """ serializer = FullSerializer(User, instance=User(), data=request.DATA, allow_passwords=True) user = serializer.deserialize() if UserList.get_user_by_username(user.username) is not None: raise HttpNotAcceptableException( error_description='User with this username already exists', error='duplicate') user.save() pw_client = Client() pw_client.ovs_type = 'INTERNAL' pw_client.grant_type = 'PASSWORD' pw_client.user = user pw_client.save() cc_client = Client() cc_client.ovs_type = 'INTERNAL' cc_client.grant_type = 'CLIENT_CREDENTIALS' cc_client.client_secret = ''.join( random.choice(string.ascii_letters + string.digits + '|_=+*#@!/-[]{}<>.?,\'";:~') for _ in range(128)) cc_client.user = user cc_client.save() for junction in user.group.roles: for client in [cc_client, pw_client]: roleclient = RoleClient() roleclient.client = client roleclient.role = junction.role roleclient.save() return user
def add_vpool(self, storagerouter, call_parameters, version, local_storagerouter, request): """ Adds a vPool to a given Storage Router :param storagerouter: StorageRouter to add the vPool to :type storagerouter: StorageRouter :param call_parameters: A complex (JSON encoded) dictionary containing all various parameters to create the vPool :type call_parameters: dict :param version: Client version :type version: int :param local_storagerouter: StorageRouter on which the call is executed :type local_storagerouter: StorageRouter :param request: The raw request :type request: Request """ def _validate_required_keys(section): for required_key in ['host', 'backend']: if required_key not in call_parameters[section]: raise HttpNotAcceptableException(error_description='Invalid data passed: "{0}" misses information about {1}'.format(section, required_key), error='invalid_data') for sub_required_key in ['backend', 'metadata']: if sub_required_key not in call_parameters[section]['backend']: raise HttpNotAcceptableException(error_description='Invalid data passed: "{0}" missing information about {1}'.format(section, sub_required_key), error='invalid_data') # API backwards compatibility if version <= 2: call_parameters['storagerouter_ip'] = storagerouter.ip call_parameters['fragment_cache_on_read'] = True call_parameters['fragment_cache_on_write'] = False call_parameters['backend_connection_info'] = {'host': call_parameters.pop('connection_host'), 'port': call_parameters.pop('connection_port'), 'username': call_parameters.pop('connection_username'), 'password': call_parameters.pop('connection_password')} if 'connection_backend' in call_parameters: connection_backend = call_parameters.pop('connection_backend') call_parameters['backend_connection_info']['backend'] = {'backend': connection_backend.pop('backend') if 'backend' in connection_backend else None, 'metadata': connection_backend.pop('metadata') if 'metadata' in connection_backend else None} if version < 6: if 'backend_connection_info' not in call_parameters: raise HttpNotAcceptableException(error_description='Invalid data passed: "backend_connection_info" should be passed', error='invalid_data') _validate_required_keys(section='backend_connection_info') if 'backend_info' not in call_parameters: call_parameters['backend_info'] = {} if 'connection_info' not in call_parameters: call_parameters['connection_info'] = {} call_parameters['backend_info']['preset'] = call_parameters['backend_connection_info']['backend']['metadata'] call_parameters['backend_info']['alba_backend_guid'] = call_parameters['backend_connection_info']['backend']['backend'] call_parameters['connection_info']['host'] = call_parameters['backend_connection_info']['host'] call_parameters['connection_info']['port'] = call_parameters['backend_connection_info'].get('port', '') call_parameters['connection_info']['client_id'] = call_parameters['backend_connection_info'].get('username', '') call_parameters['connection_info']['client_secret'] = call_parameters['backend_connection_info'].get('password', '') call_parameters.pop('backend_connection_info') if 'backend_connection_info_aa' in call_parameters: if 'backend_info_aa' not in call_parameters: call_parameters['backend_info_aa'] = {} if 'connection_info_aa' not in call_parameters: call_parameters['connection_info_aa'] = {} _validate_required_keys(section='backend_connection_info_aa') call_parameters['backend_info_aa']['preset'] = call_parameters['backend_connection_info_aa']['backend']['metadata'] call_parameters['backend_info_aa']['alba_backend_guid'] = call_parameters['backend_connection_info_aa']['backend']['backend'] call_parameters['connection_info_aa']['host'] = call_parameters['backend_connection_info_aa']['host'] call_parameters['connection_info_aa']['port'] = call_parameters['backend_connection_info_aa'].get('port', '') call_parameters['connection_info_aa']['client_id'] = call_parameters['backend_connection_info_aa'].get('username', '') call_parameters['connection_info_aa']['client_secret'] = call_parameters['backend_connection_info_aa'].get('password', '') call_parameters.pop('backend_connection_info_aa') if version >= 6 and 'backend_connection_info' in call_parameters: raise HttpNotAcceptableException(error_description='Invalid data passed: "backend_connection_info" is deprecated', error='invalid_data') # API client translation (cover "local backend" selection in GUI) if 'backend_info' not in call_parameters or 'connection_info' not in call_parameters or 'config_params' not in call_parameters: raise HttpNotAcceptableException(error_description='Invalid call_parameters passed', error='invalid_data') connection_info = call_parameters['connection_info'] connection_info_aa = call_parameters.get('connection_info_aa') if connection_info['host'] == '' or (connection_info_aa is not None and connection_info_aa['host'] == ''): client = None for _client in request.client.user.clients: if _client.ovs_type == 'INTERNAL' and _client.grant_type == 'CLIENT_CREDENTIALS': client = _client if client is None: raise HttpNotAcceptableException(error_description='Invalid call_parameters passed', error='invalid_data') if connection_info['host'] == '': connection_info['client_id'] = client.client_id connection_info['client_secret'] = client.client_secret connection_info['host'] = local_storagerouter.ip connection_info['port'] = 443 connection_info['local'] = True if connection_info_aa is not None and connection_info_aa['host'] == '': connection_info_aa['client_id'] = client.client_id connection_info_aa['client_secret'] = client.client_secret connection_info_aa['host'] = local_storagerouter.ip connection_info_aa['port'] = 443 connection_info_aa['local'] = True call_parameters.pop('type', None) call_parameters.pop('readcache_size', None) call_parameters['config_params'].pop('dedupe_mode', None) call_parameters['config_params'].pop('cache_strategy', None) # Finally, launching the add_vpool task return StorageRouterController.add_vpool.delay(call_parameters)
def new_function(*args, **kwargs): """ Wrapped function """ request = _find_request(args) new_kwargs = {} validation_new_kwargs = {} # Find out the arguments of the decorated function if validator is not None: f_info = inspect.getargspec(validator) if f_info.defaults is None: validation_mandatory_vars = f_info.args[1:] validation_optional_vars = [] else: validation_mandatory_vars = f_info.args[1:-len(f_info. defaults)] validation_optional_vars = f_info.args[ len(validation_mandatory_vars) + 1:] else: validation_mandatory_vars = [] validation_optional_vars = [] # Check versioning version_match = regex.match(request.META['HTTP_ACCEPT']) if version_match is not None: version = version_match.groupdict()['version'] else: version = settings.VERSION[-1] raw_version = version versions = (max(min_version, settings.VERSION[0]), min(max_version, settings.VERSION[-1])) if version == '*': # If accepting all versions, it defaults to the highest one version = versions[1] version = int(version) if version < versions[0] or version > versions[1]: raise HttpNotAcceptableException( error_description= 'API version requirements: {0} <= <version> <= {1}. Got {2}' .format(versions[0], versions[1], version), error='invalid_version') # Load some information instance = None if 'pk' in kwargs and object_type is not None: try: instance = object_type(kwargs['pk']) except ObjectNotFoundException: raise HttpNotFoundException( error_description= 'The requested object could not be found', error='object_not_found') # Build new kwargs for _mandatory_vars, _optional_vars, _new_kwargs in [ (f.ovs_metadata['load']['mandatory'][:], f.ovs_metadata['load']['optional'][:], new_kwargs), (validation_mandatory_vars, validation_optional_vars, validation_new_kwargs) ]: if 'version' in _mandatory_vars: _new_kwargs['version'] = version _mandatory_vars.remove('version') if 'raw_version' in _mandatory_vars: _new_kwargs['raw_version'] = raw_version _mandatory_vars.remove('raw_version') if 'request' in _mandatory_vars: _new_kwargs['request'] = request _mandatory_vars.remove('request') if instance is not None: typename = object_type.__name__.lower() if typename in _mandatory_vars: _new_kwargs[typename] = instance _mandatory_vars.remove(typename) if 'local_storagerouter' in _mandatory_vars: storagerouter = StorageRouterList.get_by_machine_id( settings.UNIQUE_ID) _new_kwargs['local_storagerouter'] = storagerouter _mandatory_vars.remove('local_storagerouter') # The rest of the mandatory parameters post_data = request.DATA if hasattr(request, 'DATA') else request.POST get_data = request.QUERY_PARAMS if hasattr( request, 'QUERY_PARAMS') else request.GET for name in _mandatory_vars: if name in kwargs: _new_kwargs[name] = kwargs[name] else: if name not in post_data: if name not in get_data: raise HttpNotAcceptableException( error_description= 'Invalid data passed: {0} is missing'. format(name), error='invalid_data') _new_kwargs[name] = _try_parse(get_data[name]) else: _new_kwargs[name] = _try_parse(post_data[name]) # Try to fill optional parameters for name in _optional_vars: if name in kwargs: _new_kwargs[name] = kwargs[name] else: if name in post_data: _new_kwargs[name] = _try_parse(post_data[name]) elif name in get_data: _new_kwargs[name] = _try_parse(get_data[name]) # Execute validator if validator is not None: validator(args[0], **validation_new_kwargs) # Call the function return f(args[0], **new_kwargs)