示例#1
0
def _cancel_jobs(dn):
    """
    Cancel all jobs that belong to dn.
    Returns the list of affected jobs ids.
    """
    jobs = Session.query(Job.job_id).filter(Job.job_state.in_(JobActiveStates),
                                            Job.user_dn == dn,
                                            Job.job_finished == None)
    job_ids = map(lambda j: j[0], jobs)

    try:
        now = datetime.utcnow()
        for job_id in job_ids:
            Session.query(File).filter(File.job_id == job_id).filter(File.file_state.in_(FileActiveStates))\
                .update({
                    'file_state': 'CANCELED', 'reason': 'User banned',
                    'finish_time': now
                }, synchronize_session=False)
            Session.query(Job).filter(Job.job_id == job_id)\
                .update({
                    'job_state': 'CANCELED', 'reason': 'User banned',
                    'job_finished': now
                }, synchronize_session=False)
        Session.commit()
        Session.expire_all()
        return job_ids
    except Exception:
        Session.rollback()
        raise
示例#2
0
    def get_access_granted(self):
        dropbox_user_info = self._get_dropbox_user_info()
        if not dropbox_user_info:
            raise HTTPBadRequest('No registered user for the service "%s" has been found' % self.service)

        dropbox_info = self._get_dropbox_info()
        if not dropbox_info:
            raise HTTPNotFound('Dropbox info not found in the databse')

        access_tokens = self._make_call(
            dropboxApiEndpoint + "/1/oauth/access_token",
            'OAuth oauth_version="1.0", oauth_signature_method="PLAINTEXT", oauth_consumer_key="' +
            dropbox_info.app_key + '", oauth_token="' + dropbox_user_info.request_token +
            '", oauth_signature="' + dropbox_info.app_secret + '&' + dropbox_user_info.request_token_secret + '"',
            None
        )

        # It returns: oauth_token=<access-token>&oauth_token_secret=<access-token-secret>&uid=<user-id>
        access_tokens = access_tokens.split('&')
        dropbox_user_info.access_token = access_tokens[1].split('=')[1]
        dropbox_user_info.access_token_secret = access_tokens[0].split('=')[1]
        try:
            Session.add(dropbox_user_info)
            Session.commit()
        except:
            Session.rollback()
            raise

        return access_tokens
示例#3
0
    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 ['']
示例#4
0
    def get_access_requested(self):
        dropbox_info = self._get_dropbox_info()
        request_tokens = self._make_call(
            dropboxApiEndpoint + "/1/oauth/request_token",
            'OAuth oauth_version="1.0", oauth_signature_method="PLAINTEXT",'
            'oauth_consumer_key="' + dropbox_info.app_key + '", oauth_signature="' + dropbox_info.app_secret + '&"',
            None
        )

        # It returns: oauth_token_secret=b9q1n5il4lcc&oauth_token=mh7an9dkrg59
        tokens = request_tokens.split('&')
        newuser = CloudStorageUser(
            user_dn=self.user_dn,
            cloudStorage_name=dropbox_info.cloudStorage_name,
            request_token=tokens[1].split('=')[1],
            request_token_secret=tokens[0].split('=')[1]
        )
        try:
            Session.add(newuser)
            Session.commit()
        except:
            Session.rollback()
            raise

        return request_tokens
示例#5
0
    def get_access_granted(self):
        dropbox_user_info = self._get_dropbox_user_info()
        if not dropbox_user_info:
            raise HTTPBadRequest('No registered user for the service "%s" has been found' % self.service)

        dropbox_info = self._get_dropbox_info()
        if not dropbox_info:
            raise HTTPNotFound('Dropbox info not found in the database')

        access_tokens = self._make_call(
            dropboxApiEndpoint + "/1/oauth/access_token",
            'OAuth oauth_version="1.0", oauth_signature_method="PLAINTEXT", oauth_consumer_key="' +
            dropbox_info.app_key + '", oauth_token="' + dropbox_user_info.request_token +
            '", oauth_signature="' + dropbox_info.app_secret + '&' + dropbox_user_info.request_token_secret + '"',
            None
        )

        # It returns: oauth_token=<access-token>&oauth_token_secret=<access-token-secret>&uid=<user-id>
        access_tokens = access_tokens.split('&')
        dropbox_user_info.access_token = access_tokens[1].split('=')[1]
        dropbox_user_info.access_token_secret = access_tokens[0].split('=')[1]
        try:
            Session.add(dropbox_user_info)
            Session.commit()
        except:
            Session.rollback()
            raise

        return access_tokens
