Example #1
0
    def get(self, rse):
        """
        Get RSE usage information.

        .. :quickref: UsageHistory; Get RSE usage history.

        :param rse: the RSE name.
        :resheader Content-Type: application/x-json-stream
        :status 200: OK.
        :status 401: Invalid Auth Token.
        :status 404: RSE Not Found.
        :status 406: Not Acceptable.
        :returns: Line separated list of dictionary with RSE usage information.

        """
        try:

            def generate(issuer, source, vo):
                for usage in list_rse_usage_history(rse=rse,
                                                    issuer=issuer,
                                                    source=source,
                                                    vo=vo):
                    yield render_json(**usage) + '\n'

            return try_stream(
                generate(issuer=request.environ.get('issuer'),
                         source=request.args.get('source'),
                         vo=request.environ.get('vo')))
        except RSENotFound as error:
            return generate_http_error_flask(404, error)
Example #2
0
    def get(self, account=None, name=None):
        """
        Retrieve a subscription.

        .. :quickref: Subscription; Get subscriptions.

        :param account: The account name.
        :param name: The subscription name.
        :resheader Content-Type: application/x-json-stream
        :status 200: OK.
        :status 401: Invalid Auth Token.
        :status 404: Subscription Not Found.
        :status 406: Not Acceptable.
        :returns: Line separated list of dictionaries with subscription information.
        """
        try:

            def generate(vo):
                for subscription in list_subscriptions(name=name,
                                                       account=account,
                                                       vo=vo):
                    yield render_json(**subscription) + '\n'

            return try_stream(generate(vo=request.environ.get('vo')))
        except SubscriptionNotFound as error:
            return generate_http_error_flask(404, error)
Example #3
0
    def get(self, rse, scheme):
        """ List all references of the provided RSE for the given protocol.

        .. :quickref: Protocol; List RSE protocol.

        :param rse: The RSE name.
        :param scheme: The protocol identifier.
        :resheader Content-Type: application/json
        :status 200: OK.
        :status 401: Invalid Auth Token.
        :status 404: RSE Not Found.
        :status 404: RSE Protocol Not Supported.
        :status 404: RSE Protocol Domain Not Supported.
        :status 406: Not Acceptable.
        :returns: A list with detailed protocol information.

        """
        try:
            p_list = get_rse_protocols(rse,
                                       issuer=request.environ.get('issuer'),
                                       vo=request.environ.get('vo'))
        except (RSENotFound, RSEProtocolNotSupported,
                RSEProtocolDomainNotSupported) as error:
            return generate_http_error_flask(404, error)

        return jsonify(p_list)
Example #4
0
    def delete(self, rse, scheme, hostname=None, port=None):
        """
        Deletes a protocol entry for the provided RSE.

        .. :quickref: Protocol; Delete an RSE protocol.

        :param rse: The RSE name.
        :param scheme: The protocol identifier.
        :param hostname: The hostname defined for the scheme, used if more than one scheme is registered with the same identifier.
        :param port: The port registered for the hostname, ued if more than one scheme is registered with the same identifier and hostname.
        :status 200: OK.
        :status 401: Invalid Auth Token.
        :status 404: RSE not found.
        :status 404: RSE Protocol Not Supported.

        """
        try:
            del_protocols(rse,
                          issuer=request.environ.get('issuer'),
                          vo=request.environ.get('vo'),
                          scheme=scheme,
                          hostname=hostname,
                          port=port)
        except (RSEProtocolNotSupported, RSENotFound) as error:
            return generate_http_error_flask(404, error)

        return '', 200
