Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copy Blob from URL/Put Blob from URL copy source tags #21128

1 change: 1 addition & 0 deletions sdk/storage/azblob/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## 1.1.0-beta.2 (Unreleased)

### Features Added
* Added support for [Cold tier](https://learn.microsoft.com/azure/storage/blobs/access-tiers-overview?tabs=azure-portal).

### Breaking Changes

Expand Down
41 changes: 23 additions & 18 deletions sdk/storage/azblob/appendblob/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package appendblob
import (
"context"
"errors"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"io"
"os"
"time"
Expand All @@ -35,12 +36,14 @@ type Client base.CompositeClient[generated.BlobClient, generated.AppendBlobClien
func NewClient(blobURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) {
authPolicy := shared.NewStorageChallengePolicy(cred)
conOptions := shared.GetClientOptions(options)
conOptions.PerRetryPolicies = append(conOptions.PerRetryPolicies, authPolicy)
pl := runtime.NewPipeline(exported.ModuleName,
exported.ModuleVersion, runtime.PipelineOptions{},
&conOptions.ClientOptions)
plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}}

return (*Client)(base.NewAppendBlobClient(blobURL, pl, nil)), nil
azClient, err := azcore.NewClient(shared.AppendBlobClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions)
if err != nil {
return nil, err
}

return (*Client)(base.NewAppendBlobClient(blobURL, azClient, nil)), nil
}

// NewClientWithNoCredential creates an instance of Client with the specified values.
Expand All @@ -49,12 +52,13 @@ func NewClient(blobURL string, cred azcore.TokenCredential, options *ClientOptio
// - options - client options; pass nil to accept the default values
func NewClientWithNoCredential(blobURL string, options *ClientOptions) (*Client, error) {
conOptions := shared.GetClientOptions(options)
pl := runtime.NewPipeline(exported.ModuleName,
exported.ModuleVersion,
runtime.PipelineOptions{},
&conOptions.ClientOptions)

return (*Client)(base.NewAppendBlobClient(blobURL, pl, nil)), nil
azClient, err := azcore.NewClient(shared.AppendBlobClient, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions)
if err != nil {
return nil, err
}

return (*Client)(base.NewAppendBlobClient(blobURL, azClient, nil)), nil
}

// NewClientWithSharedKeyCredential creates an instance of Client with the specified values.
Expand All @@ -64,13 +68,14 @@ func NewClientWithNoCredential(blobURL string, options *ClientOptions) (*Client,
func NewClientWithSharedKeyCredential(blobURL string, cred *blob.SharedKeyCredential, options *ClientOptions) (*Client, error) {
authPolicy := exported.NewSharedKeyCredPolicy(cred)
conOptions := shared.GetClientOptions(options)
conOptions.PerRetryPolicies = append(conOptions.PerRetryPolicies, authPolicy)
pl := runtime.NewPipeline(exported.ModuleName,
exported.ModuleVersion,
runtime.PipelineOptions{},
&conOptions.ClientOptions)
plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}}

azClient, err := azcore.NewClient(shared.AppendBlobClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions)
if err != nil {
return nil, err
}

return (*Client)(base.NewAppendBlobClient(blobURL, pl, cred)), nil
return (*Client)(base.NewAppendBlobClient(blobURL, azClient, cred)), nil
}

// NewClientFromConnectionString creates an instance of Client with the specified values.
Expand Down Expand Up @@ -130,7 +135,7 @@ func (ab *Client) WithSnapshot(snapshot string) (*Client, error) {
}
p.Snapshot = snapshot

return (*Client)(base.NewAppendBlobClient(p.String(), ab.generated().Pipeline(), ab.sharedKey())), nil
return (*Client)(base.NewAppendBlobClient(p.String(), ab.generated().InternalClient(), ab.sharedKey())), nil
}

// WithVersionID creates a new AppendBlobURL object identical to the source but with the specified version id.
Expand All @@ -142,7 +147,7 @@ func (ab *Client) WithVersionID(versionID string) (*Client, error) {
}
p.VersionID = versionID

return (*Client)(base.NewAppendBlobClient(p.String(), ab.generated().Pipeline(), ab.sharedKey())), nil
return (*Client)(base.NewAppendBlobClient(p.String(), ab.generated().InternalClient(), ab.sharedKey())), nil
}