示例#6
0
    def get_access_requested(self):
        dropbox_info = self._get_dropbox_info()
        request_tokens = self._make_call(
            dropboxApiEndpoint + "/1/oauth/request_token",
            'OAuth oauth_version="1.0", oauth_signature_method="PLAINTEXT",'
            'oauth_consumer_key="' + dropbox_info.app_key + '", oauth_signature="' + dropbox_info.app_secret + '&"',
            None
        )

        # It returns: oauth_token_secret=b9q1n5il4lcc&oauth_token=mh7an9dkrg59
        tokens = request_tokens.split('&')
        newuser = CloudStorageUser(
            user_dn=self.user_dn,
            storage_name=dropbox_info.storage_name,
            request_token=tokens[1].split('=')[1],
            request_token_secret=tokens[0].split('=')[1],
            vo_name=''
        )
        try:
            Session.add(newuser)
            Session.commit()
        except:
            Session.rollback()
            raise

        return request_tokens
示例#7
0
def _cancel_jobs(dn):
    """
    Cancel all jobs that belong to dn.
    Returns the list of affected jobs ids.
    """
    jobs = Session.query(Job.job_id).filter(Job.job_state.in_(JobActiveStates)).filter(Job.user_dn == dn)
    job_ids = map(lambda j: j[0], jobs)

    try:
        now = datetime.utcnow()
        for job_id in job_ids:
            Session.query(File).filter(File.job_id == job_id).filter(File.file_state.in_(FileActiveStates))\
                .update({
                    'file_state': 'CANCELED', 'reason': 'User banned',
                    'job_finished': now, 'finish_time': now
                }, synchronize_session=False)
            Session.query(Job).filter(Job.job_id == job_id)\
                .update({
                    'job_state': 'CANCELED', 'reason': 'User banned',
                    'job_finished': now, 'finish_time': now
                }, synchronize_session=False)
        Session.commit()
	Session.expire_all()
        return job_ids
    except Exception:
        Session.rollback()
        raise
示例#8
0
    def request(self, dlg_id, start_response):
        """
        First step of the delegation process: get a certificate request

        The returned certificate request must be signed with the user's original
        credentials.
        """
        user = request.environ['fts3.User.Credentials']

        if dlg_id != user.delegation_id:
            raise HTTPForbidden('The requested ID and the credentials ID do not match')

        credential_cache = Session.query(CredentialCache)\
            .get((user.delegation_id, user.user_dn))

        if credential_cache is None or credential_cache.cert_request is None:
            (x509_request, private_key) = _generate_proxy_request()
            credential_cache = CredentialCache(dlg_id=user.delegation_id, dn=user.user_dn,
                                               cert_request=x509_request.as_pem(),
                                               priv_key=private_key.as_pem(cipher=None),
                                               voms_attrs=' '.join(user.voms_cred))
            try:
                Session.merge(credential_cache)
                Session.commit()
            except Exception:
                Session.rollback()
                raise
            log.debug("Generated new credential request for %s" % dlg_id)
        else:
            log.debug("Using cached request for %s" % dlg_id)

        start_response('200 Ok', [('X-Delegation-ID', credential_cache.dlg_id),
                                  ('Content-Type', 'text/plain')])
        return [credential_cache.cert_request]
示例#9
0
    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 ['']
示例#10
0
    def delete_app(self, client_id):
        """
        Delete an application from the database
        """
        user = pylons.request.environ['fts3.User.Credentials']
        app = Session.query(OAuth2Application).get(client_id)
        if app is None:
            raise HTTPNotFound('Application not found')
        if app.owner != user.user_dn:
            raise HTTPForbidden()

        try:
            Session.delete(app)
            Session.query(OAuth2Token).filter(
                OAuth2Token.client_id == client_id).delete()
            Session.query(OAuth2Code).filter(
                OAuth2Code.client_id == client_id).delete()
            Session.commit()
        except:
            Session.rollback()
            raise

        log.info("Application removed: %s" % client_id)

        return None
