def remove_authz(self, start_response): """ Revoke access for a DN for a given operation, or all """ input_dict = get_input_as_dict(request, from_query=True) dn = input_dict.get('dn') op = input_dict.get('operation') if not dn: raise HTTPBadRequest('Missing DN parameter') to_be_removed = Session.query(AuthorizationByDn).filter( AuthorizationByDn.dn == dn) if op: to_be_removed = to_be_removed.filter( AuthorizationByDn.operation == op) try: to_be_removed.delete() if op: audit_configuration('revoke', '%s revoked for "%s"' % (op, dn)) else: audit_configuration('revoke', 'All revoked for "%s"' % dn) Session.commit() except: Session.rollback() raise start_response('204 No Content', []) return ['']
def set_drain(self): """ Set the drain status of a server """ input_dict = get_input_as_dict(request) hostname = input_dict.get('hostname', None) drain = input_dict.get('drain', True) if not isinstance(drain, bool) or not isinstance(hostname, basestring): raise HTTPBadRequest('Invalid drain request') entries = Session.query(Host).filter(Host.hostname == hostname).all() if not entries: raise HTTPBadRequest('Host not found') try: audit_configuration( 'drain', 'Turning drain %s the drain mode for %s' % (drain, hostname)) for entry in entries: entry.drain = drain Session.merge(entry) Session.commit() except: Session.rollback() raise
def add_user_to_cloud_storage(self, storage_name, start_response): """ Add a user or a VO credentials to the storage """ storage = Session.query(CloudStorage).get(storage_name) if not storage: raise HTTPNotFound('The storage does not exist') input_dict = get_input_as_dict(request) if not input_dict.get('user_dn', None) and not input_dict.get('vo_name', None): raise HTTPBadRequest('One of user_dn or vo_name must be specified') elif input_dict.get('user_dn', None) and input_dict.get('vo_name', None): raise HTTPBadRequest('Only one of user_dn or vo_name must be specified') cuser = CloudStorageUser( user_dn=input_dict.get('user_dn', ''), storage_name=storage_name, access_token=input_dict.get('access_key', input_dict.get('access_token', None)), access_token_secret=input_dict.get('secret_key', input_dict.get('access_token_secret', None)), request_token=input_dict.get('request_token'), request_token_secret=input_dict.get('request_token_secret'), vo_name=input_dict.get('vo_name', ''), ) try: Session.merge(cuser) Session.commit() except: Session.rollback() raise start_response('201 Created', []) return dict(storage_name=cuser.storage_name, user_dn=cuser.user_dn, vo_name=cuser.vo_name)
def delete_share(self, start_response): """ Delete a share """ input_dict = get_input_as_dict(request, from_query=True) source = input_dict.get('source') destination = input_dict.get('destination') vo = input_dict.get('vo') if not source or not destination or not vo: raise HTTPBadRequest('Missing source, destination and/or vo') try: share = Session.query(ShareConfig).get((source, destination, vo)) if share: Session.delete(share) audit_configuration( 'share-delete', 'Share %s, %s, %s has been deleted' % (source, destination, vo)) Session.commit() except: Session.rollback() raise start_response('204 No Content', []) return ['']
def set_activity_shares(self): """ Set a new/modify an activity share """ input_dict = get_input_as_dict(request) if not input_dict.get('vo', None): raise HTTPBadRequest('Missing VO') if not input_dict.get('share', None): raise HTTPBadRequest('Missing share') if 'active' not in input_dict: input_dict['active'] = True input_dict['share'] = _normalize_activity_share_format( input_dict['share']) # Make sure the share weights are numbers for entry in input_dict['share']: for key, value in entry.iteritems(): if not type(value) in (float, int): raise HTTPBadRequest('Share weight must be a number') try: activity_share = ActivityShare(vo=input_dict['vo'], active=input_dict['active'], activity_share=input_dict['share']) Session.merge(activity_share) audit_configuration('activity-share', json.dumps(input_dict)) Session.commit() except ValueError, e: raise HTTPBadRequest(str(e))
def submit(self): """ Submits a new job It returns the information about the new submitted job. To know the format for the submission, /api-docs/schema/submit gives the expected format encoded as a JSON-schema. It can be used to validate (i.e in Python, jsonschema.validate) """ # First, the request has to be valid JSON submitted_dict = get_input_as_dict(request) # The auto-generated delegation id must be valid user = request.environ['fts3.User.Credentials'] credential = Session.query(Credential).get((user.delegation_id, user.user_dn)) if credential is None: raise HTTPAuthenticationTimeout('No delegation found for "%s"' % user.user_dn) if credential.expired(): remaining = credential.remaining() seconds = abs(remaining.seconds + remaining.days * 24 * 3600) raise HTTPAuthenticationTimeout( 'The delegated credentials expired %d seconds ago (%s)' % (seconds, user.delegation_id) ) if user.method != 'oauth2' and credential.remaining() < timedelta(hours=1): raise HTTPAuthenticationTimeout( 'The delegated credentials has less than one hour left (%s)' % user.delegation_id ) # Populate the job and files populated = JobBuilder(user, **submitted_dict) log.info("%s (%s) is submitting a transfer job" % (user.user_dn, user.vos[0])) # Insert the job try: try: Session.execute(Job.__table__.insert(), [populated.job]) except IntegrityError: raise HTTPConflict('The sid provided by the user is duplicated') if len(populated.files): Session.execute(File.__table__.insert(), populated.files) if len(populated.datamanagement): Session.execute(DataManagement.__table__.insert(), populated.datamanagement) Session.flush() Session.commit() except IntegrityError as err: Session.rollback() raise HTTPConflict('The submission is duplicated '+ str(err)) except: Session.rollback() raise # Send messages # Need to re-query so we get the file ids job = Session.query(Job).get(populated.job_id) for i in range(len(job.files)): try: submit_state_change(job, job.files[i], populated.files[0]['file_state']) except Exception, e: log.warning("Failed to write state message to disk: %s" % e.message)
def set_se_config(self): """ Set the configuration parameters for a given SE """ input_dict = get_input_as_dict(request) try: for storage, cfg in input_dict.iteritems(): if not storage or storage.isspace(): raise ValueError se_info = None se_info_new = cfg.get('se_info', None) if se_info_new: se_info = Session.query(Se).get(storage) if not se_info: se_info = Se(storage=storage) for key, value in se_info_new.iteritems(): #value = validate_type(Se, key, value) setattr(se_info, key, value) audit_configuration( 'set-se-config', 'Set config %s: %s' % (storage, json.dumps(cfg))) Session.merge(se_info) # Operation limits operations = cfg.get('operations', None) if operations: for vo, limits in operations.iteritems(): for op, limit in limits.iteritems(): limit = int(limit) new_limit = Session.query(OperationConfig).get( (vo, storage, op)) if limit > 0: if not new_limit: new_limit = OperationConfig( vo_name=vo, host=storage, operation=op) new_limit.concurrent_ops = limit Session.merge(new_limit) elif new_limit: Session.delete(new_limit) audit_configuration( 'set-se-limits', 'Set limits for %s: %s' % (storage, json.dumps(operations))) Session.commit() except (AttributeError, ValueError): Session.rollback() raise HTTPBadRequest('Malformed configuration') except: Session.rollback() raise return (se_info, operations)
def list_authz(self): """ List granted accesses """ input_dict = get_input_as_dict(request, from_query=True) dn = input_dict.get('dn') op = input_dict.get('operation') authz = Session.query(AuthorizationByDn) if dn: authz = authz.filter(AuthorizationByDn.dn == dn) if op: authz = authz.filter(AuthorizationByDn.operation == op) return authz.all()
def set_optimizer_values(self): """ Set the number of actives and streams """ input_dict = get_input_as_dict(request) source_se = input_dict.get('source_se', None) dest_se = input_dict.get('dest_se', None) rationale = input_dict.get('rationale', None) current_time = datetime.utcnow() if not source_se or not dest_se: raise HTTPBadRequest('Missing source and/or destination') try: active = int(input_dict.get('active', 2)) except Exception, e: raise HTTPBadRequest('Active must be an integer (%s)' % str(e))
def delete_vo_global_config(self, start_response): """ Delete the global configuration for the given VO """ input_dict = get_input_as_dict(request, from_query=True) vo_name = input_dict.get('vo_name') if not vo_name or vo_name == '*': raise HTTPBadRequest('Missing VO name') try: Session.query(ServerConfig).filter( ServerConfig.vo_name == vo_name).delete() Session.commit() except: Session.rollback() raise start_response('204 No Content', [])
def set_share(self, start_response): """ Add or modify a share """ input_dict = get_input_as_dict(request) source = input_dict.get('source') destination = input_dict.get('destination') vo = input_dict.get('vo') try: share = int(input_dict.get('share')) if share < 0: raise HTTPBadRequest('Shares values cannot be negative') except: raise HTTPBadRequest('Bad share value') if not source or not destination or not vo or not share: raise HTTPBadRequest( 'Missing source, destination, vo and/or share') source = urlparse(source) if not source.scheme or not source.hostname: raise HTTPBadRequest('Invalid source') source = "%s://%s" % (source.scheme, source.hostname) destination = urlparse(destination) if not destination.scheme or not destination.hostname: raise HTTPBadRequest('Invalid source') destination = "%s://%s" % (destination.scheme, destination.hostname) try: share_cfg = ShareConfig(source=source, destination=destination, vo=vo, share=share) Session.merge(share_cfg) audit_configuration( 'share-set', 'Share %s, %s, %s has been set to %d' % (source, destination, vo, share)) Session.commit() except: Session.rollback() raise return share
def set_link_config(self): """ Set the configuration for a given link """ input_dict = get_input_as_dict(request) source = input_dict.get('source', '*') destination = input_dict.get('destination', '*') symbolicname = input_dict.get('symbolicname', None) if not symbolicname: raise HTTPBadRequest('Missing symbolicname') link_cfg = Session.query(LinkConfig).filter(LinkConfig.symbolicname == symbolicname).first() try: min_active = int(input_dict.get('min_active', 2)) max_active = int(input_dict.get('max_active', 2)) except Exception, e: raise HTTPBadRequest('Active must be an integer (%s)' % str(e))
def set_cloud_storage(self, start_response): """ Add or modify a cloud storage entry """ input_dict = get_input_as_dict(request) if 'storage_name' not in input_dict: raise HTTPBadRequest('Missing storage name') storage = CloudStorage( storage_name=input_dict.get('storage_name'), app_key=input_dict.get('app_key', None), app_secret=input_dict.get('app_secret', None), service_api_url=input_dict.get('service_api_url', None) ) try: Session.merge(storage) Session.commit() except: Session.rollback() raise start_response('201 Created', []) return storage.storage_name
def add_authz(self): """ Give special access to someone """ input_dict = get_input_as_dict(request) dn = input_dict.get('dn') op = input_dict.get('operation') if not dn or not op: raise HTTPBadRequest('Missing dn and/or operation') try: authz = Session.query(AuthorizationByDn).get((dn, op)) if not authz: authz = AuthorizationByDn(dn=dn, operation=op) audit_configuration('authorize', '%s granted to "%s"' % (op, dn)) Session.merge(authz) Session.commit() except: Session.rollback() raise return authz
def set_global_config(self): """ Set the global configuration """ cfg = get_input_as_dict(request) vo_name = cfg.get('vo_name', '*') db_cfg = Session.query(ServerConfig).get(vo_name) if not db_cfg: db_cfg = ServerConfig(vo_name=vo_name) for key, value in cfg.iteritems(): value = validate_type(ServerConfig, key, value) setattr(db_cfg, key, value) Session.merge(db_cfg) audit_configuration('set-globals', to_json(db_cfg, indent=None)) try: Session.commit() except: Session.rollback() raise return self.get_global_config()
else: setattr(job, 'http_status', '304 Not Modified') setattr(job, 'http_message', 'The job is in a terminal state') log.warning( "The job %s can not be modified, since it is %s" % (job_id, job.job_state)) responses.append(job) except HTTPClientError, e: responses.append( dict(job_id=job_id, http_status="%s %s" % (e.code, e.title), http_message=e.detail)) # Now, modify those that can be modification = get_input_as_dict(request) priority = None try: priority = int(modification['params']['priority']) except KeyError: pass except ValueError: raise HTTPBadRequest('Invalid priority value') try: for job in modifiable_jobs: if priority: for file in job.files: file.priority = priority file = Session.merge(file)