Skip to content

Commit

Permalink
Update ArifactView enum to allow pipelines artifacts api to have opti…
Browse files Browse the repository at this point in the history
…onal content disposition

Signed-off-by: VaniHaripriya <[email protected]>
  • Loading branch information
VaniHaripriya committed Nov 15, 2024
1 parent e27b687 commit 35108ee
Show file tree
Hide file tree
Showing 9 changed files with 323 additions and 427 deletions.
7 changes: 7 additions & 0 deletions backend/api/v2beta1/artifacts.proto
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ message GetArtifactRequest {

// Server responses include download_url
DOWNLOAD = 2;

// Server response includes a signed URL,
// allowing in-browser rendering or preview of the artifact.
RENDER = 3;
}

// Optional. Set to "DOWNLOAD" to included a signed URL with
Expand Down Expand Up @@ -137,4 +141,7 @@ message Artifact {
// and the error message is returned. Client has the flexibility of choosing
// how to handle the error. This is especially useful when calling ListArtifacts.
google.rpc.Status error = 11;
// Optional Output. Specifies a signed URL that can be used to
// render this Artifact directly from its store.
string render_url = 12;
}
539 changes: 184 additions & 355 deletions backend/api/v2beta1/go_client/artifacts.pb.go

Large diffs are not rendered by default.

112 changes: 50 additions & 62 deletions backend/api/v2beta1/swagger/artifacts.swagger.json

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions backend/src/apiserver/resource/resource_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2052,6 +2052,14 @@ func (r *ResourceManager) GetSignedUrl(bucketConfig *objectstore.Config, secret
return signedUrl, nil
}

func (r *ResourceManager) GetSignedUrlWithoutContentDisposition(bucketConfig *objectstore.Config, secret *corev1.Secret, expirySeconds time.Duration, artifactURI string) (string, error) {
signedUrl, err := r.objectStore.GetSignedUrlWithoutContentDisposition(bucketConfig, secret, expirySeconds, artifactURI)
if err != nil {
return "", err
}
return signedUrl, nil
}