示例#11
0
    def update_app(self, client_id):
        """
        Update an application
        """
        user = pylons.request.environ['fts3.User.Credentials']
        app = Session.query(OAuth2Application).get(client_id)
        if not app:
            raise HTTPNotFound('Application not found')
        if app.owner != user.user_dn:
            raise HTTPForbidden()
        if pylons.request.headers['Content-Type'].startswith('application/json'):
            fields = json.loads(pylons.request.body)
        else:
            fields = pylons.request.POST

        try:
            if 'delete' not in fields:
                app.description = fields.get('description', '')
                app.website = fields.get('website', '')
                app.redirect_to = fields.get('redirect_to', '')
                Session.merge(app)
                Session.commit()
                redirect(url_for(controller='oauth2', action='get_app'), code=HTTPSeeOther.code)
            else:
                Session.delete(app)
                Session.query(OAuth2Token).filter(OAuth2Token.client_id == client_id).delete()
                Session.query(OAuth2Code).filter(OAuth2Code.client_id == client_id).delete()
                Session.commit()
                redirect(url_for(controller='oauth2', action='get_my_apps'), code=HTTPSeeOther.code)
        except:
            Session.rollback()
            raise
示例#12
0
    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
示例#13
0
    def request(self, dlg_id, start_response):
        """
        First step of the delegation process: get a certificate request

        The returned certificate request must be signed with the user's original
        credentials.
        """
        user = request.environ['fts3.User.Credentials']

        if dlg_id != user.delegation_id:
            raise HTTPForbidden('The requested ID and the credentials ID do not match')

        credential_cache = Session.query(CredentialCache)\
            .get((user.delegation_id, user.user_dn))

        if credential_cache is None or credential_cache.cert_request is None:
            (x509_request, private_key) = _generate_proxy_request()
            credential_cache = CredentialCache(dlg_id=user.delegation_id, dn=user.user_dn,
                                               cert_request=x509_request.as_pem(),
                                               priv_key=private_key.as_pem(cipher=None),
                                               voms_attrs=' '.join(user.voms_cred))
            try:
                Session.merge(credential_cache)
                Session.commit()
            except Exception:
                Session.rollback()
                raise
            log.debug("Generated new credential request for %s" % dlg_id)
        else:
            log.debug("Using cached request for %s" % dlg_id)

        start_response('200 Ok', [('X-Delegation-ID', str(credential_cache.dlg_id)),
                                  ('Content-Type', 'text/plain')])
        return [credential_cache.cert_request]
示例#14
0
    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)
示例#15
0
    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)
示例#16
0
    def register(self):
        """
        Register a new third party application
        """
        if pylons.request.content_type.split(
                ';')[0].strip() == 'application/json':
            req = json.loads(pylons.request.body)
            scopes = req.get('scope', list())
        else:
            req = pylons.request.POST
            scopes = req.getall('scope')

        if isinstance(scopes, basestring):
            scopes = scopes.split(',')

        if not req.get('name', None):
            raise HTTPBadRequest('Missing application name')
        if not req.get('website', None):
            raise HTTPBadRequest('Missing application website')
        if not req.get('redirect_to', None):
            raise HTTPBadRequest('Missing redirect urls')
        for s in scopes:
            if str(s) not in VALID_OPERATIONS:
                raise HTTPBadRequest('Invalid scope (%s)' % s)

        user = pylons.request.environ['fts3.User.Credentials']

        app_id = _generate_app_id()
        app = OAuth2Application(client_id=app_id,
                                client_secret=_generate_app_secret(),
                                name=req['name'],
                                description=req.get('description', ''),
                                website=req['website'],
                                scope=scopes,
                                redirect_to=req['redirect_to'],
                                owner=user.user_dn)

        try:
            Session.merge(app)
            Session.commit()
        except IntegrityError:
            Session.rollback()
            raise HTTPForbidden('The name already exists')
        except:
            Session.rollback()
            raise

        log.info("New application registered: %s (%s)" % (req['name'], app_id))

        if _accept_html(pylons.request.accept):
            redirect(url_for(controller='oauth2', action='get_my_apps'),
                     code=HTTPSeeOther.code)
        else:
            pylons.response.status_int = HTTPCreated.code
            pylons.response.headers['Content-Type'] = 'application/json'
            return [to_json(app.client_id)]