Example #5
0
    def get(self):
        """
        ---
        summary: Return all rules for a given account
        tags:
          - Rule
        responses:
          200:
            description: OK
            content:
              application/json:
                schema:
                  type: string
          401:
            description: Invalid Auth Token
          404:
            description: No rule found for the given id
          406:
            description: Not Acceptable
        """
        try:
            def generate(filters, vo):
                for rule in list_replication_rules(filters=filters, vo=vo):
                    yield dumps(rule, cls=APIEncoder) + '\n'

            return try_stream(generate(filters=dict(request.args.items(multi=False)), vo=request.environ.get('vo')))
        except RuleNotFound as error:
            return generate_http_error_flask(404, error)
Example #6
0
File: auth.py Project: vokac/rucio
    def get(self):
        """
        Validate a Rucio Auth Token.

        .. :quickref: Validate; Validate a Rucio Auth Token.

        :reqheader Rucio-Auth-Token: as a variable-length string.
        :status 406: Not Acceptable.
        :returns: Tuple(account name, token lifetime).
        """

        headers = self.get_headers()

        headers['Content-Type'] = 'application/octet-stream'
        headers[
            'Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
        headers.add('Cache-Control', 'post-check=0, pre-check=0')
        headers['Pragma'] = 'no-cache'

        token = request.headers.get('X-Rucio-Auth-Token', default=None)

        result = validate_auth_token(token)
        if not result:
            return generate_http_error_flask(
                status_code=401,
                exc=CannotAuthenticate.__name__,
                exc_msg='Cannot authenticate with given credentials',
                headers=headers)

        return str(result), 200, headers
Example #7
0
    def get(self, account):
        """
        Return all rules of a given account.

        .. :quickref: Rules; Get rules for account.

        :param account: The account name.
        :resheader Content-Type: application/x-json-stream
        :status 200: OK.
        :status 401: Invalid auth token.
        :status 404: Rule not found.
        :status 406: Not Acceptable.
        :returns: Line separated list of rules.
        """
        filters = {'account': account}
        filters.update(request.args)
        try:

            def generate(vo):
                for rule in list_replication_rules(filters=filters, vo=vo):
                    yield dumps(rule, cls=APIEncoder) + '\n'

            return try_stream(generate(vo=request.environ.get('vo')))
        except RuleNotFound as error:
            return generate_http_error_flask(404, error)
Example #8
0
    def get(self, account, rse_expression=None):
        """ get the current global limits for an account on a specific RSE expression

        .. :quickref: GlobalAccountLimits; Get global account limits.

        :param account: The account name.
        :param rse_expression: The rse expression.
        :resheader Content-Type: application/json
        :status 200: OK.
        :status 401: Invalid auth token.
        :status 404: RSE not found.
        :status 406: Not Acceptable.
        :returns: JSON dict containing informations about the requested user.
        """
        try:
            if rse_expression:
                limits = get_global_account_limit(
                    account=account,
                    rse_expression=rse_expression,
                    vo=request.environ.get('vo'))
            else:
                limits = get_global_account_limits(
                    account=account, vo=request.environ.get('vo'))
        except RSENotFound as error:
            return generate_http_error_flask(404, error)

        return Response(render_json(**limits), content_type="application/json")
Example #9
0
    def get(self, section):
        """
        List configuration of a section

        .. :quickref: Section; List config section.

        :param section: The section name.
        :resheader Content-Type: application/json
        :status 200: OK.
        :status 401: Invalid Auth Token.
        :status 404: Config not found.
        :status 406: Not Acceptable.
        """
        res = {}
        for item in config.items(section,
                                 issuer=request.environ.get('issuer'),
                                 vo=request.environ.get('vo')):
            res[item[0]] = item[1]

        if res == {}:
            return generate_http_error_flask(
                status_code=404,
                exc=ConfigNotFound.__name__,
                exc_msg=f"No configuration found for section '{section}'")

        return jsonify(res), 200
Example #10
0
    def post(self):
        """
        List the DIDs associated to a list of replicas.

        .. :quickref: ReplicasDIDs; List DIDs for replicas.

        :<json string pfns: The list of PFNs.
        :<json string rse: The RSE name.
        :resheader Content-Type: application/x-json-string
        :status 200: OK.
        :status 400: Cannot decode json parameter list.
        :status 406: Not Acceptable.
        :returns: A list of dictionaries containing the mapping PFNs to DIDs.
        """
        parameters = json_parameters()
        pfns = param_get(parameters, 'pfns', default=[])
        rse = param_get(parameters, 'rse')

        try:

            def generate(vo):
                for pfn in get_did_from_pfns(pfns, rse, vo=vo):
                    yield dumps(pfn) + '\n'

            return try_stream(generate(vo=request.environ.get('vo')))
        except AccessDenied as error:
            return generate_http_error_flask(401, error)
Example #11
0
    def post(self):
        """
        Declare a list of suspicious replicas.

        .. :quickref: SuspiciousReplicas; Declare suspicious replicas.

        :<json string pfns: The list of PFNs.
        :<json string reason: The reason of the loss.
        :resheader Content-Type: application/json
        :status 201: Created.
        :status 400: Cannot decode json parameter list.
        :status 401: Invalid auth token.
        :status 404: Replica not found.
        :returns: A list of not successfully declared files.
        """
        parameters = json_parameters(parse_response)
        pfns = param_get(parameters, 'pfns', default=[])
        reason = param_get(parameters, 'reason', default=None)

        try:
            not_declared_files = declare_suspicious_file_replicas(
                pfns=pfns,
                reason=reason,
                issuer=request.environ.get('issuer'),
                vo=request.environ.get('vo'))
            return not_declared_files, 201
        except AccessDenied as error:
            return generate_http_error_flask(401, error)
Example #12
0
    def get(self, scope_name):
        """ get locks for a given scope, name.
        :param scope_name: data identifier (scope)/(name).
        :query did_type: The type used to filter, e.g., DATASET, CONTAINER.
        :resheader Content-Type: application/x-json-stream
        :status 200: OK.
        :status 401: Invalid Auth Token.
        :status 406: Not Acceptable.
        :returns: Line separated list of dictionary with lock information.
        """
        did_type = request.args.get('did_type', default=None)
        if did_type != 'dataset':
            return 'Wrong did_type specified', 500

        try:
            scope, name = parse_scope_name(scope_name,
                                           request.environ.get('vo'))

            def generate(vo):
                for lock in get_dataset_locks(scope, name, vo=vo):
                    yield render_json(**lock) + '\n'

            return try_stream(generate(vo=request.environ.get('vo')))
        except ValueError as error:
            return generate_http_error_flask(400, error)
Example #13
0
    def put(self):
        """
        Update a file replicas state at a given RSE.

        .. :quickref: Replicas; update replicas state.

        :<json string rse: The RSE name.
        :<json list files: list of dicts with 'scope', 'name' and 'state'.
        :status 201: Replica successfully updated.
        :status 400: Cannot decode json parameter list.
        :status 401: Invalid auth token.
        """
        parameters = json_parameters(parse_response)
        rse = param_get(parameters, 'rse')
        files = param_get(parameters, 'files')

        try:
            update_replicas_states(rse=rse,
                                   files=files,
                                   issuer=request.environ.get('issuer'),
                                   vo=request.environ.get('vo'))
        except AccessDenied as error:
            return generate_http_error_flask(401, error)

        return '', 200
Example #14
0
    def get(self, rse):
        """
        Get RSE usage information.

        .. :quickref: Usage; Get RSE usage.

        :param rse: the RSE name.
        :query source: The information source, e.g., srm.
        :query per_account: Boolean whether the usage should be also calculated per account or not.
        :resheader Content-Type: application/x-json-stream
        :status 200: OK.
        :status 401: Invalid Auth Token.
        :status 404: RSE Not Found.
        :status 406: Not Acceptable.
        :returns: A list of dictionaries with the usage information.

        """
        per_account = request.args.get('per_account') == 'True'
        try:
            def generate(issuer, source, per_account, vo):
                for usage in get_rse_usage(rse, issuer=issuer, source=source, per_account=per_account, vo=vo):
                    yield render_json(**usage) + '\n'

            return try_stream(
                generate(
                    issuer=request.environ.get('issuer'),
                    source=request.args.get('source'),
                    per_account=per_account,
                    vo=request.environ.get('vo'),
                )
            )
        except RSENotFound as error:
            return generate_http_error_flask(404, error)
Example #15
0
    def post(self):
        """ get locks for a given scope, name.

        :resheader Content-Type: application/x-json-stream
        :status 200: OK.
        :status 400: Wrong DID type.
        :returns: Line separated list of dictionary with lock information.
        """

        data = json_parse(types=(dict, ))
        try:
            dids = data["dids"]
        except KeyError:
            return 'Can not find the list of DIDs in the data. Use "dids" keyword.', 400
        vo = request.environ.get('vo')
        try:
            locks = get_dataset_locks_bulk(dids, vo)  # removes duplicates

            def generate(locks):
                for lock in locks:
                    lock["scope"] = str(lock["scope"])
                    yield render_json(**lock) + '\n'

            return try_stream(generate(locks))

        except ValueError as error:
            return generate_http_error_flask(400, error)
Example #16
0
    def get(self):
        """ List all RSEs.

        .. :quickref: RSEs; List all RSEs.

        :query expression: The returned list only contains RSE matching this expression.
        :resheader Content-Type: application/x-json-stream
        :status 200: DIDs found.
        :status 400: Invalid RSE Expression.
        :status 401: Invalid Auth Token.
        :status 406: Not Acceptable.
        :returns: A list containing all RSEs.
        """
        expression = request.args.get('expression', default=None)

        if expression:
            try:
                def generate(vo):
                    for rse in parse_rse_expression(expression, vo=vo):
                        yield render_json(rse=rse) + '\n'

                return try_stream(generate(vo=request.environ.get('vo')))
            except (InvalidRSEExpression, InvalidObject) as error:
                return generate_http_error_flask(400, error)
        else:
            def generate(vo):
                for rse in list_rses(vo=vo):
                    yield render_json(**rse) + '\n'

            return try_stream(generate(vo=request.environ.get('vo')))
Example #17
0
    def get(self, account, name):
        """
        Return all rules of a given subscription id.

        .. :quickref: Rules; Get subscription rules.

        :param account: The account name.
        :param name: The subscription name.
        :resheader Content-Type: application/x-json-stream
        :status 200: OK.
        :status 401: Invalid Auth Token.
        :status 404: Rule Not Found.
        :status 404: Subscription Not Found.
        :status 406: Not Acceptable.
        :returns: Line separated list of dictionaries with rule information.
        """
        state = request.args.get('state', default=None)
        try:
            subscriptions = [subscription['id'] for subscription in list_subscriptions(name=name, account=account, vo=request.environ.get('vo'))]

            def generate(vo):
                if len(subscriptions) > 0:
                    if state:
                        for rule in list_replication_rules({'subscription_id': subscriptions[0], 'state': state}, vo=vo):
                            yield render_json(**rule) + '\n'
                    else:
                        for rule in list_replication_rules({'subscription_id': subscriptions[0]}, vo=vo):
                            yield render_json(**rule) + '\n'

            return try_stream(generate(vo=request.environ.get('vo')))
        except (RuleNotFound, SubscriptionNotFound) as error:
            return generate_http_error_flask(404, error)
Example #18
0
    def get(self, scope_name):
        """
        List dataset replicas using the Virtual Placement service.

        NOTICE: This is an RnD function and might change or go away at any time.

        .. :quickref: DatasetReplicas; List dataset replicas with VP.

        :param scope_name: data identifier (scope)/(name).
        :query deep: Flag to ennable lookup at the file level.
        :resheader Content-Type: application/x-json-stream
        :status 200: OK.
        :status 401: Invalid auth token.
        :status 406: Not Acceptable.
        :returns: If VP exists a list of dicts of sites, otherwise nothing
        """
        try:
            scope, name = parse_scope_name(scope_name,
                                           request.environ.get('vo'))

            def generate(_deep, vo):
                for row in list_dataset_replicas_vp(scope=scope,
                                                    name=name,
                                                    deep=_deep,
                                                    vo=vo):
                    yield dumps(row, cls=APIEncoder) + '\n'

            deep = request.args.get('deep', default=False)

            return try_stream(
                generate(_deep=deep, vo=request.environ.get('vo')))
        except ValueError as error:
            return generate_http_error_flask(400, error)
Example #19
0
    def get(self, scope_name):
        """
        List dataset replicas.

        .. :quickref: DatasetReplicas; List dataset replicas.

        :param scope_name: data identifier (scope)/(name).
        :query deep: Flag to ennable lookup at the file level.
        :resheader Content-Type: application/x-json-stream
        :status 200: OK.
        :status 401: Invalid auth token.
        :status 406: Not Acceptable.
        :returns: A dictionary containing all replicas information.
        """
        try:
            scope, name = parse_scope_name(scope_name,
                                           request.environ.get('vo'))

            def generate(_deep, vo):
                for row in list_dataset_replicas(scope=scope,
                                                 name=name,
                                                 deep=_deep,
                                                 vo=vo):
                    yield dumps(row, cls=APIEncoder) + '\n'

            deep = request.args.get('deep', default=False)

            return try_stream(
                generate(_deep=deep, vo=request.environ.get('vo')))
        except ValueError as error:
            return generate_http_error_flask(400, error)
Example #20
0
    def put(self, account):
        """
        ---
        summary: Update
        description: Update a parameter for an account.
        tags:
          - Account
        parameters:
        - name: account
          in: path
          description: The account identifier.
          schema:
            type: string
          style: simple
        requestBody:
          content:
            'application/json':
              schema:
                description: Json object with key-value pairs corresponding to the new values of the parameters.
                type: object
        responses:
          200:
            description: OK
          401:
            description: Invalid Auth Token
          404:
            description: No account found.
          400:
            description: Unknown status
        """
        parameters = json_parameters()
        for key, value in parameters.items():
            try:
                update_account(account,
                               key=key,
                               value=value,
                               issuer=request.environ.get('issuer'),
                               vo=request.environ.get('vo'))
            except ValueError:
                return generate_http_error_flask(400, ValueError.__name__,
                                                 f'Unknown value {value}')
            except AccessDenied as error:
                return generate_http_error_flask(401, error)
            except AccountNotFound as error:
                return generate_http_error_flask(404, error)

        return '', 200
Example #21
0
File: dids.py Project: vokac/rucio
    def post(self, scope_name, key):
        """
        Add metadata to a data identifier.

        .. :quickref: SingleMeta; Add DID metadata.

        HTTP Success:
            201 Created

        HTTP Error:
            400 Bad Request
            401 Unauthorized
            404 Not Found
            409 Conflict
            500 Internal Error

        :param scope_name: data identifier (scope)/(name).
        :param key: the key.

        """
        try:
            scope, name = parse_scope_name(scope_name,
                                           request.environ.get('vo'))
        except ValueError as error:
            return generate_http_error_flask(400, error)

        parameters = json_parameters()
        value = param_get(parameters, 'value')

        try:
            set_metadata(
                scope=scope,
                name=name,
                key=key,
                value=value,
                issuer=request.environ.get('issuer'),
                recursive=param_get(parameters, 'recursive', default=False),
                vo=request.environ.get('vo'),
            )
        except DataIdentifierNotFound as error:
            return generate_http_error_flask(404, error)
        except Duplicate as error:
            return generate_http_error_flask(409, error)
        except (KeyNotFound, InvalidMetadata, InvalidValueForKey) as error:
            return generate_http_error_flask(400, error)

        return 'Created', 201
Example #22
0
File: dids.py Project: vokac/rucio
    def get(self, scope_name):
        """
        Retrieve a single data identifier.

        .. :quickref: DIDs; Retrieve a single DID.

        **Example request**:

        .. sourcecode:: http

            GET /dids/scope1/dataset1?dynamic HTTP/1.1
            Host: rucio.cern.ch

        **Example response**:

        .. sourcecode:: http

            HTTP/1.1 200 OK
            Vary: Accept
            Content-Type: application/json

            {"scope": "scope1", "did_type": "DATASET", "name": "dataset1",
             "bytes": 234, "length": 3, "account": "jdoe", "open": True,
             "monotonic": False, "expired_at": null}

        :query dynamic: Flag to dynamically calculate size for open DIDs
        :resheader Content-Type: application/json
        :status 200: DID found
        :status 401: Invalid Auth Token
        :status 404: Scope not found
        :status 406: Not Acceptable.
        :returns: Dictionary with DID metadata
        """
        try:
            scope, name = parse_scope_name(scope_name,
                                           request.environ.get('vo'))
            dynamic = 'dynamic' in request.args
            did = get_did(scope=scope,
                          name=name,
                          dynamic=dynamic,
                          vo=request.environ.get('vo'))
            return Response(render_json(**did),
                            content_type='application/json')
        except ValueError as error:
            return generate_http_error_flask(400, error)
        except (ScopeNotFound, DataIdentifierNotFound) as error:
            return generate_http_error_flask(404, error)
Example #23
0
File: dids.py Project: vokac/rucio
    def get(self, scope_name):
        """
        Returns the contents of a data identifier.

        .. :quickref: Attachement; Get DID contents.

        **Example request**:

        .. sourcecode:: http

            GET /dids/scope1/dataset1?dynamic HTTP/1.1
            Host: rucio.cern.ch

        **Example response**:

        .. sourcecode:: http

            HTTP/1.1 200 OK
            Vary: Accept
            Content-Type: application/json

            {"scope": "scope1", "did_type": "DATASET", "name": "dataset1",
             "bytes": 234, "length": 3, "account": "jdoe", "open": True,
             "monotonic": False, "expired_at": null}

        :query dynamic: Flag to dynamically calculate size for open DIDs
        :resheader Content-Type: application/x-json-stream
        :status 200: DID found
        :status 401: Invalid Auth Token
        :status 404: Scope not found
        :status 406: Not Acceptable
        :returns: Dictionary with DID metadata
        """
        try:
            scope, name = parse_scope_name(scope_name,
                                           request.environ.get('vo'))

            def generate(vo):
                for did in list_content(scope=scope, name=name, vo=vo):
                    yield render_json(**did) + '\n'

            return try_stream(generate(vo=request.environ.get('vo')))
        except ValueError as error:
            return generate_http_error_flask(400, error)
        except DataIdentifierNotFound as error:
            return generate_http_error_flask(404, error)
Example #24
0
    def post(self, account, scope):
        """
        ---
        summary: Add Scope
        description: Adds a new scope.
        tags:
          - Scopes
        parameters:
        - name: account
          in: path
          description: The account associated with the scope.
          schema:
            type: string
          style: simple
        - name: scope
          in: path
          description: The name of the scope.
          schema:
            type: string
          style: simple
        responses:
          201:
            description: OK
            content:
              application/json:
                schema:
                  type: string
                  enum: ["Created"]
          401:
            description: Invalid Auth Token
          404:
            description: Account not found
          409:
            description: Scope already exists
        """
        try:
            add_scope(scope,
                      account,
                      issuer=request.environ.get('issuer'),
                      vo=request.environ.get('vo'))
        except Duplicate as error:
            return generate_http_error_flask(409, error)
        except AccountNotFound as error:
            return generate_http_error_flask(404, error)

        return 'Created', 201
Example #25
0
 def post(self):
     """
     ---
     summary: Create
     description: Create or set the configuration option in the requested section.
     tags:
       - Config
     requestBody:
       content:
         'application/json':
           schema:
             description: "The request body is expected to contain a json {'section': {'option': 'value'}}."
             type: object
     responses:
       201:
         description: OK
         content:
           application/json:
             schema:
               type: string
               enum: ['Created']
       401:
         description: Invalid Auth Token
       400:
         description: The input data was incomplete or invalid
       500:
         description: Configuration error
     """
     parameters = json_parameters()
     for section, section_config in parameters.items():
         if not isinstance(section_config, dict):
             return generate_http_error_flask(400, ValueError.__name__, '')
         for option, value in section_config.items():
             try:
                 config.set(section=section,
                            option=option,
                            value=value,
                            issuer=request.environ.get('issuer'),
                            vo=request.environ.get('vo'))
             except ConfigurationError:
                 return generate_http_error_flask(
                     400, 'ConfigurationError',
                     f"Could not set value '{value}' for section '{section}' option '{option}'"
                 )
     return 'Created', 201
Example #26
0
    def post(self):
        """
        Declare a list of bad replicas by DID.

        .. :quickref: BadDIDs; Declare bad replicas by DID.

        :<json string pfns: The list of PFNs.
        :<json string reason: The reason of the loss.
        :<json string state: The state is eiher BAD, SUSPICIOUS or TEMPORARY_UNAVAILABLE.
        :<json string expires_at: The expiration date. Only apply to TEMPORARY_UNAVAILABLE.
        :resheader Content-Type: application/x-json-string
        :status 201: Created.
        :status 400: Cannot decode json parameter list.
        :status 401: Invalid auth token.
        :status 404: Replica not found.
        :returns: A list of not successfully declared files.
        """
        parameters = json_parameters(parse_response)
        expires_at = param_get(parameters, 'expires_at', default=None)
        if expires_at:
            expires_at = datetime.strptime(expires_at, "%Y-%m-%dT%H:%M:%S.%f")

        try:
            not_declared_files = add_bad_dids(
                dids=param_get(parameters, 'dids', default=[]),
                rse=param_get(parameters, 'rse', default=None),
                issuer=request.environ.get('issuer'),
                state=BadFilesStatus.BAD,
                reason=param_get(parameters, 'reason', default=None),
                expires_at=expires_at,
                vo=request.environ.get('vo'),
            )
        except (ValueError, InvalidType) as error:
            return generate_http_error_flask(400, ValueError.__name__,
                                             error.args[0])
        except AccessDenied as error:
            return generate_http_error_flask(401, error)
        except ReplicaNotFound as error:
            return generate_http_error_flask(404, error)
        except Duplicate as error:
            return generate_http_error_flask(409, error)

        return Response(dumps(not_declared_files),
                        status=201,
                        content_type='application/json')
Example #27
0
    def get(self):
        """
        .. :quickref: OIDC;

        :status 200: OK
        :status 401: Unauthorized
        :resheader X-Rucio-Auth-Token: The authentication token
        :resheader X-Rucio-Auth-Token-Expires: The time when the token expires
        """
        headers = self.get_headers()

        headers.set('Content-Type', 'application/octet-stream')
        headers.set('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')
        headers.add('Cache-Control', 'post-check=0, pre-check=0')
        headers.set('Pragma', 'no-cache')

        query_string = request.query_string.decode(encoding='utf-8')
        ip = request.headers.get('X-Forwarded-For', default=request.remote_addr)

        try:
            result = get_token_oidc(query_string, ip)
        except AccessDenied:
            return generate_http_error_flask(401, CannotAuthorize.__name__, 'Cannot authorize token request.', headers=headers)

        if not result:
            return generate_http_error_flask(401, CannotAuthorize.__name__, 'Cannot authorize token request.', headers=headers)
        if 'token' in result and 'webhome' not in result:
            headers.set('X-Rucio-Auth-Token', result['token'].token)
            headers.set('X-Rucio-Auth-Token-Expires', date_to_str(result['token'].expired_at))
            return '', 200, headers
        elif 'webhome' in result:
            webhome = result['webhome']
            if webhome is None:
                headers.extend(error_headers(CannotAuthenticate.__name__, 'Cannot find your OIDC identity linked to any Rucio account'))
                headers.set('Content-Type', 'text/html')
                return render_template('auth_crash.html', crashtype='unknown_identity'), 401, headers
            # domain setting is necessary so that the token gets distributed also to the webui server
            domain = '.'.join(urlparse(webhome).netloc.split('.')[1:])
            response = redirect(webhome, code=303)
            response.headers.extend(headers)
            response.set_cookie('x-rucio-auth-token', value=result['token'].token, domain=domain, path='/')
            response.set_cookie('rucio-auth-token-created-at', value=str(time.time()), domain=domain, path='/')
            return response
        else:
            return '', 400, headers
Example #28
0
    def delete(self, rse):
        """ Disable RSE with given RSE name.

        .. :quickref: RSE; disable RSE.

        :param rse: the RSE name.
        :status 200: OK.
        :status 401: Invalid Auth Token.
        :status 404: RSE not found.
        """
        try:
            del_rse(rse=rse, issuer=request.environ.get('issuer'), vo=request.environ.get('vo'))
        except (RSENotFound, RSEOperationNotSupported, CounterNotFound) as error:
            return generate_http_error_flask(404, error)
        except AccessDenied as error:
            return generate_http_error_flask(401, error)

        return '', 200
Example #29
0
    def delete(self, account):
        """ disable account with given account name.

        .. :quickref: AccountParameter; Delete account information.

        :param account: The account identifier.
        :status 200: OK.
        :status 401: Invalid auth token.
        :status 404: Account not found.
        """
        try:
            del_account(account, issuer=request.environ.get('issuer'), vo=request.environ.get('vo'))
        except AccessDenied as error:
            return generate_http_error_flask(401, error)
        except AccountNotFound as error:
            return generate_http_error_flask(404, error)

        return '', 200
Example #30
0
    def post(self):
        """
        Create file replicas at a given RSE.

        .. :quickref: Replicas; create replicas at RSE

        :<json string rse: The RSE name.
        :<json list files: list of dicts with 'scope', 'name', 'bytes', 'meta' and 'adler32'.
        :<json bool ignore_availability: Flag to ignore the RSE blacklisting.
        :status 201: Replica Successfully created.
        :status 400: Invalid Path.
        :status 401: Invalid auth token.
        :status 404: RSE not found.
        :status 404: Scope not found.
        :status 409: Replica already exists.
        :status 409: DID already exists.
        :status 503: Resource Temporary Unavailable.
        """
        parameters = json_parameters(parse_response)
        rse = param_get(parameters, 'rse')
        files = param_get(parameters, 'files')

        try:
            add_replicas(
                rse=rse,
                files=files,
                issuer=request.environ.get('issuer'),
                vo=request.environ.get('vo'),
                ignore_availability=param_get(parameters,
                                              'ignore_availability',
                                              default=False),
            )
        except InvalidPath as error:
            return generate_http_error_flask(400, error)
        except AccessDenied as error:
            return generate_http_error_flask(401, error)
        except (Duplicate, DataIdentifierAlreadyExists) as error:
            return generate_http_error_flask(409, error)
        except (RSENotFound, ScopeNotFound) as error:
            return generate_http_error_flask(404, error)
        except ResourceTemporaryUnavailable as error:
            return generate_http_error_flask(503, error)

        return 'Created', 201