// Create creates a 0-size append blob. Call AppendBlock to append data to an append blob.
Expand Down
2 changes: 1 addition & 1 deletion sdk/storage/azblob/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "go",
"TagPrefix": "go/storage/azblob",
"Tag": "go/storage/azblob_a772b9c866"
"Tag": "go/storage/azblob_1a8d8f30f5"
}
34 changes: 22 additions & 12 deletions sdk/storage/azblob/blob/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package blob

import (
"context"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror"
"io"
"os"
Expand Down Expand Up @@ -37,10 +38,13 @@ type Client base.Client[generated.BlobClient]
func NewClient(blobURL string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) {
authPolicy := shared.NewStorageChallengePolicy(cred)
conOptions := shared.GetClientOptions(options)
conOptions.PerRetryPolicies = append(conOptions.PerRetryPolicies, authPolicy)
pl := runtime.NewPipeline(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions)
plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}}

return (*Client)(base.NewBlobClient(blobURL, pl, &cred)), nil
azClient, err := azcore.NewClient(shared.BlobClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions)
if err != nil {
return nil, err
}
return (*Client)(base.NewBlobClient(blobURL, azClient, &cred)), nil
}

// NewClientWithNoCredential creates an instance of Client with the specified values.
Expand All @@ -49,9 +53,12 @@ func NewClient(blobURL string, cred azcore.TokenCredential, options *ClientOptio
// - options - client options; pass nil to accept the default values
func NewClientWithNoCredential(blobURL string, options *ClientOptions) (*Client, error) {
conOptions := shared.GetClientOptions(options)
pl := runtime.NewPipeline(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions)

return (*Client)(base.NewBlobClient(blobURL, pl, nil)), nil
azClient, err := azcore.NewClient(shared.BlobClient, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions)
if err != nil {
return nil, err
}
return (*Client)(base.NewBlobClient(blobURL, azClient, nil)), nil
}

// NewClientWithSharedKeyCredential creates an instance of Client with the specified values.
Expand All @@ -61,10 +68,13 @@ func NewClientWithNoCredential(blobURL string, options *ClientOptions) (*Client,
func NewClientWithSharedKeyCredential(blobURL string, cred *SharedKeyCredential, options *ClientOptions) (*Client, error) {
authPolicy := exported.NewSharedKeyCredPolicy(cred)
conOptions := shared.GetClientOptions(options)
conOptions.PerRetryPolicies = append(conOptions.PerRetryPolicies, authPolicy)
pl := runtime.NewPipeline(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions)
plOpts := runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}}

return (*Client)(base.NewBlobClient(blobURL, pl, cred)), nil
azClient, err := azcore.NewClient(shared.BlobClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions)
if err != nil {
return nil, err
}
return (*Client)(base.NewBlobClient(blobURL, azClient, cred)), nil
}

// NewClientFromConnectionString creates an instance of Client with the specified values.
Expand Down Expand Up @@ -116,7 +126,7 @@ func (b *Client) WithSnapshot(snapshot string) (*Client, error) {
}
p.Snapshot = snapshot

return (*Client)(base.NewBlobClient(p.String(), b.generated().Pipeline(), b.credential())), nil
return (*Client)(base.NewBlobClient(p.String(), b.generated().InternalClient(), b.credential())), nil
}

// WithVersionID creates a new AppendBlobURL object identical to the source but with the specified version id.
Expand All @@ -128,7 +138,7 @@ func (b *Client) WithVersionID(versionID string) (*Client, error) {
}
p.VersionID = versionID

return (*Client)(base.NewBlobClient(p.String(), b.generated().Pipeline(), b.credential())), nil
return (*Client)(base.NewBlobClient(p.String(), b.generated().InternalClient(), b.credential())), nil
}