示例#17
0
    def request(self, dlg_id, start_response):
        """
        First step of the delegation process: get a certificate request

        The returned certificate request must be signed with the user's original
        credentials.
        """
        user = request.environ['fts3.User.Credentials']

        if dlg_id != user.delegation_id:
            raise HTTPForbidden(
                'The requested ID and the credentials ID do not match')

        credential_cache = Session.query(CredentialCache)\
            .get((user.delegation_id, user.user_dn))

        user_cert = self.certificate()

        request_key_len = 2048
        if user_cert:
            user_key = X509.load_cert_string(user_cert)
            request_key_len = user_key.get_pubkey().size() * 8

        cached = credential_cache is not None and credential_cache.cert_request is not None
        if cached:
            cached_key_len = X509.load_request_string(
                credential_cache.cert_request).get_pubkey().size() * 8
            if cached_key_len != request_key_len:
                cached = False
                log.debug(
                    "Invalidating cache due to key length missmatch between client and cached certificates"
                )

        if not cached:
            (x509_request,
             private_key) = _generate_proxy_request(request_key_len)
            credential_cache = CredentialCache(
                dlg_id=user.delegation_id,
                dn=user.user_dn,
                cert_request=x509_request.as_pem(),
                priv_key=private_key.as_pem(cipher=None),
                voms_attrs=' '.join(user.voms_cred))
            try:
                Session.merge(credential_cache)
                Session.commit()
            except Exception:
                Session.rollback()
                raise
            log.debug("Generated new credential request for %s" % dlg_id)
        else:
            log.debug("Using cached request for %s" % dlg_id)

        start_response('200 Ok',
                       [('X-Delegation-ID', str(credential_cache.dlg_id)),
                        ('Content-Type', 'text/plain')])
        return [credential_cache.cert_request]
示例#18
0
 def remove_token(self):
     info = self._get_dropbox_user_info()
     if info is None:
         raise HTTPNotFound('No registered user for the service "%s" has been found' % self.service)
     try:
         Session.delete(info)
         Session.commit()
     except:
         Session.rollback()
         raise
示例#19
0
    def cancel_files(self, job_id, file_ids):
        """
        Cancel individual files - comma separated for multiple - within a job
        """
        job = self._get_job(job_id)

        if job.job_type != 'N':
            raise HTTPBadRequest('Multihop or reuse jobs must be cancelled at once (%s)' % str(job.job_type))

        file_ids = file_ids.split(',')
        changed_states = list()

        try:
            # Mark files in the list as CANCELED
            for file_id in file_ids:
                file = Session.query(File).get(file_id)
                if not file or file.job_id != job_id:
                    changed_states.append('File does not belong to the job')
                    continue

                if file.file_state not in FileActiveStates:
                    changed_states.append(file.file_state)
                    continue

                file.file_state = 'CANCELED'
                file.finish_time = datetime.utcnow()
                file.dest_surl_uuid = None
                changed_states.append('CANCELED')
                Session.merge(file)

            # Mark job depending on the status of the rest of files
            not_changed_states = map(lambda f: f.file_state, filter(lambda f: f.file_id not in file_ids, job.files))
            all_states = not_changed_states + changed_states

            # All files within the job have been canceled
            if len(not_changed_states) == 0:
                job.job_state = 'CANCELED'
                job.cancel_job = True
                job.job_finished = datetime.utcnow()
                log.warning('Cancelling all remaining files within the job %s' % job_id)
            # No files in non-terminal, mark the job as CANCELED too
            elif len(filter(lambda s: s in FileActiveStates, all_states)) == 0:
                log.warning('Cancelling a file within a job with others in terminal state (%s)' % job_id)
                job.job_state = 'CANCELED'
                job.cancel_job = True
                job.job_finished = datetime.utcnow()
            else:
                log.warning('Cancelling files within a job with others still active (%s)' % job_id)

            Session.merge(job)
            Session.commit()
        except:
            Session.rollback()
            raise
        return changed_states if len(changed_states) > 1 else changed_states[0]
示例#20
0
文件: se.py 项目: cern-fts/fts-rest
    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)
示例#21
0
 def delete_link_config(self,sym_name, start_response):
     """
     Deletes an existing link configuration
     """
     try:
         sym_name = urllib.unquote(sym_name)
         Session.query(LinkConfig).filter(LinkConfig.symbolicname == sym_name).delete()
         audit_configuration('link-delete', 'Link %s has been deleted' % sym_name)
         Session.commit()
     except:
         Session.rollback()
         raise
     start_response('204 No Content', [])
     return ['']
示例#22
0
def _ban_dn(dn):
    """
    Mark in the db the given DN as banned
    """
    user = request.environ['fts3.User.Credentials']
    banned = BannedDN()
    banned.dn = dn
    banned.addition_time = datetime.utcnow()
    banned.admin_dn = user.user_dn
    try:
        Session.merge(banned)
        Session.commit()
    except Exception:
        Session.rollback()
        raise
