Skip to content

Commit

Permalink
Merge "v2/files: redirect download to S3"
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuul CI authored and Gerrit Code Review committed Dec 6, 2024
2 parents 48894f7 + 9c7a2a6 commit 2a34523
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 0 deletions.
1 change: 1 addition & 0 deletions dci/api/v2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ def index():


import dci.api.v2.components # noqa
import dci.api.v2.files # noqa
54 changes: 54 additions & 0 deletions dci/api/v2/files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) Red Hat, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import flask

from dci.api.v2 import api
from dci.api.v1 import base
from dci import decorators
from dci.common import exceptions as dci_exc

from dci.db import models2
from dci.stores import files_utils
import logging

logger = logging.getLogger(__name__)


@api.route("/files/<uuid:file_id>/content", methods=["GET", "HEAD"])
@decorators.login_required
def get_file_content_from_s3(user, file_id):
file = base.get_resource_orm(models2.File, file_id)
if (
user.is_not_in_team(file.team_id)
and user.is_not_read_only_user()
and user.is_not_epm()
):
raise dci_exc.Unauthorized()

file_path = files_utils.build_file_path(file.team_id, file.job_id, file.id)

presign_url_method = "get_object"
if flask.request.method == "HEAD":
presign_url_method = "head_object"

presigned_url = flask.g.store.get_presigned_url(
presign_url_method, "files", file_path
)

return flask.Response(
None, 302, content_type="application/json", headers={"Location": presigned_url}
)
42 changes: 42 additions & 0 deletions tests/api/v2/test_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) Red Hat, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.


from dci import dci_config
from dci.stores import files_utils


def test_get_file_content_from_s3(user, job_user_id, app):

s3_endpoint_url = dci_config.CONFIG["STORE_S3_ENDPOINT_URL"]
bucket = dci_config.CONFIG["STORE_FILES_CONTAINER"]

headers = {"DCI-JOB-ID": job_user_id, "DCI-NAME": "name1"}
pfile = user.post("/api/v1/files", headers=headers, data="kikoolol").data
file1_id = pfile["file"]["id"]
file_path = files_utils.build_file_path(
pfile["file"]["team_id"], pfile["file"]["job_id"], file1_id
)

# GET
r = user.get("/api/v2/files/%s/content" % file1_id)
assert r.status_code == 302
assert r.headers["Location"].startswith(f"{s3_endpoint_url}/{bucket}/{file_path}")

# HEAD
r = user.head("/api/v2/files/%s/content" % file1_id)
assert r.status_code == 302
assert r.headers["Location"].startswith(f"{s3_endpoint_url}/{bucket}/{file_path}")

0 comments on commit 2a34523

Please sign in to comment.