diff --git a/post-processor/yandex-import/storage.go b/post-processor/yandex-import/storage.go index 006afcaca..212928f68 100644 --- a/post-processor/yandex-import/storage.go +++ b/post-processor/yandex-import/storage.go @@ -2,11 +2,15 @@ package yandeximport import ( "fmt" + "net/url" + "strings" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/s3" + "github.com/hashicorp/packer/packer" ) const defaultS3Region = "ru-central1" @@ -40,3 +44,53 @@ func newYCStorageClient(storageEndpoint, accessKey, secretKey string) (*s3.S3, e return s3.New(newSession), nil } + +// Get path-style S3 URL and return presigned URL +func presignUrl(s3conn *s3.S3, ui packer.Ui, fullUrl string) (string, error) { + bucket, key, err := s3URLToBucketKey(fullUrl) + if err != nil { + return "", err + } + + req, _ := s3conn.GetObjectRequest(&s3.GetObjectInput{ + Bucket: aws.String(bucket), + Key: aws.String(key), + }) + + // Compute service allow only `https://storage.yandexcloud.net/...` URLs for Image create process + req.Config.S3ForcePathStyle = aws.Bool(true) + + urlStr, _, err := req.PresignRequest(15 * time.Minute) + if err != nil { + ui.Say(fmt.Sprintf("Failed to presign url: %s", err)) + return "", err + } + + return urlStr, nil +} + +func s3URLToBucketKey(storageURL string) (bucket string, key string, err error) { + u, err := url.Parse(storageURL) + if err != nil { + return + } + + if u.Scheme == "s3" { + // s3://bucket/key + bucket = u.Host + key = strings.TrimLeft(u.Path, "/") + } else if u.Scheme == "https" { + // https://***.storage.yandexcloud.net/... + if u.Host == defaultStorageEndpoint { + // No bucket name in the host part + path := strings.SplitN(u.Path, "/", 3) + bucket = path[1] + key = path[2] + } else { + // Bucket name in host + bucket = strings.TrimSuffix(u.Host, "."+defaultStorageEndpoint) + key = strings.TrimLeft(u.Path, "/") + } + } + return +} diff --git a/post-processor/yandex-import/storage_test.go b/post-processor/yandex-import/storage_test.go new file mode 100644 index 000000000..7cfeed976 --- /dev/null +++ b/post-processor/yandex-import/storage_test.go @@ -0,0 +1,57 @@ +package yandeximport + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_s3URLToBucketKey(t *testing.T) { + tests := []struct { + name string + storageURL string + wantBucket string + wantKey string + wantErr bool + }{ + { + name: "path-style url #1", + storageURL: "https://storage.yandexcloud.net/bucket1/key1/foobar.txt", + wantBucket: "bucket1", + wantKey: "key1/foobar.txt", + wantErr: false, + }, + { + name: "path-style url #2", + storageURL: "https://storage.yandexcloud.net/bucket1.with.dots/key1/foobar.txt", + wantBucket: "bucket1.with.dots", + wantKey: "key1/foobar.txt", + wantErr: false, + }, + { + name: "host-style url #1", + storageURL: "https://bucket1.with.dots.storage.yandexcloud.net/key1/foobar.txt", + wantBucket: "bucket1.with.dots", + wantKey: "key1/foobar.txt", + wantErr: false, + }, + { + name: "host-style url #2", + storageURL: "https://bucket-with-dash.storage.yandexcloud.net/key2/foobar.txt", + wantBucket: "bucket-with-dash", + wantKey: "key2/foobar.txt", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotBucket, gotKey, err := s3URLToBucketKey(tt.storageURL) + if (err != nil) != tt.wantErr { + t.Errorf("s3URLToBucketKey() error = %v, wantErr %v", err, tt.wantErr) + return + } + assert.Equal(t, tt.wantBucket, gotBucket) + assert.Equal(t, tt.wantKey, gotKey) + }) + } +}