示例#23
0
    def cancel_all_by_vo(self, vo_name):
        """
        Cancel all files by the given vo_name
        """
        user = request.environ['fts3.User.Credentials']

        now = datetime.utcnow()
        if not user.is_root:
            raise HTTPForbidden(
                'User does not have root privileges'
            )

        try:
            # FTS3 daemon expects finish_time to be NULL in order to trigger the signal
            # to fts_url_copy
            file_count = Session.query(File).filter(File.vo_name == vo_name)\
                .filter(File.file_state.in_(FileActiveStates))\
                .update({
                    'file_state': 'CANCELED', 'reason': 'Job canceled by the user', 'dest_surl_uuid':None,
                    'finish_time': None
                }, synchronize_session=False)

            # However, for data management operations there is nothing to signal, so
            # set job_finished
            dm_count = Session.query(DataManagement).filter(DataManagement.vo_name == vo_name)\
                .filter(DataManagement.file_state.in_(DataManagementActiveStates))\
                .update({
                    'file_state': 'CANCELED', 'reason': 'Job canceled by the user',
                    'job_finished': now, 'finish_time': now
                }, synchronize_session=False)

            job_count = Session.query(Job).filter(Job.vo_name == vo_name)\
                .filter(Job.job_state.in_(JobActiveStates))\
                .update({
                    'job_state': 'CANCELED', 'reason': 'Job canceled by the user',
                    'job_finished': now
                }, synchronize_session=False)
            Session.commit()
            Session.expire_all()
            log.info("Active jobs for VO %s canceled" % vo_name)
        except:
            Session.rollback()
            raise
        return {
            "affected_files": file_count,
            "affected_dm": dm_count,
            "affected_jobs": job_count
        }
示例#24
0
def _ban_dn(dn, message):
    """
    Mark in the db the given DN as banned
    """
    user = request.environ['fts3.User.Credentials']
    banned = BannedDN()
    banned.dn = dn
    banned.addition_time = datetime.utcnow()
    banned.admin_dn = user.user_dn
    banned.message = message
    try:
        Session.merge(banned)
        Session.commit()
    except Exception:
        Session.rollback()
        raise
示例#25
0
def _set_to_wait(storage, vo_name):
    """
    Updates the transfers that have the given storage either in source or destination,
    and belong to the given VO.
    """
    try:
        job_ids = _set_to_wait_helper(storage, vo_name, 'SUBMITTED', 'ON_HOLD')
        job_ids.update(
            _set_to_wait_helper(storage, vo_name, 'STAGING',
                                'ON_HOLD_STAGING'))
        Session.commit()
        Session.expire_all()
    except Exception:
        Session.rollback()
        raise
    return job_ids
示例#26
0
    def update_app(self, client_id):
        """
        Update an application
        """
        user = pylons.request.environ['fts3.User.Credentials']
        app = Session.query(OAuth2Application).get(client_id)
        if not app:
            raise HTTPNotFound('Application not found')
        if app.owner != user.user_dn:
            raise HTTPForbidden()
        if pylons.request.headers['Content-Type'].startswith(
                'application/json'):
            fields = json.loads(pylons.request.body)
            scopes = fields.get('scope', list())
        else:
            fields = pylons.request.POST
            scopes = fields.getall('scope')

        if isinstance(scopes, basestring):
            scopes = scopes.split(',')

        for s in scopes:
            if str(s) not in VALID_OPERATIONS:
                raise HTTPBadRequest('Invalid scope (%s)' % s)

        try:
            if 'delete' not in fields:
                app.description = fields.get('description', '')
                app.website = fields.get('website', '')
                app.redirect_to = fields.get('redirect_to', '')
                app.scope = scopes
                Session.merge(app)
                Session.commit()
                redirect(url_for(controller='oauth2', action='get_app'),
                         code=HTTPSeeOther.code)
            else:
                Session.delete(app)
                Session.query(OAuth2Token).filter(
                    OAuth2Token.client_id == client_id).delete()
                Session.query(OAuth2Code).filter(
                    OAuth2Code.client_id == client_id).delete()
                Session.commit()
                redirect(url_for(controller='oauth2', action='get_my_apps'),
                         code=HTTPSeeOther.code)
        except:
            Session.rollback()
            raise