// Delete marks the specified blob or snapshot for deletion. The blob is later deleted during garbage collection.
Expand Down Expand Up @@ -261,8 +271,8 @@ func (b *Client) SetLegalHold(ctx context.Context, legalHold bool, options *SetL
// CopyFromURL synchronously copies the data at the source URL to a block blob, with sizes up to 256 MB.
// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob-from-url.
func (b *Client) CopyFromURL(ctx context.Context, copySource string, options *CopyFromURLOptions) (CopyFromURLResponse, error) {
copyOptions, smac, mac, lac := options.format()
resp, err := b.generated().CopyFromURL(ctx, copySource, copyOptions, smac, mac, lac)
copyOptions, smac, mac, lac, cpkScopeInfo := options.format()
resp, err := b.generated().CopyFromURL(ctx, copySource, copyOptions, smac, mac, lac, cpkScopeInfo)
return resp, err
}

Expand Down
115 changes: 26 additions & 89 deletions sdk/storage/azblob/blob/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3274,95 +3274,32 @@ func (s *BlobRecordedTestsSuite) TestPermanentDeleteWithoutPermission() {
return nil
}*/

//
////func (s *BlobRecordedTestsSuite) TestBlobTierInferred() {
//// svcClient, err := getPremiumserviceClient()
//// if err != nil {
//// c.Skip(err.Error())
//// }
////
//// containerClient, _ := testcommon.CreateNewContainer(c, svcClient)
//// defer testcommon.DeleteContainer(context.Background(), _require, containerClient)
//// bbClient, _ := createNewPageBlob(c, containerClient)
////
//// resp, err := bbClient.GetProperties(context.Background(), nil)
//// _require.Nil(err)
//// _assert(resp.AccessTierInferred(), chk.Equals, "true")
////
//// resp2, err := containerClient.NewListBlobsFlatPager(ctx, Marker{}, ListBlobsSegmentOptions{})
//// _require.Nil(err)
//// _assert(resp2.Segment.BlobItems[0].Properties.AccessTierInferred, chk.NotNil)
//// _assert(resp2.Segment.BlobItems[0].Properties.AccessTier, chk.Not(chk.Equals), "")
////
//// _, err = bbClient.SetTier(ctx, AccessTierP4, LeaseAccessConditions{})
//// _require.Nil(err)
////
//// resp, err = bbClient.GetProperties(context.Background(), nil)
//// _require.Nil(err)
//// _assert(resp.AccessTierInferred(), chk.Equals, "")
////
//// resp2, err = containerClient.NewListBlobsFlatPager(ctx, Marker{}, ListBlobsSegmentOptions{})
//// _require.Nil(err)
//// _assert(resp2.Segment.BlobItems[0].Properties.AccessTierInferred, chk.IsNil) // AccessTierInferred never returned if false
////}
////
////func (s *BlobRecordedTestsSuite) TestBlobArchiveStatus() {
//// svcClient, err := getBlobStorageserviceClient()
//// if err != nil {
//// c.Skip(err.Error())
//// }
////
//// containerClient, _ := testcommon.CreateNewContainer(c, svcClient)
//// defer testcommon.DeleteContainer(context.Background(), _require, containerClient)
//// bbClient, _ := createNewBlockBlob(c, containerClient)
////
//// _, err = bbClient.SetTier(ctx, AccessTierArchive, LeaseAccessConditions{})
//// _require.Nil(err)
//// _, err = bbClient.SetTier(ctx, AccessTierCool, LeaseAccessConditions{})
//// _require.Nil(err)
////
//// resp, err := bbClient.GetProperties(context.Background(), nil)
//// _require.Nil(err)
//// _assert(resp.ArchiveStatus(), chk.Equals, string(ArchiveStatusRehydratePendingToCool))
////
//// resp2, err := containerClient.NewListBlobsFlatPager(ctx, Marker{}, ListBlobsSegmentOptions{})
//// _require.Nil(err)
//// _assert(resp2.Segment.BlobItems[0].Properties.ArchiveStatus, chk.Equals, ArchiveStatusRehydratePendingToCool)
////
//// // delete first blob
//// _, err = bbClient.Delete(context.Background(), DeleteSnapshotsOptionNone, nil)
//// _require.Nil(err)
////
//// bbClient, _ = createNewBlockBlob(c, containerClient)
////
//// _, err = bbClient.SetTier(ctx, AccessTierArchive, LeaseAccessConditions{})
//// _require.Nil(err)
//// _, err = bbClient.SetTier(ctx, AccessTierHot, LeaseAccessConditions{})
//// _require.Nil(err)
////
//// resp, err = bbClient.GetProperties(context.Background(), nil)
//// _require.Nil(err)
//// _assert(resp.ArchiveStatus(), chk.Equals, string(ArchiveStatusRehydratePendingToHot))
////
//// resp2, err = containerClient.NewListBlobsFlatPager(ctx, Marker{}, ListBlobsSegmentOptions{})
//// _require.Nil(err)
//// _assert(resp2.Segment.BlobItems[0].Properties.ArchiveStatus, chk.Equals, ArchiveStatusRehydratePendingToHot)
////}
////
////func (s *BlobRecordedTestsSuite) TestBlobTierInvalidValue() {
//// svcClient, err := getBlobStorageserviceClient()
//// if err != nil {
//// c.Skip(err.Error())
//// }
////
//// containerClient, _ := testcommon.CreateNewContainer(c, svcClient)
//// defer testcommon.DeleteContainer(context.Background(), _require, containerClient)
//// bbClient, _ := createNewBlockBlob(c, containerClient)
////
//// _, err = bbClient.SetTier(ctx, AccessTierType("garbage"), LeaseAccessConditions{})
//// testcommon.ValidateBlobErrorCode(c, err, bloberror.InvalidHeaderValue)
////}
////
func (s *BlobRecordedTestsSuite) TestBlobSetTierInvalidAndValid() {
_require := require.New(s.T())
testName := s.T().Name()
svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil)
_require.NoError(err)

containerName := testcommon.GenerateContainerName(testName)
containerClient := testcommon.CreateNewContainer(context.Background(), _require, containerName, svcClient)
defer testcommon.DeleteContainer(context.Background(), _require, containerClient)

blockBlobName := testcommon.GenerateBlobName(testName)
bbClient := testcommon.CreateNewBlockBlob(context.Background(), _require, blockBlobName, containerClient)

_, err = bbClient.SetTier(context.Background(), blob.AccessTier("nothing"), nil)
_require.Error(err)
testcommon.ValidateBlobErrorCode(_require, err, bloberror.InvalidHeaderValue)

for _, tier := range []blob.AccessTier{blob.AccessTierCool, blob.AccessTierHot, blob.AccessTierCold, blob.AccessTierArchive} {
_, err = bbClient.SetTier(context.Background(), tier, nil)
_require.NoError(err)

getResp, err := bbClient.GetProperties(context.Background(), nil)
_require.NoError(err)
_require.Equal(*getResp.AccessTier, string(tier))
}
}

