Skip to content

Commit

Permalink
CreateDownloadLink: Head before signing
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Dye <andrewwdye@gmail.com>
  • Loading branch information
iaroslav-ciupin authored and andrewwdye committed Sep 25, 2024
1 parent 1522f36 commit 693dfb8
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 1 deletion.
12 changes: 11 additions & 1 deletion flyteadmin/dataproxy/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,17 @@ func (s Service) CreateDownloadLink(ctx context.Context, req *service.CreateDown
return nil, errors.NewFlyteAdminErrorf(codes.Internal, "no deckUrl found for request [%+v]", req)
}

signedURLResp, err := s.dataStore.CreateSignedURL(ctx, storage.DataReference(nativeURL), storage.SignedURLProperties{
ref := storage.DataReference(nativeURL)
meta, err := s.dataStore.Head(ctx, ref)
if err != nil {
return nil, errors.NewFlyteAdminErrorf(codes.Internal, "failed to head object before signing url. Error: %v", err)
}

if !meta.Exists() {
return nil, errors.NewFlyteAdminErrorf(codes.NotFound, "object not found")
}

signedURLResp, err := s.dataStore.CreateSignedURL(ctx, ref, storage.SignedURLProperties{
Scope: stow.ClientMethodGet,
ExpiresIn: req.ExpiresIn.AsDuration(),
})
Expand Down
59 changes: 59 additions & 0 deletions flyteadmin/dataproxy/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ import (
"bytes"
"context"
"crypto/md5" // #nosec
"fmt"
"net/url"
"testing"
"time"

"github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/durationpb"

commonMocks "github.com/flyteorg/flyte/flyteadmin/pkg/common/mocks"
Expand Down Expand Up @@ -157,6 +160,15 @@ func TestCreateUploadLocationMore(t *testing.T) {
})
}

type testMetadata struct {
storage.Metadata
exists bool
}

func (t testMetadata) Exists() bool {
return t.exists
}

func TestCreateDownloadLink(t *testing.T) {
dataStore := commonMocks.GetMockStorageClient()
nodeExecutionManager := &mocks.MockNodeExecutionManager{}
Expand All @@ -179,18 +191,65 @@ func TestCreateDownloadLink(t *testing.T) {
assert.Error(t, err)
})

t.Run("item not found", func(t *testing.T) {
dataStore.ComposedProtobufStore.(*commonMocks.TestDataStore).HeadCb = func(ctx context.Context, ref storage.DataReference) (storage.Metadata, error) {
return testMetadata{exists: false}, nil
}

_, err = s.CreateDownloadLink(context.Background(), &service.CreateDownloadLinkRequest{
ArtifactType: service.ArtifactType_ARTIFACT_TYPE_DECK,
Source: &service.CreateDownloadLinkRequest_NodeExecutionId{
NodeExecutionId: &core.NodeExecutionIdentifier{},
},
ExpiresIn: durationpb.New(time.Hour),
})

st, ok := status.FromError(err)
assert.True(t, ok)
assert.Equal(t, codes.NotFound, st.Code())
assert.Equal(t, "object not found", st.Message())
})

t.Run("valid config", func(t *testing.T) {
dataStore.ComposedProtobufStore.(*commonMocks.TestDataStore).HeadCb = func(ctx context.Context, ref storage.DataReference) (storage.Metadata, error) {
return testMetadata{exists: true}, nil
}

_, err = s.CreateDownloadLink(context.Background(), &service.CreateDownloadLinkRequest{
ArtifactType: service.ArtifactType_ARTIFACT_TYPE_DECK,
Source: &service.CreateDownloadLinkRequest_NodeExecutionId{
NodeExecutionId: &core.NodeExecutionIdentifier{},
},
ExpiresIn: durationpb.New(time.Hour),
})

assert.NoError(t, err)
})

t.Run("head failed", func(t *testing.T) {
dataStore.ComposedProtobufStore.(*commonMocks.TestDataStore).HeadCb = func(ctx context.Context, ref storage.DataReference) (storage.Metadata, error) {
return testMetadata{}, fmt.Errorf("head fail")
}

_, err = s.CreateDownloadLink(context.Background(), &service.CreateDownloadLinkRequest{
ArtifactType: service.ArtifactType_ARTIFACT_TYPE_DECK,
Source: &service.CreateDownloadLinkRequest_NodeExecutionId{
NodeExecutionId: &core.NodeExecutionIdentifier{},
},
ExpiresIn: durationpb.New(time.Hour),
})

st, ok := status.FromError(err)
assert.True(t, ok)
assert.Equal(t, codes.Internal, st.Code())
assert.Equal(t, "failed to head object before signing url. Error: head fail", st.Message())
})

t.Run("use default ExpiresIn", func(t *testing.T) {
dataStore.ComposedProtobufStore.(*commonMocks.TestDataStore).HeadCb = func(ctx context.Context, ref storage.DataReference) (storage.Metadata, error) {
return testMetadata{exists: true}, nil
}

_, err = s.CreateDownloadLink(context.Background(), &service.CreateDownloadLinkRequest{
ArtifactType: service.ArtifactType_ARTIFACT_TYPE_DECK,
Source: &service.CreateDownloadLinkRequest_NodeExecutionId{
Expand Down

0 comments on commit 693dfb8

Please sign in to comment.