示例#27
0
    def register(self):
        """
        Register a new third party application
        """
        if pylons.request.content_type.split(';')[0].strip() == 'application/json':
            req = json.loads(pylons.request.body)
        else:
            req = pylons.request.POST

        if not req.get('name', None):
            raise HTTPBadRequest('Missing application name')
        if not req.get('website', None):
            raise HTTPBadRequest('Missing application website')
        if not req.get('redirect_to', None):
            raise HTTPBadRequest('Missing redirect urls')

        user = pylons.request.environ['fts3.User.Credentials']

        app_id = _generate_app_id()
        app = OAuth2Application(
            client_id=app_id,
            client_secret=_generate_app_secret(),
            name=req['name'],
            description=req.get('description', ''),
            website=req['website'],
            redirect_to=req['redirect_to'],
            owner=user.user_dn
        )

        try:
            Session.merge(app)
            Session.commit()
        except IntegrityError:
            Session.rollback()
            raise HTTPForbidden('The name already exists')
        except:
            Session.rollback()
            raise

        log.info("New application registered: %s (%s)" % (req['name'], app_id))

        if _accept_html(pylons.request.accept):
            redirect(url_for(controller='oauth2', action='get_my_apps'), code=HTTPSeeOther.code)
        else:
            pylons.response.status_int = HTTPCreated.code
            pylons.response.headers['Content-Type'] = 'application/json'
            return to_json(app.client_id)
示例#28
0
 def delete_activity_shares(self, vo_name, start_response):
     """
     Delete an existing activity share
     """
     activity_share = Session.query(ActivityShare).get(vo_name)
     if activity_share is None:
         raise HTTPNotFound('No activity shares for %s' % vo_name)
     try:
         Session.delete(activity_share)
         audit_configuration('activity-share',
                             'Activity share removed for "%s"' % (vo_name))
         Session.commit()
     except:
         Session.rollback()
         raise
     start_response('204 No Content', [])
     return ['']
示例#29
0
    def is_access_requested(self):
        info = self._get_dropbox_user_info()
        if info is None:
            raise HTTPNotFound('No registered user for the service "%s" has been found' % self.service)

        if info.is_registered():
            res = self._get_content("/")
            if res.startswith("401"):
                try:
                    Session.delete(info)
                    Session.commit()
                except:
                    Session.rollback()
                    raise
                raise HTTPNotFound('No registered user for the service "%s" has been found' % self.service)

        return info
示例#30
0
    def is_access_requested(self):
        info = self._get_dropbox_user_info()
        if info is None:
            raise HTTPNotFound('No registered user for the service "%s" has been found' % self.service)

        if info.is_registered():
            res = self._get_content("/")
            if res.startswith("401"):
                try:
                    Session.delete(info)
                    Session.commit()
                except:
                    Session.rollback()
                    raise
                raise HTTPNotFound('No registered user for the service "%s" has been found' % self.service)

        return info.storage_name
示例#31
0
 def revoke_token(self, client_id):
     """
     Current user revokes all tokens for a given application
     """
     user = pylons.request.environ['fts3.User.Credentials']
     try:
         Session.query(OAuth2Token).filter(
             (OAuth2Token.client_id == client_id) & (OAuth2Token.dlg_id == user.delegation_id)
         ).delete()
         Session.query(OAuth2Code).filter(
             (OAuth2Code.client_id == client_id) & (OAuth2Code.dlg_id == user.delegation_id)
         )
         Session.commit()
     except:
         Session.rollback()
         raise
     log.warning("User %s revoked application %s" % (user.user_dn, client_id))
     redirect(url_for(controller='oauth2', action='get_my_apps'), code=HTTPSeeOther.code)
示例#32
0
 def revoke_token(self, client_id):
     """
     Current user revokes all tokens for a given application
     """
     user = pylons.request.environ['fts3.User.Credentials']
     try:
         Session.query(OAuth2Token).filter(
             (OAuth2Token.client_id == client_id) & (OAuth2Token.dlg_id == user.delegation_id)
         ).delete()
         Session.query(OAuth2Code).filter(
             (OAuth2Code.client_id == client_id) & (OAuth2Code.dlg_id == user.delegation_id)
         )
         Session.commit()
     except:
         Session.rollback()
         raise
     log.warning("User %s revoked application %s" % (user.user_dn, client_id))
     redirect(url_for(controller='oauth2', action='get_my_apps'), code=HTTPSeeOther.code)
示例#33
0
    def remove_cloud_storage(self, storage_name, start_response):
        """
        Remove a registered cloud storage
        """
        storage = Session.query(CloudStorage).get(storage_name)
        if not storage:
            raise HTTPNotFound('The storage does not exist')

        try:
            Session.query(CloudStorageUser).filter(CloudStorageUser.storage_name == storage_name).delete()
            Session.delete(storage)
            Session.commit()
        except:
            Session.rollback()
            raise

        start_response('204 No Content', [])
        return [''] 
示例#34
0
    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', [])
示例#35
0
    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