// GetObjectSize retrieves the size of the Artifact's object in bytes.
func (r *ResourceManager) GetObjectSize(bucketConfig *objectstore.Config, secret *corev1.Secret, artifactURI string) (int64, error) {
size, err := r.objectStore.GetObjectSize(bucketConfig, secret, artifactURI)
Expand Down
4 changes: 4 additions & 0 deletions backend/src/apiserver/resource/resource_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ func (m *FakeBadObjectStore) GetSignedUrl(bucketConfig *objectstore.Config, secr
return "", util.NewInternalServerError(errors.New("Error"), "bad object store")
}

func (m *FakeBadObjectStore) GetSignedUrlWithoutContentDisposition(bucketConfig *objectstore.Config, secret *corev1.Secret, expirySeconds time.Duration, artifactURI string) (string, error) {
return "", util.NewInternalServerError(errors.New("Error"), "bad object store")
}

func (m *FakeBadObjectStore) GetObjectSize(bucketConfig *objectstore.Config, secret *corev1.Secret, artifactURI string) (int64, error) {
return 0, util.NewInternalServerError(errors.New("Error"), "bad object store")
}
Expand Down
23 changes: 18 additions & 5 deletions backend/src/apiserver/server/artifact_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func (s *ArtifactServer) ListArtifacts(ctx context.Context, r *apiv2beta1.ListAr
if err1 != nil || bucketConfig == nil {
return nil, util.NewInternalServerError(fmt.Errorf("failed to retrieve session info error: %v", err1), artifactId)
}
artifactResp, err1 := s.generateResponseArtifact(ctx, artifact, bucketConfig, namespace, false)
artifactResp, err1 := s.generateResponseArtifact(ctx, artifact, bucketConfig, namespace, false, false)
if err1 != nil {
return nil, util.NewInternalServerError(fmt.Errorf("encountered error parsing artifact: %v", err), artifactId)
}
Expand Down Expand Up @@ -186,12 +186,15 @@ func (s *ArtifactServer) GetArtifact(ctx context.Context, r *apiv2beta1.GetArtif
return nil, util.Wrap(err, "Failed to authorize the request")
}

downloadURL := false
if r.GetView() == apiv2beta1.GetArtifactRequest_DOWNLOAD {
downloadURL, renderURL := false, false

switch r.GetView() {
case apiv2beta1.GetArtifactRequest_DOWNLOAD:
downloadURL = true
case apiv2beta1.GetArtifactRequest_RENDER:
renderURL = true
}

artifactResp, err := s.generateResponseArtifact(ctx, artifact, sessionInfo, namespace, downloadURL)
artifactResp, err := s.generateResponseArtifact(ctx, artifact, sessionInfo, namespace, downloadURL, renderURL)
if err != nil {
return nil, util.NewInternalServerError(fmt.Errorf("encountered error parsing artifact: %v", err), r.ArtifactId)
}
Expand All @@ -212,6 +215,7 @@ func (s *ArtifactServer) generateResponseArtifact(
bucketConfig *objectstore.Config,
namespace string,
includeShareUrl bool,
includeRenderUrl bool,
) (*apiv2beta1.Artifact, error) {
params, err := objectstore.StructuredS3Params(bucketConfig.SessionInfo.Params)
if err != nil {
Expand Down Expand Up @@ -251,6 +255,15 @@ func (s *ArtifactServer) generateResponseArtifact(
artifactResp.DownloadUrl = shareUrl
}

if includeRenderUrl {
expiry := time.Second * time.Duration(common.GetSignedURLExpiryTimeSeconds())
renderUrl, err := s.resourceManager.GetSignedUrlWithoutContentDisposition(bucketConfig, secret, expiry, *artifact.Uri)
if err != nil {
return nil, err
}
artifactResp.RenderUrl = renderUrl
}

return artifactResp, nil
}

Expand Down
27 changes: 24 additions & 3 deletions backend/src/apiserver/server/artifact_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ package server

import (
"context"
apiv2beta1 "github.com/kubeflow/pipelines/backend/api/v2beta1/go_client"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/timestamppb"
"strings"
"testing"
"time"

apiv2beta1 "github.com/kubeflow/pipelines/backend/api/v2beta1/go_client"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/timestamppb"
)

func TestGetArtifacts(t *testing.T) {
Expand Down Expand Up @@ -76,6 +77,26 @@ func TestGetArtifacts(t *testing.T) {
LastUpdatedAt: timestamppb.New(time.Unix(2, 0)),
},
},
{
name: "Fetch artifact 2",
artifactRequest: &apiv2beta1.GetArtifactRequest{
ArtifactId: "2",
View: apiv2beta1.GetArtifactRequest_RENDER,
},
expectedArtifact: &apiv2beta1.Artifact{
ArtifactId: "2",
StorageProvider: "s3",
StoragePath: "pipeline/some-pipeline-id/task/key0",
Uri: "s3://test-bucket/pipeline/some-pipeline-id/task/key0",
DownloadUrl: "dummy-render-url", // defined in object_store_fake
Namespace: "test-namespace",
ArtifactType: "1",
ArtifactSize: 123,

CreatedAt: timestamppb.New(time.Unix(1, 0)),
LastUpdatedAt: timestamppb.New(time.Unix(1, 0)),
},
},
{
name: "Fetch artifact 1 - View unspecified",
artifactRequest: &apiv2beta1.GetArtifactRequest{
Expand Down
21 changes: 21 additions & 0 deletions backend/src/apiserver/storage/object_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type ObjectStoreInterface interface {
GetFromYamlFile(o interface{}, filePath string) error
GetPipelineKey(pipelineId string) string
GetSignedUrl(bucketConfig *objectstore.Config, secret *v1.Secret, expirySeconds time.Duration, artifactURI string) (string, error)
GetSignedUrlWithoutContentDisposition(bucketConfig *objectstore.Config, secret *v1.Secret, expirySeconds time.Duration, artifactURI string) (string, error)
GetObjectSize(bucketConfig *objectstore.Config, secret *v1.Secret, artifactURI string) (int64, error)
}

Expand Down Expand Up @@ -151,6 +152,26 @@ func (m *MinioObjectStore) GetSignedUrl(bucketConfig *objectstore.Config, secret
return signedUrl.String(), nil
}

func (m *MinioObjectStore) GetSignedUrlWithoutContentDisposition(bucketConfig *objectstore.Config, secret *v1.Secret, expirySeconds time.Duration, artifactURI string) (string, error) {
s3Client, err := buildClientFromConfig(bucketConfig, secret)
if err != nil {
return "", err
}

key, err := objectstore.ArtifactKeyFromURI(artifactURI)
if err != nil {
return "", err
}
reqParams := make(url.Values)
reqParams.Set("response-content-disposition", "inline")
signedUrl, err := s3Client.Presign("GET", bucketConfig.BucketName, key, expirySeconds, reqParams)
if err != nil {
return "", util.Wrap(err, "Failed to generate signed url")
}

return signedUrl.String(), nil
}

// GetObjectSize Retrieves the Size of the object in bytes.
// Return zero with no error if artifact URI does not exist.
func (m *MinioObjectStore) GetObjectSize(bucketConfig *objectstore.Config, secret *v1.Secret, artifactURI string) (int64, error) {
Expand Down
9 changes: 7 additions & 2 deletions backend/src/apiserver/storage/object_store_fake.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
package storage

import (
"github.com/kubeflow/pipelines/backend/src/v2/objectstore"
"k8s.io/api/core/v1"
"time"

"github.com/kubeflow/pipelines/backend/src/v2/objectstore"
v1 "k8s.io/api/core/v1"
)

type fakeMinioObjectStore struct {
Expand Down Expand Up @@ -52,6 +53,10 @@ func (m *fakeMinioObjectStore) GetSignedUrl(*objectstore.Config, *v1.Secret, tim
return "dummy-signed-url", nil
}

func (m *fakeMinioObjectStore) GetSignedUrlWithoutContentDisposition(*objectstore.Config, *v1.Secret, time.Duration, string) (string, error) {
return "dummy-render-url", nil
}

func (m *fakeMinioObjectStore) GetObjectSize(*objectstore.Config, *v1.Secret, string) (int64, error) {
return 123, nil
}
Expand Down

0 comments on commit 35108ee

Please sign in to comment.