func (s *BlobRecordedTestsSuite) TestBlobClientPartsSASQueryTimes() {
_require := require.New(s.T())
Expand Down
1 change: 1 addition & 0 deletions sdk/storage/azblob/blob/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ type AccessTier = generated.AccessTier
const (
AccessTierArchive AccessTier = generated.AccessTierArchive
AccessTierCool AccessTier = generated.AccessTierCool
AccessTierCold AccessTier = generated.AccessTierCold
AccessTierHot AccessTier = generated.AccessTierHot
AccessTierP10 AccessTier = generated.AccessTierP10
AccessTierP15 AccessTier = generated.AccessTierP15
Expand Down
8 changes: 5 additions & 3 deletions sdk/storage/azblob/blob/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -544,11 +544,13 @@ type CopyFromURLOptions struct {
SourceModifiedAccessConditions *SourceModifiedAccessConditions

BlobAccessConditions *AccessConditions

CPKScopeInfo *CPKScopeInfo
}

func (o *CopyFromURLOptions) format() (*generated.BlobClientCopyFromURLOptions, *generated.SourceModifiedAccessConditions, *generated.ModifiedAccessConditions, *generated.LeaseAccessConditions) {
func (o *CopyFromURLOptions) format() (*generated.BlobClientCopyFromURLOptions, *generated.SourceModifiedAccessConditions, *generated.ModifiedAccessConditions, *generated.LeaseAccessConditions, *generated.CPKScopeInfo) {
if o == nil {
return nil, nil, nil, nil
return nil, nil, nil, nil, nil
}

options := &generated.BlobClientCopyFromURLOptions{
Expand All @@ -563,7 +565,7 @@ func (o *CopyFromURLOptions) format() (*generated.BlobClientCopyFromURLOptions,
}

leaseAccessConditions, modifiedAccessConditions := exported.FormatBlobAccessConditions(o.BlobAccessConditions)
return options, o.SourceModifiedAccessConditions, modifiedAccessConditions, leaseAccessConditions
return options, o.SourceModifiedAccessConditions, modifiedAccessConditions, leaseAccessConditions, o.CPKScopeInfo
}

// ---------------------------------------------------------------------------------------------------------------------
Expand Down
Loading