示例#36
0
    def delete_se_config(self, start_response):
        """
        Delete the configuration for a given SE
        """
        se = request.params.get('se', None)
        if not se:
            raise HTTPBadRequest('Missing storage (se)')

        try:
            Session.query(Se).filter(Se.storage == se).delete()
            Session.query(OperationConfig).filter(
                OperationConfig.host == se).delete()
            Session.commit()
        except:
            Session.rollback()
            raise

        start_response('204 No Content', [])
        return ['']
示例#37
0
    def unban_se(self, start_response):
        """
        Unban a storage element
        """
        storage = request.params.get('storage', None)
        if not storage:
            raise HTTPBadRequest('Missing storage parameter')

        banned = Session.query(BannedSE).get(storage)
        if banned:
            try:
                Session.delete(banned)
                Session.commit()
            except Exception:
                Session.rollback()
            log.warn("Storage %s unbanned" % storage)
        else:
            log.warn("Unban of storage %s without effect" % storage)

        start_response('204 No Content', [])
        return ['']
示例#38
0
def _ban_se(storage, vo_name, allow_submit, status, timeout):
    """
    Mark in the db the given storage as banned
    """
    user = request.environ['fts3.User.Credentials']
    banned = BannedSE()
    banned.se = storage
    banned.addition_time = datetime.utcnow()
    banned.admin_dn = user.user_dn
    banned.vo = vo_name
    if allow_submit and status == 'WAIT':
        banned.status = 'WAIT_AS'
    else:
        banned.status = status
    banned.wait_timeout = timeout
    try:
        Session.merge(banned)
        Session.commit()
    except Exception:
        Session.rollback()
        raise
示例#39
0
    def delete(self, dlg_id, start_response):
        """
        Delete the delegated credentials from the database
        """
        user = request.environ['fts3.User.Credentials']

        if dlg_id != user.delegation_id:
            raise HTTPForbidden('The requested ID and the credentials ID do not match')

        cred = Session.query(Credential).get((user.delegation_id, user.user_dn))
        if not cred:
            raise HTTPNotFound('Delegated credentials not found')
        else:
            try:
                Session.delete(cred)
                Session.commit()
            except Exception:
                Session.rollback()
                raise
            start_response('204 No Content', [])
            return ['']
示例#40
0
def _ban_se(storage, vo_name, allow_submit, status, message):
    """
    Mark in the db the given storage as banned
    """
    user = request.environ['fts3.User.Credentials']
    banned = BannedSE()
    banned.se = storage
    banned.addition_time = datetime.utcnow()
    banned.admin_dn = user.user_dn
    banned.vo = vo_name
    banned.message = message
    if allow_submit and status == 'WAIT':
        banned.status = 'WAIT_AS'
    else:
        banned.status = status
    try:
        Session.merge(banned)
        Session.commit()
    except Exception:
        Session.rollback()
        raise
示例#41
0
    def delete(self, dlg_id, start_response):
        """
        Delete the delegated credentials from the database
        """
        user = request.environ['fts3.User.Credentials']

        if dlg_id != user.delegation_id:
            raise HTTPForbidden('The requested ID and the credentials ID do not match')

        cred = Session.query(Credential).get((user.delegation_id, user.user_dn))
        if not cred:
            raise HTTPNotFound('Delegated credentials not found')
        else:
            try:
                Session.delete(cred)
                Session.commit()
            except Exception:
                Session.rollback()
                raise
            start_response('204 No Content', [])
            return ['']
示例#42
0
    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
示例#43
0
    def unban_dn(self, start_response):
        """
        Unban a user
        """
        dn = request.params.get('user_dn', None)
        if not dn:
            raise HTTPBadRequest('Missing user_dn parameter')

        banned = Session.query(BannedDN).get(dn)
        if banned:
            try:

                Session.delete(banned)
                Session.commit()
            except Exception:
                Session.rollback()
            log.warn("User %s unbanned" % dn)
        else:
            log.warn("Unban of user %s without effect" % dn)

        start_response('204 No Content', [])
        return ['']
示例#44
0
    def delete_app(self, client_id):
        """
        Delete an application from the database
        """
        user = pylons.request.environ['fts3.User.Credentials']
        app = Session.query(OAuth2Application).get(client_id)
        if app is None:
            raise HTTPNotFound('Application not found')
        if app.owner != user.user_dn:
            raise HTTPForbidden()

        try:
            Session.delete(app)
            Session.query(OAuth2Token).filter(OAuth2Token.client_id == client_id).delete()
            Session.query(OAuth2Code).filter(OAuth2Code.client_id == client_id).delete()
            Session.commit()
        except:
            Session.rollback()
            raise

        log.info("Application removed: %s" % client_id)

        return None
示例#45
0
def _set_to_wait(storage=None, vo_name=None, timeout=0):
    """
    Updates the transfers that have the given storage either in source or destination,
    and belong to the given VO.
    Returns the list of affected jobs ids.
    """
    job_ids = Session.query(distinct(File.job_id))\
        .filter((File.source_se == storage) | (File.dest_se == storage)).filter(File.file_state.in_(FileActiveStates))
    if vo_name:
        job_ids = job_ids.filter(File.vo_name == vo_name)
    job_ids = map(lambda j: j[0], job_ids.all())

    try:
        for job_id in job_ids:
            Session.query(File).filter(File.job_id == job_id).filter(File.file_state.in_(FileActiveStates))\
                .update({'wait_timestamp': datetime.utcnow(), 'wait_timeout': timeout}, synchronize_session=False)

        Session.commit()
	Session.expire_all()
        return job_ids
    except Exception:
        Session.rollback()
        raise
示例#46
0
        try:
            voms_client = voms.VomsClient(credential.proxy)
            (new_proxy, new_termination_time) = voms_client.init(voms_list)
        except voms.VomsException, e:
            # Error generating the proxy because of the request itself
            raise HTTPMethodFailure(str(e))

        credential.proxy = new_proxy
        credential.termination_time = new_termination_time
        credential.voms_attrs = ' '.join(voms_list)

        try:
            Session.merge(credential)
            Session.commit()
        except Exception:
            Session.rollback()
            raise

        start_response('203 Non-Authoritative Information', [('Content-Type', 'text/plain')])
        return [str(new_termination_time)]

    @require_certificate
    def delegation_page(self):
        """
        Render an HTML form to delegate the credentials
        """
        user = request.environ['fts3.User.Credentials']
        return render(
            '/delegation.html', extra_vars={
                'user': user,
                'vos': self.vo_list,
示例#47
0
def _cancel_transfers(storage=None, vo_name=None):
    """
    Cancels the transfers that have the given storage either in source or destination,
    and belong to the given VO.
    Returns the list of affected jobs ids.
    """
    affected_job_ids = set()
    files = Session.query(File)\
        .filter((File.source_se == storage) | (File.dest_se == storage))\
        .filter(File.file_state.in_(FileActiveStates + ['NOT_USED']))
    if vo_name:
        files = files.filter(File.vo_name == vo_name)

    now = datetime.utcnow()

    try:
        for file in files:
            affected_job_ids.add(file.job_id)
            # Cancel the affected file
            file.file_state = 'CANCELED'
            file.reason = 'Storage banned'
            file.finish_time = now
            Session.merge(file)
            # If there are alternatives, enable them
            Session.query(File).filter(File.job_id == file.job_id)\
                .filter(File.file_index == file.file_index)\
                .filter(File.file_state == 'NOT_USED').update({'file_state': 'SUBMITTED'})

        # Or next queries will not see the changes!
        Session.commit()
    except Exception:
        Session.rollback()
        raise

    # Set each job terminal state if needed
    try:
        for job_id in affected_job_ids:
            reuse_flag = Session.query(Job.reuse_job).filter(Job.job_id == job_id)[0][0]
            n_files = Session.query(func.count(distinct(File.file_id))).filter(File.job_id == job_id).all()[0][0]
            n_canceled = Session.query(func.count(distinct(File.file_id)))\
                .filter(File.job_id == job_id).filter(File.file_state == 'CANCELED').all()[0][0]
            n_finished = Session.query(func.count(distinct(File.file_id)))\
                .filter(File.job_id == job_id).filter(File.file_state == 'FINISHED').all()[0][0]
            n_failed = Session.query(func.count(distinct(File.file_id)))\
                .filter(File.job_id == job_id).filter(File.file_state == 'FAILED').all()[0][0]

            n_terminal = n_canceled + n_finished + n_failed

            # Job finished!
            if n_terminal == n_files:
                reason = None
                Session.query(Job).filter(Job.job_id == job_id).update({
                    'job_state': 'CANCELED',
                    'job_finished': now,
                    'finish_time': now,
                    'reason': reason
                })
                Session.query(File).filter(File.job_id == job_id).update({
                    'job_finished': now
                })

        Session.commit()
    except Exception:
        Session.rollback()
        raise
    return affected_job_ids