diff --git a/sdk/storage/azblob/CHANGELOG.md b/sdk/storage/azblob/CHANGELOG.md index 72dbd3ac9748..ca1866f68783 100644 --- a/sdk/storage/azblob/CHANGELOG.md +++ b/sdk/storage/azblob/CHANGELOG.md @@ -3,15 +3,22 @@ ## 1.1.1 (Unreleased) ### Features Added +* Added support for [Cold Tier](https://learn.microsoft.com/azure/storage/blobs/access-tiers-overview?tabs=azure-portal). +* Added `CopySourceTag` option for `UploadBlobFromURLOptions` +* Added [FilterBlobs by Tags](https://learn.microsoft.com/rest/api/storageservices/find-blobs-by-tags-container) API for container client. +* Added `System` option to `ListContainersInclude` to allow listing of system containers (i.e, $web). +* Updated the SAS Version to `2021-12-02` and added `Encryption Scope` to Account SAS, Service SAS, and User Delegation SAS ### Breaking Changes ### Bugs Fixed -* Fixed issue where some requests fail with mismatch in string to sign. +* Fixed issue where some requests fail with mismatch in string to sign. +* Fixed service SAS creation where expiry time or permissions can be omitted when stored access policy is used. Fixes [#21229](https://github.com/Azure/azure-sdk-for-go/issues/21229). * Fixed service SAS creation where expiry time or permissions can be omitted when stored access policy is used. Fixes [#21229](https://github.com/Azure/azure-sdk-for-go/issues/21229). ### Other Changes +* Updating version of azcore to 1.6.0. ## 1.1.0 (2023-07-13) diff --git a/sdk/storage/azblob/appendblob/client.go b/sdk/storage/azblob/appendblob/client.go index fc96b67de766..69913e334d4b 100644 --- a/sdk/storage/azblob/appendblob/client.go +++ b/sdk/storage/azblob/appendblob/client.go @@ -9,6 +9,7 @@ package appendblob import ( "context" "errors" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "io" "os" "time" @@ -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. @@ -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. @@ -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. @@ -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. @@ -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. diff --git a/sdk/storage/azblob/appendblob/client_test.go b/sdk/storage/azblob/appendblob/client_test.go index 2d650e492244..9fd8a3ac90bf 100644 --- a/sdk/storage/azblob/appendblob/client_test.go +++ b/sdk/storage/azblob/appendblob/client_test.go @@ -12,6 +12,7 @@ import ( "crypto/md5" "encoding/binary" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/service" "hash/crc64" "io" "math/rand" @@ -371,6 +372,149 @@ func (s *AppendBlobUnrecordedTestsSuite) TestAppendBlockFromURL() { _require.Equal(destBuffer, sourceData) } +func (s *AppendBlobUnrecordedTestsSuite) TestBlobEncryptionScopeSAS() { + _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) + + blobClient := containerClient.NewAppendBlobClient(testcommon.GenerateBlobName("appendsrc")) + + // Get source abClient URL with SAS for AppendBlockFromURL. + blobParts, _ := blob.ParseURL(blobClient.URL()) + + encryptionScope, err := testcommon.GetRequiredEnv(testcommon.EncryptionScopeEnvVar) + _require.Nil(err) + credential, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + _require.Nil(err) + perms := sas.BlobPermissions{Read: true, Create: true, Write: true, Delete: true} + + blobParts.SAS, err = sas.BlobSignatureValues{ + Protocol: sas.ProtocolHTTPS, // Users MUST use HTTPS (not HTTP) + ExpiryTime: time.Now().UTC().Add(48 * time.Hour), // 48-hours before expiration + ContainerName: blobParts.ContainerName, + BlobName: blobParts.BlobName, + Permissions: perms.String(), + EncryptionScope: encryptionScope, + }.SignWithSharedKey(credential) + _require.NoError(err) + + blobURLWithSAS := blobParts.String() + + // create new client with sas url + blobClient, err = appendblob.NewClientWithNoCredential(blobURLWithSAS, nil) + _require.Nil(err) + + createResponse, err := blobClient.Create(context.Background(), nil) + _require.NoError(err) + _require.Equal(*createResponse.EncryptionScope, encryptionScope) +} + +func (s *AppendBlobUnrecordedTestsSuite) TestAccountEncryptionScopeSAS() { + _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) + + blobName := testcommon.GenerateBlobName("appendsrc") + blobClient := containerClient.NewAppendBlobClient(blobName) + + // Get blob URL with SAS for AppendBlockFromURL. + blobParts, _ := blob.ParseURL(blobClient.URL()) + + encryptionScope, err := testcommon.GetRequiredEnv(testcommon.EncryptionScopeEnvVar) + _require.Nil(err) + + credential, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + _require.Nil(err) + + blobParts.SAS, err = sas.AccountSignatureValues{ + Protocol: sas.ProtocolHTTPS, // Users MUST use HTTPS (not HTTP) + ExpiryTime: time.Now().UTC().Add(48 * time.Hour), // 48-hours before expiration + Permissions: to.Ptr(sas.AccountPermissions{Read: true, Create: true, Write: true, Delete: true}).String(), + ResourceTypes: to.Ptr(sas.AccountResourceTypes{Service: true, Container: true, Object: true}).String(), + EncryptionScope: encryptionScope, + }.SignWithSharedKey(credential) + _require.NoError(err) + + blobURLWithSAS := blobParts.String() + blobClient, err = appendblob.NewClientWithNoCredential(blobURLWithSAS, nil) + _require.NoError(err) + + createResp, err := blobClient.Create(context.Background(), nil) + _require.NoError(err) + _require.NotNil(createResp) + _require.Equal(*createResp.EncryptionScope, encryptionScope) +} + +func (s *AppendBlobUnrecordedTestsSuite) TestGetUserDelegationEncryptionScopeSAS() { + _require := require.New(s.T()) + testName := s.T().Name() + accountName, _ := testcommon.GetGenericAccountInfo(testcommon.TestAccountDefault) + _require.Greater(len(accountName), 0) + + cred, err := testcommon.GetGenericTokenCredential() + _require.NoError(err) + + svcClient, err := service.NewClient("https://"+accountName+".blob.core.windows.net/", cred, nil) + _require.NoError(err) + + containerName := testcommon.GenerateContainerName(testName) + cntClientTokenCred := testcommon.CreateNewContainer(context.Background(), _require, containerName, svcClient) + defer testcommon.DeleteContainer(context.Background(), _require, cntClientTokenCred) + + blobName := testcommon.GenerateBlobName("appendsrc") + blobClient := cntClientTokenCred.NewAppendBlobClient(blobName) + + // Set current and past time and create key + now := time.Now().UTC().Add(-10 * time.Second) + expiry := now.Add(2 * time.Hour) + info := service.KeyInfo{ + Start: to.Ptr(now.UTC().Format(sas.TimeFormat)), + Expiry: to.Ptr(expiry.UTC().Format(sas.TimeFormat)), + } + + udc, err := svcClient.GetUserDelegationCredential(context.Background(), info, nil) + _require.NoError(err) + + // get permissions and details for sas + encryptionScope, err := testcommon.GetRequiredEnv(testcommon.EncryptionScopeEnvVar) + _require.Nil(err) + + permissions := sas.BlobPermissions{Read: true, Create: true, Write: true, List: true, Add: true, Delete: true} + + blobParts, _ := blob.ParseURL(blobClient.URL()) + + // Create Blob Signature Values with desired permissions and sign with user delegation credential + blobParts.SAS, err = sas.BlobSignatureValues{ + Protocol: sas.ProtocolHTTPS, + StartTime: time.Now().UTC().Add(time.Second * -10), + ExpiryTime: time.Now().UTC().Add(15 * time.Minute), + Permissions: permissions.String(), + ContainerName: containerName, + EncryptionScope: encryptionScope, + }.SignWithUserDelegation(udc) + _require.NoError(err) + + blobURLWithSAS := blobParts.String() + blobClient, err = appendblob.NewClientWithNoCredential(blobURLWithSAS, nil) + _require.NoError(err) + + createResp, err := blobClient.Create(context.Background(), nil) + _require.NoError(err) + _require.NotNil(createResp) + _require.Equal(*createResp.EncryptionScope, encryptionScope) + +} + func (s *AppendBlobUnrecordedTestsSuite) TestAppendBlockFromURLWithMD5() { _require := require.New(s.T()) testName := s.T().Name() diff --git a/sdk/storage/azblob/assets.json b/sdk/storage/azblob/assets.json index 7301bd69d694..f9d16daba57b 100644 --- a/sdk/storage/azblob/assets.json +++ b/sdk/storage/azblob/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "go", "TagPrefix": "go/storage/azblob", - "Tag": "go/storage/azblob_0776f1b95b" + "Tag": "go/storage/azblob_7a25fb98e8" } diff --git a/sdk/storage/azblob/blob/client.go b/sdk/storage/azblob/blob/client.go index 98c166aaf966..c93db3041702 100644 --- a/sdk/storage/azblob/blob/client.go +++ b/sdk/storage/azblob/blob/client.go @@ -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" @@ -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. @@ -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. @@ -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. @@ -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. @@ -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. @@ -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 } diff --git a/sdk/storage/azblob/blob/client_test.go b/sdk/storage/azblob/blob/client_test.go index 1d3040713a51..cc1dffcedef1 100644 --- a/sdk/storage/azblob/blob/client_test.go +++ b/sdk/storage/azblob/blob/client_test.go @@ -191,67 +191,6 @@ func waitForCopy(_require *require.Assertions, copyBlobClient *blockblob.Client, } } -func (s *BlobUnrecordedTestsSuite) TestCopyBlockBlobFromUrlSourceContentMD5() { - _require := require.New(s.T()) - testName := s.T().Name() - svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) - if err != nil { - s.Fail("Unable to fetch service client because " + err.Error()) - } - - containerName := testcommon.GenerateContainerName(testName) - containerClient := testcommon.CreateNewContainer(context.Background(), _require, containerName, svcClient) - defer testcommon.DeleteContainer(context.Background(), _require, containerClient) - - const contentSize = 8 * 1024 // 8 KB - content := make([]byte, contentSize) - contentMD5 := md5.Sum(content) - body := bytes.NewReader(content) - - srcBlob := containerClient.NewBlockBlobClient("srcblob") - destBlob := containerClient.NewBlockBlobClient("destblob") - - // Prepare source bbClient for copy. - _, err = srcBlob.Upload(context.Background(), streaming.NopCloser(body), nil) - _require.Nil(err) - - expiryTime, err := time.Parse(time.UnixDate, "Fri Jun 11 20:00:00 UTC 2049") - _require.Nil(err) - - credential, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) - if err != nil { - s.T().Fatal("Couldn't fetch credential because " + err.Error()) - } - - // Get source blob url with SAS for StageFromURL. - sasQueryParams, err := sas.AccountSignatureValues{ - Protocol: sas.ProtocolHTTPS, - ExpiryTime: expiryTime, - Permissions: to.Ptr(sas.AccountPermissions{Read: true, List: true}).String(), - ResourceTypes: to.Ptr(sas.AccountResourceTypes{Container: true, Object: true}).String(), - }.SignWithSharedKey(credential) - _require.Nil(err) - - srcBlobParts, _ := blob.ParseURL(srcBlob.URL()) - srcBlobParts.SAS = sasQueryParams - srcBlobURLWithSAS := srcBlobParts.String() - - // Invoke CopyFromURL. - sourceContentMD5 := contentMD5[:] - resp, err := destBlob.CopyFromURL(context.Background(), srcBlobURLWithSAS, &blob.CopyFromURLOptions{ - SourceContentMD5: sourceContentMD5, - }) - _require.Nil(err) - _require.EqualValues(resp.ContentMD5, sourceContentMD5) - - // Provide bad MD5 and make sure the copy fails - _, badMD5 := testcommon.GetDataAndReader(testName, 16) - resp, err = destBlob.CopyFromURL(context.Background(), srcBlobURLWithSAS, &blob.CopyFromURLOptions{ - SourceContentMD5: badMD5, - }) - _require.NotNil(err) -} - func (s *BlobRecordedTestsSuite) TestBlobStartCopyDestEmpty() { _require := require.New(s.T()) testName := s.T().Name() @@ -3274,95 +3213,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()) diff --git a/sdk/storage/azblob/blob/constants.go b/sdk/storage/azblob/blob/constants.go index c15635448ef9..8a9107954381 100644 --- a/sdk/storage/azblob/blob/constants.go +++ b/sdk/storage/azblob/blob/constants.go @@ -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 diff --git a/sdk/storage/azblob/blob/models.go b/sdk/storage/azblob/blob/models.go index fea2f1ec505b..9ff5f24f5c0f 100644 --- a/sdk/storage/azblob/blob/models.go +++ b/sdk/storage/azblob/blob/models.go @@ -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{ @@ -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 } // --------------------------------------------------------------------------------------------------------------------- diff --git a/sdk/storage/azblob/bloberror/error_codes.go b/sdk/storage/azblob/bloberror/error_codes.go index ad653c1c4655..8a1573c0ce25 100644 --- a/sdk/storage/azblob/bloberror/error_codes.go +++ b/sdk/storage/azblob/bloberror/error_codes.go @@ -153,4 +153,5 @@ const ( var ( // MissingSharedKeyCredential - Error is returned when SAS URL is being created without SharedKeyCredential. MissingSharedKeyCredential = errors.New("SAS can only be signed with a SharedKeyCredential") + UnsupportedChecksum = errors.New("for multi-part uploads, user generated checksums cannot be validated") ) diff --git a/sdk/storage/azblob/blockblob/client.go b/sdk/storage/azblob/blockblob/client.go index d7e5aa0dc2d4..eedf4c2362e6 100644 --- a/sdk/storage/azblob/blockblob/client.go +++ b/sdk/storage/azblob/blockblob/client.go @@ -11,9 +11,12 @@ import ( "context" "encoding/base64" "errors" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror" "io" "math" "os" + "reflect" "sync" "time" @@ -43,10 +46,13 @@ type Client base.CompositeClient[generated.BlobClient, generated.BlockBlobClient 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.NewBlockBlobClient(blobURL, pl, nil)), nil + azClient, err := azcore.NewClient(shared.BlockBlobClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + return (*Client)(base.NewBlockBlobClient(blobURL, azClient, nil)), nil } // NewClientWithNoCredential creates an instance of Client with the specified values. @@ -55,9 +61,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.NewBlockBlobClient(blobURL, pl, nil)), nil + azClient, err := azcore.NewClient(shared.BlockBlobClient, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + + return (*Client)(base.NewBlockBlobClient(blobURL, azClient, nil)), nil } // NewClientWithSharedKeyCredential creates an instance of Client with the specified values. @@ -67,10 +77,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}} - return (*Client)(base.NewBlockBlobClient(blobURL, pl, cred)), nil + azClient, err := azcore.NewClient(shared.BlockBlobClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + + return (*Client)(base.NewBlockBlobClient(blobURL, azClient, cred)), nil } // NewClientFromConnectionString creates an instance of Client with the specified values. @@ -130,7 +144,7 @@ func (bb *Client) WithSnapshot(snapshot string) (*Client, error) { } p.Snapshot = snapshot - return (*Client)(base.NewBlockBlobClient(p.String(), bb.generated().Pipeline(), bb.sharedKey())), nil + return (*Client)(base.NewBlockBlobClient(p.String(), bb.generated().Internal(), bb.sharedKey())), nil } // WithVersionID creates a new AppendBlobURL object identical to the source but with the specified version id. @@ -142,7 +156,7 @@ func (bb *Client) WithVersionID(versionID string) (*Client, error) { } p.VersionID = versionID - return (*Client)(base.NewBlockBlobClient(p.String(), bb.generated().Pipeline(), bb.sharedKey())), nil + return (*Client)(base.NewBlockBlobClient(p.String(), bb.generated().Internal(), bb.sharedKey())), nil } // Upload creates a new block blob or overwrites an existing block blob. @@ -160,6 +174,13 @@ func (bb *Client) Upload(ctx context.Context, body io.ReadSeekCloser, options *U opts, httpHeaders, leaseInfo, cpkV, cpkN, accessConditions := options.format() + if options != nil && options.TransactionalValidation != nil { + body, err = options.TransactionalValidation.Apply(body, opts) + if err != nil { + return UploadResponse{}, err + } + } + resp, err := bb.generated().Upload(ctx, count, body, opts, httpHeaders, leaseInfo, cpkV, cpkN, accessConditions) return resp, err } @@ -248,6 +269,11 @@ func (bb *Client) CommitBlockList(ctx context.Context, base64BlockIDs []string, ImmutabilityPolicyExpiry: options.ImmutabilityPolicyExpiryTime, } + // If user attempts to pass in their own checksum, errors out. + if options.TransactionalContentMD5 != nil || options.TransactionalContentCRC64 != nil { + return CommitBlockListResponse{}, bloberror.UnsupportedChecksum + } + headers = options.HTTPHeaders leaseAccess, modifiedAccess = exported.FormatBlobAccessConditions(options.AccessConditions) cpkInfo = options.CPKInfo @@ -494,6 +520,12 @@ func (bb *Client) UploadBuffer(ctx context.Context, buffer []byte, o *UploadBuff if o != nil { uploadOptions = *o } + + // If user attempts to pass in their own checksum, errors out. + if uploadOptions.TransactionalValidation != nil && reflect.TypeOf(uploadOptions.TransactionalValidation).Kind() != reflect.Func { + return UploadBufferResponse{}, bloberror.UnsupportedChecksum + } + return bb.uploadFromReader(ctx, bytes.NewReader(buffer), int64(len(buffer)), &uploadOptions) } @@ -507,6 +539,12 @@ func (bb *Client) UploadFile(ctx context.Context, file *os.File, o *UploadFileOp if o != nil { uploadOptions = *o } + + // If user attempts to pass in their own checksum, errors out. + if uploadOptions.TransactionalValidation != nil && reflect.TypeOf(uploadOptions.TransactionalValidation).Kind() != reflect.Func { + return UploadFileResponse{}, bloberror.UnsupportedChecksum + } + return bb.uploadFromReader(ctx, file, stat.Size(), &uploadOptions) } @@ -517,6 +555,11 @@ func (bb *Client) UploadStream(ctx context.Context, body io.Reader, o *UploadStr o = &UploadStreamOptions{} } + // If user attempts to pass in their own checksum, errors out. + if o.TransactionalValidation != nil && reflect.TypeOf(o.TransactionalValidation).Kind() != reflect.Func { + return UploadStreamResponse{}, bloberror.UnsupportedChecksum + } + result, err := copyFromReader(ctx, body, bb, *o, newMMBPool) if err != nil { return CommitBlockListResponse{}, err diff --git a/sdk/storage/azblob/blockblob/client_test.go b/sdk/storage/azblob/blockblob/client_test.go index edafdf0622b7..bbc5ea81217d 100644 --- a/sdk/storage/azblob/blockblob/client_test.go +++ b/sdk/storage/azblob/blockblob/client_test.go @@ -257,6 +257,187 @@ type BlockBlobUnrecordedTestsSuite struct { // _require.Nil(err) // _require.EqualValues(destData, content) // } + +func (s *BlockBlobUnrecordedTestsSuite) TestStageBlockFromURLWithMD5() { + _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) + + contentSize := 4 * 1024 // 4 KB + r, sourceData := testcommon.GetDataAndReader(testName, contentSize) + contentMD5 := md5.Sum(sourceData) + rsc := streaming.NopCloser(r) + + srcBlob := containerClient.NewBlockBlobClient("src" + testcommon.GenerateBlobName(testName)) + destBlob := containerClient.NewBlockBlobClient("dst" + testcommon.GenerateBlobName(testName)) + + // Prepare source bbClient for copy. + _, err = srcBlob.Upload(context.Background(), rsc, nil) + _require.Nil(err) + + // Get source blob url with SAS for StageFromURL. + srcBlobParts, _ := blob.ParseURL(srcBlob.URL()) + credential, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + _require.Nil(err) + perms := sas.BlobPermissions{Read: true} + + srcBlobParts.SAS, err = sas.BlobSignatureValues{ + Protocol: sas.ProtocolHTTPS, // Users MUST use HTTPS (not HTTP) + ExpiryTime: time.Now().UTC().Add(48 * time.Hour), // 48-hours before expiration + ContainerName: srcBlobParts.ContainerName, + BlobName: srcBlobParts.BlobName, + Permissions: perms.String(), + }.SignWithSharedKey(credential) + _require.NoError(err) + + srcBlobURLWithSAS := srcBlobParts.String() + + // Stage blocks from URL. + blockIDs := testcommon.GenerateBlockIDsList(2) + + opts := blockblob.StageBlockFromURLOptions{ + SourceContentValidation: blob.SourceContentValidationTypeMD5(contentMD5[:]), + } + + stageResp1, err := destBlob.StageBlockFromURL(context.Background(), blockIDs[0], srcBlobURLWithSAS, &opts) + _require.Nil(err) + _require.Equal(stageResp1.ContentMD5, contentMD5[:]) + + stageResp2, err := destBlob.StageBlockFromURL(context.Background(), blockIDs[1], srcBlobURLWithSAS, &opts) + _require.Nil(err) + _require.Equal(stageResp2.ContentMD5, contentMD5[:]) + + // Check block list. + blockList, err := destBlob.GetBlockList(context.Background(), blockblob.BlockListTypeAll, nil) + _require.Nil(err) + _require.NotNil(blockList.BlockList) + _require.Nil(blockList.BlockList.CommittedBlocks) + _require.NotNil(blockList.BlockList.UncommittedBlocks) + _require.Len(blockList.BlockList.UncommittedBlocks, 2) + + // Commit block list. + _, err = destBlob.CommitBlockList(context.Background(), blockIDs, nil) + _require.Nil(err) + + // Check data integrity through downloading. + destBuffer := make([]byte, 4*1024) + downloadBufferOptions := blob.DownloadBufferOptions{Range: blob.HTTPRange{Offset: 0, Count: 4096}} + _, err = destBlob.DownloadBuffer(context.Background(), destBuffer, &downloadBufferOptions) + _require.Nil(err) + _require.Equal(destBuffer, sourceData) + + // Test stage block from URL with bad MD5 value + _, badMD5 := testcommon.GetDataAndReader(testName, 16) + var badMD5Validator blob.SourceContentValidationTypeMD5 = badMD5[:] + opts = blockblob.StageBlockFromURLOptions{ + SourceContentValidation: badMD5Validator, + } + _, err = destBlob.StageBlockFromURL(context.Background(), blockIDs[0], srcBlobURLWithSAS, &opts) + _require.NotNil(err) + testcommon.ValidateBlobErrorCode(_require, err, bloberror.MD5Mismatch) + + _, err = destBlob.StageBlockFromURL(context.Background(), blockIDs[1], srcBlobURLWithSAS, &opts) + _require.NotNil(err) + testcommon.ValidateBlobErrorCode(_require, err, bloberror.MD5Mismatch) +} + +func (s *BlockBlobUnrecordedTestsSuite) TestStageBlockFromURLWithCRC64() { + _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) + + contentSize := 4 * 1024 // 4 KB + r, sourceData := testcommon.GetDataAndReader(testName, contentSize) + rsc := streaming.NopCloser(r) + crc64Value := crc64.Checksum(sourceData, shared.CRC64Table) + crc := make([]byte, 8) + binary.LittleEndian.PutUint64(crc, crc64Value) + + srcBlob := containerClient.NewBlockBlobClient("src" + testcommon.GenerateBlobName(testName)) + destBlob := containerClient.NewBlockBlobClient("dst" + testcommon.GenerateBlobName(testName)) + + // Prepare source bbClient for copy. + _, err = srcBlob.Upload(context.Background(), rsc, nil) + _require.Nil(err) + + // Get source blob url with SAS for StageFromURL. + srcBlobParts, _ := blob.ParseURL(srcBlob.URL()) + credential, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + _require.Nil(err) + perms := sas.BlobPermissions{Read: true} + + srcBlobParts.SAS, err = sas.BlobSignatureValues{ + Protocol: sas.ProtocolHTTPS, // Users MUST use HTTPS (not HTTP) + ExpiryTime: time.Now().UTC().Add(48 * time.Hour), // 48-hours before expiration + ContainerName: srcBlobParts.ContainerName, + BlobName: srcBlobParts.BlobName, + Permissions: perms.String(), + }.SignWithSharedKey(credential) + _require.NoError(err) + + srcBlobURLWithSAS := srcBlobParts.String() + + // Stage blocks from URL. + blockIDs := testcommon.GenerateBlockIDsList(2) + + opts := blockblob.StageBlockFromURLOptions{ + SourceContentValidation: blob.SourceContentValidationTypeCRC64(crc), + } + + stageResp1, err := destBlob.StageBlockFromURL(context.Background(), blockIDs[0], srcBlobURLWithSAS, &opts) + _require.Nil(err) + _require.Equal(stageResp1.ContentCRC64, crc) + + stageResp2, err := destBlob.StageBlockFromURL(context.Background(), blockIDs[1], srcBlobURLWithSAS, &opts) + _require.Nil(err) + _require.Equal(stageResp2.ContentCRC64, crc) + + // Check block list. + blockList, err := destBlob.GetBlockList(context.Background(), blockblob.BlockListTypeAll, nil) + _require.Nil(err) + _require.NotNil(blockList.BlockList) + _require.Nil(blockList.BlockList.CommittedBlocks) + _require.NotNil(blockList.BlockList.UncommittedBlocks) + _require.Len(blockList.BlockList.UncommittedBlocks, 2) + + // Commit block list. + _, err = destBlob.CommitBlockList(context.Background(), blockIDs, nil) + _require.Nil(err) + + // Check data integrity through downloading. + destBuffer := make([]byte, 4*1024) + downloadBufferOptions := blob.DownloadBufferOptions{Range: blob.HTTPRange{Offset: 0, Count: 4096}} + _, err = destBlob.DownloadBuffer(context.Background(), destBuffer, &downloadBufferOptions) + _require.Nil(err) + _require.Equal(destBuffer, sourceData) + + // Test stage block from URL with bad CRC64 value + _, sourceData = testcommon.GetDataAndReader(testName, 16) + crc64Value = crc64.Checksum(sourceData, shared.CRC64Table) + badCRC := make([]byte, 8) + binary.LittleEndian.PutUint64(badCRC, crc64Value) + opts = blockblob.StageBlockFromURLOptions{ + SourceContentValidation: blob.SourceContentValidationTypeCRC64(badCRC), + } + _, err = destBlob.StageBlockFromURL(context.Background(), blockIDs[0], srcBlobURLWithSAS, &opts) + _require.NotNil(err) + testcommon.ValidateBlobErrorCode(_require, err, bloberror.CRC64Mismatch) + + _, err = destBlob.StageBlockFromURL(context.Background(), blockIDs[1], srcBlobURLWithSAS, &opts) + _require.NotNil(err) + testcommon.ValidateBlobErrorCode(_require, err, bloberror.CRC64Mismatch) +} + // // func (s *BlockBlobUnrecordedTestsSuite) TestCopyBlockBlobFromURL() { // _require := require.New(s.T()) @@ -421,7 +602,7 @@ type BlockBlobUnrecordedTestsSuite struct { // } // nolint -func (s *BlockBlobUnrecordedTestsSuite) TestStageBlockWithGeneratedCRC64() { +func (s *BlockBlobRecordedTestsSuite) TestStageBlockWithGeneratedCRC64() { _require := require.New(s.T()) testName := s.T().Name() svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) @@ -434,7 +615,7 @@ func (s *BlockBlobUnrecordedTestsSuite) TestStageBlockWithGeneratedCRC64() { blobName := testcommon.GenerateBlobName(testName) bbClient := containerClient.NewBlockBlobClient(blobName) - // test put block with valid CRC64 value + // test stage block with valid CRC64 value contentSize := 8 * 1024 // 8 KB content := make([]byte, contentSize) body := bytes.NewReader(content) @@ -446,24 +627,49 @@ func (s *BlockBlobUnrecordedTestsSuite) TestStageBlockWithGeneratedCRC64() { TransactionalValidation: blob.TransferValidationTypeComputeCRC64(), }) _require.Nil(err) - // _require.Equal(putResp.RawResponse.StatusCode, 201) _require.NotNil(putResp.ContentCRC64) _require.EqualValues(binary.LittleEndian.Uint64(putResp.ContentCRC64), contentCrc64) _require.NotNil(putResp.RequestID) _require.NotNil(putResp.Version) _require.NotNil(putResp.Date) _require.Equal((*putResp.Date).IsZero(), false) +} + +func (s *BlockBlobRecordedTestsSuite) TestStageBlockWithCRC64() { + _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) + + blobName := testcommon.GenerateBlobName(testName) + bbClient := containerClient.NewBlockBlobClient(blobName) + + // test stage block with valid CRC64 value + contentSize := 8 * 1024 // 8 KB + content := make([]byte, contentSize) + body := bytes.NewReader(content) + contentCrc64 := crc64.Checksum(content, shared.CRC64Table) + rsc := streaming.NopCloser(body) + + blockID1 := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%6d", 0))) + putResp, err := bbClient.StageBlock(context.Background(), blockID1, rsc, &blockblob.StageBlockOptions{ + TransactionalValidation: blob.TransferValidationTypeCRC64(contentCrc64), + }) + _require.Nil(err) + _require.EqualValues(binary.LittleEndian.Uint64(putResp.ContentCRC64), contentCrc64) // test put block with bad CRC64 value badContentCrc64 := rand.Uint64() - _, _ = rsc.Seek(0, io.SeekStart) blockID2 := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%6d", 1))) _, err = bbClient.StageBlock(context.Background(), blockID2, rsc, &blockblob.StageBlockOptions{ TransactionalValidation: blob.TransferValidationTypeCRC64(badContentCrc64), }) _require.NotNil(err) - _require.Contains(err.Error(), bloberror.CRC64Mismatch) } // nolint @@ -480,7 +686,7 @@ func (s *BlockBlobRecordedTestsSuite) TestStageBlockWithMD5() { blobName := testcommon.GenerateBlobName(testName) bbClient := containerClient.NewBlockBlobClient(blobName) - // test put block with valid MD5 value + // test stage block with valid MD5 value contentSize := 8 * 1024 // 8 KB content := make([]byte, contentSize) body := bytes.NewReader(content) @@ -493,14 +699,13 @@ func (s *BlockBlobRecordedTestsSuite) TestStageBlockWithMD5() { TransactionalValidation: blob.TransferValidationTypeMD5(contentMD5), }) _require.Nil(err) - // _require.Equal(putResp.RawResponse.StatusCode, 201) _require.EqualValues(putResp.ContentMD5, contentMD5) _require.NotNil(putResp.RequestID) _require.NotNil(putResp.Version) _require.NotNil(putResp.Date) _require.Equal((*putResp.Date).IsZero(), false) - // test put block with bad MD5 value + // test stage block with bad MD5 value _, badContent := testcommon.GetDataAndReader(testName, contentSize) badMD5Value := md5.Sum(badContent) badContentMD5 := badMD5Value[:] @@ -514,6 +719,39 @@ func (s *BlockBlobRecordedTestsSuite) TestStageBlockWithMD5() { _require.Contains(err.Error(), bloberror.MD5Mismatch) } +func (s *BlockBlobRecordedTestsSuite) TestPutBlobWithCRC64() { + s.T().Skip("Content CRC64 cannot be validated in Upload()") + _require := require.New(s.T()) + testName := s.T().Name() + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + containerName := "test" + testcommon.GenerateContainerName(testName) + "1" + containerClient := testcommon.CreateNewContainer(context.Background(), _require, containerName, svcClient) + defer testcommon.DeleteContainer(context.Background(), _require, containerClient) + + contentSize := 4 * 1024 // 4 KB + r, sourceData := testcommon.GetDataAndReader(testName, contentSize) + rsc := streaming.NopCloser(r) + crc64Value := crc64.Checksum(sourceData, shared.CRC64Table) + crc := make([]byte, 8) + binary.LittleEndian.PutUint64(crc, crc64Value) + + blobName := testcommon.GenerateBlobName(testName) + bbClient := testcommon.GetBlockBlobClient(blobName, containerClient) + + blockID := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%6d", 0))) + _, err = bbClient.StageBlock(context.Background(), blockID, streaming.NopCloser(strings.NewReader(testcommon.BlockBlobDefaultData)), nil) + _require.Nil(err) + + _, err = bbClient.Upload(context.Background(), rsc, &blockblob.UploadOptions{ + TransactionalValidation: blob.TransferValidationTypeCRC64(crc64Value), + }) + _require.Error(err, bloberror.UnsupportedChecksum) + // TODO: UploadResponse does not return ContentCRC64 + // _require.Equal(resp.ContentCRC64, crc) +} + func (s *BlockBlobRecordedTestsSuite) TestBlobPutBlobHTTPHeaders() { _require := require.New(s.T()) testName := s.T().Name() @@ -613,7 +851,7 @@ func setUpPutBlobFromURLTest(testName string, _require *require.Assertions, svcC sasQueryParams, err := sas.AccountSignatureValues{ Protocol: sas.ProtocolHTTPS, ExpiryTime: expiryTime, - Permissions: to.Ptr(sas.AccountPermissions{Read: true, List: true}).String(), + Permissions: to.Ptr(sas.AccountPermissions{Read: true, List: true, Tag: true}).String(), ResourceTypes: to.Ptr(sas.AccountResourceTypes{Container: true, Object: true}).String(), }.SignWithSharedKey(credential) _require.Nil(err) @@ -646,6 +884,121 @@ func (s *BlockBlobUnrecordedTestsSuite) TestPutBlobFromURL() { _require.Equal(destBuffer, sourceData) } +func (s *BlockBlobUnrecordedTestsSuite) TestPutBlobFromURLWithCopySourceTagsDefault() { + _require := require.New(s.T()) + testName := s.T().Name() + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + containerClient, srcBlob, destBlob, srcBlobURLWithSAS, _ := setUpPutBlobFromURLTest(testName, _require, svcClient) + defer testcommon.DeleteContainer(context.Background(), _require, containerClient) + + // Set tags to source + srcBlobTagsMap := map[string]string{ + "source": "tags", + } + _, err = srcBlob.SetTags(context.Background(), srcBlobTagsMap, nil) + _require.NoError(err) + + // Dest tags + destBlobTagsMap := map[string]string{ + "dest": "tags", + } + + // By default, the CopySourceTag header is Replace + options := blockblob.UploadBlobFromURLOptions{ + Tags: destBlobTagsMap, + } + + // Invoke UploadBlobFromURL + pbResp, err := destBlob.UploadBlobFromURL(context.Background(), srcBlobURLWithSAS, &options) + _require.NotNil(pbResp) + _require.NoError(err) + + // Get tags from dest and check if tags got replaced with dest tags + resp, err := destBlob.GetTags(context.Background(), nil) + _require.NoError(err) + _require.Equal(*resp.BlobTagSet[0].Key, "dest") + _require.Equal(*resp.BlobTagSet[0].Value, "tags") +} + +func (s *BlockBlobUnrecordedTestsSuite) TestPutBlobFromURLWithCopySourceTagsReplace() { + _require := require.New(s.T()) + testName := s.T().Name() + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + containerClient, srcBlob, destBlob, srcBlobURLWithSAS, _ := setUpPutBlobFromURLTest(testName, _require, svcClient) + defer testcommon.DeleteContainer(context.Background(), _require, containerClient) + + // Set tags to source + srcBlobTagsMap := map[string]string{ + "source": "tags", + } + _, err = srcBlob.SetTags(context.Background(), srcBlobTagsMap, nil) + _require.NoError(err) + + // Dest tags + destBlobTagsMap := map[string]string{ + "dest": "tags", + } + + options := blockblob.UploadBlobFromURLOptions{ + Tags: destBlobTagsMap, + CopySourceTags: to.Ptr(blockblob.BlobCopySourceTagsReplace), + } + + // Invoke UploadBlobFromURL + pbResp, err := destBlob.UploadBlobFromURL(context.Background(), srcBlobURLWithSAS, &options) + _require.NotNil(pbResp) + _require.NoError(err) + + // Get tags from dest and check if tags got replaced with dest tags + resp, err := destBlob.GetTags(context.Background(), nil) + _require.NoError(err) + _require.Equal(*resp.BlobTagSet[0].Key, "dest") + _require.Equal(*resp.BlobTagSet[0].Value, "tags") +} + +func (s *BlockBlobUnrecordedTestsSuite) TestPutBlobFromURLWithCopySourceTagsCopy() { + _require := require.New(s.T()) + testName := s.T().Name() + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + containerClient, srcBlob, destBlob, srcBlobURLWithSAS, _ := setUpPutBlobFromURLTest(testName, _require, svcClient) + defer testcommon.DeleteContainer(context.Background(), _require, containerClient) + + // Set tags to source + srcBlobTagsMap := map[string]string{ + "source": "tags", + } + _, err = srcBlob.SetTags(context.Background(), srcBlobTagsMap, nil) + _require.NoError(err) + + // Set tags to dest to ensure that COPY works + destBlobTagsMap := map[string]string{ + "dest": "tags", + } + _, err = destBlob.SetTags(context.Background(), destBlobTagsMap, nil) + _require.NoError(err) + + options := blockblob.UploadBlobFromURLOptions{ + CopySourceTags: to.Ptr(blockblob.BlobCopySourceTagsCopy), + } + + // Invoke UploadBlobFromURL + pbResp, err := destBlob.UploadBlobFromURL(context.Background(), srcBlobURLWithSAS, &options) + _require.NotNil(pbResp) + _require.NoError(err) + + // Get tags from dest and check if it matches source tags + resp, err := destBlob.GetTags(context.Background(), nil) + _require.NoError(err) + _require.Equal(*resp.BlobTagSet[0].Key, "source") + _require.Equal(*resp.BlobTagSet[0].Value, "tags") +} + func (s *BlockBlobUnrecordedTestsSuite) TestPutBlobFromURLNegative() { _require := require.New(s.T()) testName := s.T().Name() @@ -1247,6 +1600,56 @@ func (s *BlockBlobRecordedTestsSuite) TestPutBlobFromURLCopySourceAuthNegative() testcommon.ValidateBlobErrorCode(_require, err, bloberror.CannotVerifyCopySource) } +func (s *BlockBlobUnrecordedTestsSuite) TestPutBlobFromURLWithTier() { + _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) + + src := testcommon.GenerateBlobName("src" + testName) + srcBlob := testcommon.CreateNewBlockBlob(context.Background(), _require, src, containerClient) + + // Create SAS for source and get SAS URL + expiryTime := time.Now().UTC().Add(15 * time.Minute) + _require.Nil(err) + + credential, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + _require.NoError(err) + + sasQueryParams, err := sas.AccountSignatureValues{ + Protocol: sas.ProtocolHTTPS, + ExpiryTime: expiryTime, + Permissions: to.Ptr(sas.AccountPermissions{Read: true, List: true}).String(), + ResourceTypes: to.Ptr(sas.AccountResourceTypes{Container: true, Object: true}).String(), + }.SignWithSharedKey(credential) + _require.Nil(err) + + srcBlobParts, _ := blob.ParseURL(srcBlob.URL()) + srcBlobParts.SAS = sasQueryParams + srcBlobURLWithSAS := srcBlobParts.String() + + for _, tier := range []blob.AccessTier{blob.AccessTierArchive, blob.AccessTierCool, blob.AccessTierHot, blob.AccessTierCold} { + dest := testcommon.GenerateBlobName("dest" + string(tier) + testName) + destBlob := testcommon.CreateNewBlockBlob(context.Background(), _require, dest, containerClient) + + opts := blockblob.UploadBlobFromURLOptions{ + Tier: &tier, + } + // Invoke UploadBlobFromURL + pbResp, err := destBlob.UploadBlobFromURL(context.Background(), srcBlobURLWithSAS, &opts) + _require.NotNil(pbResp) + _require.NoError(err) + + getResp, err := destBlob.GetProperties(context.Background(), nil) + _require.Nil(err) + _require.Equal(*getResp.AccessTier, string(tier)) + } +} + func (s *BlockBlobRecordedTestsSuite) TestPutBlockListWithImmutabilityPolicy() { _require := require.New(s.T()) testName := s.T().Name() @@ -1909,7 +2312,7 @@ func (s *BlockBlobRecordedTestsSuite) TestSetTierOnBlobUpload() { containerClient := testcommon.CreateNewContainer(context.Background(), _require, containerName, svcClient) defer testcommon.DeleteContainer(context.Background(), _require, containerClient) - for _, tier := range []blob.AccessTier{blob.AccessTierArchive, blob.AccessTierCool, blob.AccessTierHot} { + for _, tier := range []blob.AccessTier{blob.AccessTierArchive, blob.AccessTierCool, blob.AccessTierHot, blob.AccessTierCold} { blobName := strings.ToLower(string(tier)) + testcommon.GenerateBlobName(testName) bbClient := testcommon.GetBlockBlobClient(blobName, containerClient) @@ -1936,7 +2339,7 @@ func (s *BlockBlobRecordedTestsSuite) TestBlobSetTierOnCommit() { containerClient := testcommon.CreateNewContainer(context.Background(), _require, containerName, svcClient) defer testcommon.DeleteContainer(context.Background(), _require, containerClient) - for _, tier := range []blob.AccessTier{blob.AccessTierCool, blob.AccessTierHot} { + for _, tier := range []blob.AccessTier{blob.AccessTierCool, blob.AccessTierHot, blob.AccessTierCold} { blobName := strings.ToLower(string(tier)) + testcommon.GenerateBlobName(testName) bbClient := testcommon.GetBlockBlobClient(blobName, containerClient) @@ -1955,7 +2358,120 @@ func (s *BlockBlobRecordedTestsSuite) TestBlobSetTierOnCommit() { _require.NotNil(resp.BlockList.CommittedBlocks) _require.Nil(resp.BlockList.UncommittedBlocks) _require.Len(resp.BlockList.CommittedBlocks, 1) + + getResp, err := bbClient.GetProperties(context.Background(), nil) + _require.NoError(err) + _require.Equal(*getResp.AccessTier, string(tier)) + } +} + +func (s *BlockBlobRecordedTestsSuite) TestCommitBlockListWithMD5() { + _require := require.New(s.T()) + testName := s.T().Name() + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + containerName := "test" + testcommon.GenerateContainerName(testName) + containerClient := testcommon.CreateNewContainer(context.Background(), _require, containerName, svcClient) + defer testcommon.DeleteContainer(context.Background(), _require, containerClient) + + contentSize := 4 * 1024 // 4 KB + _, sourceData := testcommon.GetDataAndReader(testName, contentSize) + contentMD5 := md5.Sum(sourceData) + + blobName := testcommon.GenerateBlobName(testName) + bbClient := testcommon.GetBlockBlobClient(blobName, containerClient) + + blockID := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%6d", 0))) + _, err = bbClient.StageBlock(context.Background(), blockID, streaming.NopCloser(strings.NewReader(testcommon.BlockBlobDefaultData)), nil) + _require.Nil(err) + + // CommitBlockList is a multipart upload, user generated checksum cannot be passed + _, err = bbClient.CommitBlockList(context.Background(), []string{blockID}, &blockblob.CommitBlockListOptions{ + TransactionalContentMD5: contentMD5[:], + }) + _require.Error(err, bloberror.UnsupportedChecksum) +} + +func (s *BlockBlobRecordedTestsSuite) TestCommitBlockListWithCRC64() { + _require := require.New(s.T()) + testName := s.T().Name() + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + containerName := "test" + testcommon.GenerateContainerName(testName) + "1" + containerClient := testcommon.CreateNewContainer(context.Background(), _require, containerName, svcClient) + defer testcommon.DeleteContainer(context.Background(), _require, containerClient) + + contentSize := 4 * 1024 // 4 KB + _, sourceData := testcommon.GetDataAndReader(testName, contentSize) + crc64Value := crc64.Checksum(sourceData, shared.CRC64Table) + crc := make([]byte, 8) + binary.LittleEndian.PutUint64(crc, crc64Value) + + blobName := testcommon.GenerateBlobName(testName) + bbClient := testcommon.GetBlockBlobClient(blobName, containerClient) + + blockID := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%6d", 0))) + _, err = bbClient.StageBlock(context.Background(), blockID, streaming.NopCloser(strings.NewReader(testcommon.BlockBlobDefaultData)), nil) + _require.Nil(err) + + // CommitBlockList is a multipart upload, user generated checksum cannot be passed + _, err = bbClient.CommitBlockList(context.Background(), []string{blockID}, &blockblob.CommitBlockListOptions{ + TransactionalContentCRC64: crc, + }) + _require.Error(err, bloberror.UnsupportedChecksum) +} + +func (s *BlockBlobUnrecordedTestsSuite) TestCopyBlockBlobFromURLWithEncryptionScope() { + _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) + + // set up source blob + const contentSize = 4 * 1024 * 1024 // 4 MB + contentReader, _ := testcommon.GetDataAndReader(testName, contentSize) + + srcBlob := containerClient.NewBlockBlobClient(testcommon.GenerateBlobName(testName)) + _, err = srcBlob.Upload(context.Background(), streaming.NopCloser(contentReader), nil) + _require.Nil(err) + + // Get source blob url with SAS for StageFromURL. + credential, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + _require.Nil(err) + + sasQueryParams, err := sas.AccountSignatureValues{ + Protocol: sas.ProtocolHTTPS, + ExpiryTime: time.Now().UTC().Add(48 * time.Hour), // 48-hours before expiration, + Permissions: to.Ptr(sas.AccountPermissions{Read: true, List: true}).String(), + ResourceTypes: to.Ptr(sas.AccountResourceTypes{Container: true, Object: true}).String(), + }.SignWithSharedKey(credential) + _require.Nil(err) + + srcBlobParts, _ := blob.ParseURL(srcBlob.URL()) + srcBlobParts.SAS = sasQueryParams + srcBlobURLWithSAS := srcBlobParts.String() + + destBlobName := testcommon.GenerateBlobName(testName) + destBlob := containerClient.NewBlockBlobClient(testcommon.GenerateBlobName(destBlobName)) + + encryptionScope, err := testcommon.GetRequiredEnv(testcommon.EncryptionScopeEnvVar) + _require.Nil(err) + cpk := blob.CPKScopeInfo{ + EncryptionScope: to.Ptr(encryptionScope), } + copyBlockBlobFromURLOptions := blob.CopyFromURLOptions{ + CPKScopeInfo: &cpk, + } + resp, err := destBlob.CopyFromURL(context.Background(), srcBlobURLWithSAS, ©BlockBlobFromURLOptions) + _require.Nil(err) + _require.Equal(*resp.CopyStatus, "success") + _require.Equal(*resp.EncryptionScope, encryptionScope) } func (s *BlockBlobUnrecordedTestsSuite) TestSetTierOnCopyBlockBlobFromURL() { @@ -1998,7 +2514,7 @@ func (s *BlockBlobUnrecordedTestsSuite) TestSetTierOnCopyBlockBlobFromURL() { srcBlobParts.SAS = sasQueryParams srcBlobURLWithSAS := srcBlobParts.String() - for _, tier := range []blob.AccessTier{blob.AccessTierArchive, blob.AccessTierCool, blob.AccessTierHot} { + for _, tier := range []blob.AccessTier{blob.AccessTierArchive, blob.AccessTierCool, blob.AccessTierHot, blob.AccessTierCold} { destBlobName := strings.ToLower(string(tier)) + testcommon.GenerateBlobName(testName) destBlob := containerClient.NewBlockBlobClient(testcommon.GenerateBlobName(destBlobName)) @@ -2017,6 +2533,59 @@ func (s *BlockBlobUnrecordedTestsSuite) TestSetTierOnCopyBlockBlobFromURL() { } } +func (s *BlockBlobUnrecordedTestsSuite) TestCopyBlockBlobFromUrlSourceContentMD5() { + _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) + + contentSize := 8 * 1024 // 8 KB + body, sourceData := testcommon.GetDataAndReader(testName, contentSize) + contentMD5 := md5.Sum(sourceData) + + srcBlob := containerClient.NewBlockBlobClient("src" + testName) + destBlob := containerClient.NewBlockBlobClient("dest" + testName) + + // Prepare source bbClient for copy. + _, err = srcBlob.Upload(context.Background(), streaming.NopCloser(body), nil) + _require.Nil(err) + + credential, err := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + _require.NoError(err) + + // Get source blob url with SAS for CopyFromURL. + sasQueryParams, err := sas.AccountSignatureValues{ + Protocol: sas.ProtocolHTTPS, + ExpiryTime: time.Now().UTC().Add(48 * time.Hour), // 48-hours before expiration, + Permissions: to.Ptr(sas.AccountPermissions{Read: true, List: true}).String(), + ResourceTypes: to.Ptr(sas.AccountResourceTypes{Container: true, Object: true}).String(), + }.SignWithSharedKey(credential) + _require.Nil(err) + + srcBlobParts, _ := blob.ParseURL(srcBlob.URL()) + srcBlobParts.SAS = sasQueryParams + srcBlobURLWithSAS := srcBlobParts.String() + + // Invoke CopyFromURL. + sourceContentMD5 := contentMD5[:] + resp, err := destBlob.CopyFromURL(context.Background(), srcBlobURLWithSAS, &blob.CopyFromURLOptions{ + SourceContentMD5: sourceContentMD5, + }) + _require.Nil(err) + _require.EqualValues(resp.ContentMD5, sourceContentMD5) + + // Provide bad MD5 and make sure the copy fails + _, badMD5 := testcommon.GetDataAndReader(testName, 16) + resp, err = destBlob.CopyFromURL(context.Background(), srcBlobURLWithSAS, &blob.CopyFromURLOptions{ + SourceContentMD5: badMD5, + }) + _require.NotNil(err) +} + // func (s *BlockBlobUnrecordedTestsSuite) TestSetTierOnStageBlockFromURL() { // _require := require.New(s.T()) // testName := s.T().Name() @@ -2247,6 +2816,34 @@ func (s *BlockBlobRecordedTestsSuite) TestCopyBlobWithRehydratePriority() { _require.Equal(*getResp2.ArchiveStatus, string(blob.ArchiveStatusRehydratePendingToHot)) } +func (s *BlockBlobRecordedTestsSuite) TestCopyWithTier() { + _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) + + for _, tier := range []blob.AccessTier{blob.AccessTierArchive, blob.AccessTierCool, blob.AccessTierHot, blob.AccessTierCold} { + src := testcommon.GenerateBlobName("src" + string(tier) + testName) + srcBlob := testcommon.CreateNewBlockBlob(context.Background(), _require, src, containerClient) + + dest := testcommon.GenerateBlobName("dest" + string(tier) + testName) + destBlob := testcommon.CreateNewBlockBlob(context.Background(), _require, dest, containerClient) + + _, err = destBlob.StartCopyFromURL(context.Background(), srcBlob.URL(), &blob.StartCopyFromURLOptions{ + Tier: &tier, + }) + _require.NoError(err) + + getResp, err := destBlob.GetProperties(context.Background(), nil) + _require.Nil(err) + _require.Equal(*getResp.AccessTier, string(tier)) + } +} + func (s *BlockBlobRecordedTestsSuite) TestBlobServiceClientDelete() { _require := require.New(s.T()) svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) @@ -3915,6 +4512,46 @@ func (s *BlockBlobRecordedTestsSuite) TestPutBlockAndPutBlockListWithCPKByScope( // _require.EqualValues(*downloadResp.EncryptionScope, *testcommon.TestCPKByScope.EncryptionScope) // } +func (s *BlockBlobRecordedTestsSuite) TestUploadBlobWithMD5() { + _require := require.New(s.T()) + testName := s.T().Name() + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + containerClient := testcommon.CreateNewContainer(context.Background(), _require, testcommon.GenerateContainerName(testName), svcClient) + defer testcommon.DeleteContainer(context.Background(), _require, containerClient) + + contentSize := 8 * 1024 + r, srcData := testcommon.GenerateData(contentSize) + md5Val := md5.Sum(srcData) + bbClient := containerClient.NewBlockBlobClient(testcommon.GenerateBlobName(testName)) + + uploadBlockBlobOptions := blockblob.UploadOptions{ + TransactionalValidation: blob.TransferValidationTypeMD5(md5Val[:]), + } + uploadResp, err := bbClient.Upload(context.Background(), r, &uploadBlockBlobOptions) + _require.Nil(err) + _require.Equal(uploadResp.ContentMD5, md5Val[:]) + + // Download blob to do data integrity check. + downloadResp, err := bbClient.DownloadStream(context.Background(), nil) + _require.Nil(err) + _require.EqualValues(downloadResp.ContentMD5, md5Val[:]) + destData, err := io.ReadAll(downloadResp.Body) + _require.Nil(err) + _require.EqualValues(destData, srcData) + + // Test Upload with bad MD5 + _, badMD5 := testcommon.GetDataAndReader(testName, 16) + var badMD5Validator blob.TransferValidationTypeMD5 = badMD5[:] + + uploadBlockBlobOptions = blockblob.UploadOptions{ + TransactionalValidation: badMD5Validator, + } + uploadResp, err = bbClient.Upload(context.Background(), r, &uploadBlockBlobOptions) + _require.NotNil(err) +} + func (s *BlockBlobRecordedTestsSuite) TestUploadBlobWithMD5WithCPK() { _require := require.New(s.T()) testName := s.T().Name() @@ -4598,6 +5235,73 @@ func (s *BlockBlobUnrecordedTestsSuite) TestUploadFromReader() { } } +/* siminsavani: This test has a large allocation and blocks other tests from running that's why this test is commented out +func (s *BlockBlobUnrecordedTestsSuite) TestLargeBlockBufferedUploadInParallelWithGeneratedCRC64() { + _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) + + bbClient := testcommon.GetBlockBlobClient(testcommon.GenerateBlobName(testName), containerClient) + + var largeBlockSize, numberOfBlocks int64 = 2500 * 1024 * 1024, 2 + _, sourceData := testcommon.GetDataAndReader(testName, int(numberOfBlocks*largeBlockSize)) + // rsc := streaming.NopCloser(r) + crc64Value := crc64.Checksum(sourceData, shared.CRC64Table) + crc := make([]byte, 8) + binary.LittleEndian.PutUint64(crc, crc64Value) + + _, err = bbClient.UploadBuffer(context.Background(), sourceData, &blockblob.UploadBufferOptions{ + TransactionalValidation: blob.TransferValidationTypeComputeCRC64(), + BlockSize: largeBlockSize, + Concurrency: 2, + }) + _require.Nil(err) + + resp, err := bbClient.GetBlockList(context.Background(), blockblob.BlockListTypeAll, nil) + _require.Nil(err) + _require.Len(resp.BlockList.CommittedBlocks, 2) + _require.Equal(*resp.BlobContentLength, numberOfBlocks*largeBlockSize) + committed := resp.BlockList.CommittedBlocks + _require.Equal(*(committed[0].Size), largeBlockSize) + _require.Equal(*(committed[1].Size), largeBlockSize) +}*/ + +func (s *BlockBlobRecordedTestsSuite) TestUploadBufferWithCRC64OrMD5() { + _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) + + bbClient := testcommon.GetBlockBlobClient(testcommon.GenerateBlobName(testName), containerClient) + + _, content := testcommon.GetDataAndReader(testName, 1024) + md5Value := md5.Sum(content) + contentMD5 := md5Value[:] + + crc64Value := crc64.Checksum(content, shared.CRC64Table) + + _, err = bbClient.UploadBuffer(context.Background(), content, &blockblob.UploadBufferOptions{ + TransactionalValidation: blob.TransferValidationTypeCRC64(crc64Value), + }) + _require.NotNil(err) + _require.Error(err, bloberror.UnsupportedChecksum) + + _, err = bbClient.UploadBuffer(context.Background(), content, &blockblob.UploadBufferOptions{ + TransactionalValidation: blob.TransferValidationTypeMD5(contentMD5), + }) + _require.NotNil(err) + _require.Error(err, bloberror.UnsupportedChecksum) +} + func (s *BlockBlobRecordedTestsSuite) TestBlockGetAccountInfo() { _require := require.New(s.T()) testName := s.T().Name() diff --git a/sdk/storage/azblob/blockblob/constants.go b/sdk/storage/azblob/blockblob/constants.go index cb11626402d7..ce3a5d8de3f2 100644 --- a/sdk/storage/azblob/blockblob/constants.go +++ b/sdk/storage/azblob/blockblob/constants.go @@ -37,3 +37,16 @@ const ( func PossibleBlockListTypeValues() []BlockListType { return generated.PossibleBlockListTypeValues() } + +// BlobCopySourceTags - can be 'COPY' or 'REPLACE' +type BlobCopySourceTags = generated.BlobCopySourceTags + +const ( + BlobCopySourceTagsCopy = generated.BlobCopySourceTagsCOPY + BlobCopySourceTagsReplace = generated.BlobCopySourceTagsREPLACE +) + +// PossibleBlobCopySourceTagsValues returns the possible values for the BlobCopySourceTags const type. +func PossibleBlobCopySourceTagsValues() []BlobCopySourceTags { + return generated.PossibleBlobCopySourceTagsValues() +} diff --git a/sdk/storage/azblob/blockblob/models.go b/sdk/storage/azblob/blockblob/models.go index ba1b9ee9f67b..453d569e5d2d 100644 --- a/sdk/storage/azblob/blockblob/models.go +++ b/sdk/storage/azblob/blockblob/models.go @@ -36,8 +36,9 @@ type UploadOptions struct { // Optional. Indicates the tier to be set on the blob. Tier *blob.AccessTier - // Specify the transactional md5 for the body, to be validated by the service. - TransactionalContentMD5 []byte + // TransactionalValidation specifies the transfer validation type to use. + // The default is nil (no transfer validation). + TransactionalValidation blob.TransferValidationType HTTPHeaders *blob.HTTPHeaders CPKInfo *blob.CPKInfo @@ -46,6 +47,9 @@ type UploadOptions struct { LegalHold *bool ImmutabilityPolicyMode *blob.ImmutabilityPolicySetting ImmutabilityPolicyExpiryTime *time.Time + + // Deprecated: TransactionalContentMD5 can be set by using TransactionalValidation instead + TransactionalContentMD5 []byte } func (o *UploadOptions) format() (*generated.BlockBlobClientUploadOptions, *generated.BlobHTTPHeaders, *generated.LeaseAccessConditions, @@ -81,6 +85,9 @@ type UploadBlobFromURLOptions struct { // Optional, default is true. Indicates if properties from the source blob should be copied. CopySourceBlobProperties *bool + // Optional, default 'replace'. Indicates if source tags should be copied or replaced with the tags specified by x-ms-tags. + CopySourceTags *BlobCopySourceTags + // Optional. Specifies a user-defined name-value pair associated with the blob. Metadata map[string]*string @@ -109,6 +116,7 @@ func (o *UploadBlobFromURLOptions) format() (*generated.BlockBlobClientPutBlobFr BlobTagsString: shared.SerializeBlobTagsToStrPtr(o.Tags), CopySourceAuthorization: o.CopySourceAuthorization, CopySourceBlobProperties: o.CopySourceBlobProperties, + CopySourceTags: o.CopySourceTags, Metadata: o.Metadata, SourceContentMD5: o.SourceContentMD5, Tier: o.Tier, @@ -190,8 +198,6 @@ type CommitBlockListOptions struct { RequestID *string Tier *blob.AccessTier Timeout *int32 - TransactionalContentCRC64 []byte - TransactionalContentMD5 []byte HTTPHeaders *blob.HTTPHeaders CPKInfo *blob.CPKInfo CPKScopeInfo *blob.CPKScopeInfo @@ -199,6 +205,12 @@ type CommitBlockListOptions struct { LegalHold *bool ImmutabilityPolicyMode *blob.ImmutabilityPolicySetting ImmutabilityPolicyExpiryTime *time.Time + + // Deprecated: TransactionalContentCRC64 cannot be generated + TransactionalContentCRC64 []byte + + // Deprecated: TransactionalContentMD5 cannot be generated + TransactionalContentMD5 []byte } // --------------------------------------------------------------------------------------------------------------------- @@ -253,9 +265,10 @@ type uploadFromReaderOptions struct { TransactionalValidation blob.TransferValidationType - // Optional header, Specifies the transactional crc64 for the body, to be validated by the service. + // Deprecated: TransactionalContentCRC64 cannot be generated at block level TransactionalContentCRC64 uint64 - // Specify the transactional md5 for the body, to be validated by the service. + + // Deprecated: TransactionalContentMD5 cannot be generated at block level TransactionalContentMD5 []byte } diff --git a/sdk/storage/azblob/client_test.go b/sdk/storage/azblob/client_test.go index f04d5190a59a..579b4751eb92 100644 --- a/sdk/storage/azblob/client_test.go +++ b/sdk/storage/azblob/client_test.go @@ -8,8 +8,12 @@ package azblob_test import ( "context" + "crypto/md5" + "encoding/binary" "errors" "fmt" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror" + "hash/crc64" "io" "os" "sync/atomic" @@ -77,6 +81,60 @@ func generateFile(fileName string, fileSize int) []byte { return bigBuff } +func performUploadStreamToBlockBlobTestWithChecksums(t *testing.T, _require *require.Assertions, testName string, blobSize, bufferSize, maxBuffers int) { + client, err := testcommon.GetClient(t, testcommon.TestAccountDefault, nil) + _require.NoError(err) + + containerName := testcommon.GenerateContainerName(testName) + _, err = client.CreateContainer(context.Background(), containerName, nil) + _require.NoError(err) + defer func() { + _, err := client.DeleteContainer(context.Background(), containerName, nil) + _require.NoError(err) + }() + + // Set up test blob + blobName := testcommon.GenerateBlobName(testName) + + // Create some data to test the upload stream + blobContentReader, blobData := testcommon.GenerateData(blobSize) + crc64Value := crc64.Checksum(blobData, shared.CRC64Table) + crc := make([]byte, 8) + binary.LittleEndian.PutUint64(crc, crc64Value) + + // Perform UploadStream + _, err = client.UploadStream(ctx, containerName, blobName, blobContentReader, + &blockblob.UploadStreamOptions{BlockSize: int64(bufferSize), Concurrency: maxBuffers, TransactionalValidation: blob.TransferValidationTypeComputeCRC64()}) + _require.NoError(err) + + // TODO: UploadResponse does not return ContentCRC64 + // // Assert that upload was successful + // _require.Equal(uploadResp.ContentCRC64, crc) + + // UploadStream does not accept user generated checksum, should return UnsupportedChecksum + _, err = client.UploadStream(ctx, containerName, blobName, blobContentReader, + &blockblob.UploadStreamOptions{BlockSize: int64(bufferSize), Concurrency: maxBuffers, TransactionalValidation: blob.TransferValidationTypeCRC64(crc64Value)}) + _require.NotNil(err) + _require.Error(err, bloberror.UnsupportedChecksum) + + md5Value := md5.Sum(blobData) + contentMD5 := md5Value[:] + + _, err = client.UploadStream(ctx, containerName, blobName, blobContentReader, + &blockblob.UploadStreamOptions{BlockSize: int64(bufferSize), Concurrency: maxBuffers, TransactionalValidation: blob.TransferValidationTypeMD5(contentMD5)}) + _require.NotNil(err) + _require.Error(err, bloberror.UnsupportedChecksum) +} + +func (s *AZBlobUnrecordedTestsSuite) TestUploadStreamToBlockBlobInChunksChecksums() { + blobSize := 8 * 1024 + bufferSize := 1024 + maxBuffers := 3 + _require := require.New(s.T()) + testName := s.T().Name() + performUploadStreamToBlockBlobTestWithChecksums(s.T(), _require, testName, blobSize, bufferSize, maxBuffers) +} + func performUploadStreamToBlockBlobTest(t *testing.T, _require *require.Assertions, testName string, blobSize, bufferSize, maxBuffers int) { client, err := testcommon.GetClient(t, testcommon.TestAccountDefault, nil) _require.NoError(err) @@ -159,6 +217,102 @@ func (s *AZBlobUnrecordedTestsSuite) TestUploadStreamToBlockBlobEmpty() { performUploadStreamToBlockBlobTest(s.T(), _require, testName, blobSize, bufferSize, maxBuffers) } +func performUploadAndDownloadFileTestWithChecksums(t *testing.T, _require *require.Assertions, testName string, fileSize, blockSize, concurrency, downloadOffset, downloadCount int) { + // Set up file to upload + fileName := "BigFile.bin" + fileData := generateFile(fileName, fileSize) + + // Open the file to upload + file, err := os.Open(fileName) + _require.NoError(err) + defer func(file *os.File) { + _ = file.Close() + }(file) + defer func(name string) { + _ = os.Remove(name) + }(fileName) + + //body := bytes.NewReader(fileData) + crc64Value := crc64.Checksum(fileData, shared.CRC64Table) + crc := make([]byte, 8) + binary.LittleEndian.PutUint64(crc, crc64Value) + + client, err := testcommon.GetClient(t, testcommon.TestAccountDefault, nil) + _require.NoError(err) + + containerName := testcommon.GenerateContainerName(testName) + _, err = client.CreateContainer(context.Background(), containerName, nil) + _require.NoError(err) + defer func() { + _, err := client.DeleteContainer(context.Background(), containerName, nil) + _require.NoError(err) + }() + + // Set up test blob + blobName := testcommon.GenerateBlobName(testName) + + // Upload the file to a block blob + var errTransferred error + _, err = client.UploadFile(context.Background(), containerName, blobName, file, + &blockblob.UploadFileOptions{ + BlockSize: int64(blockSize), + Concurrency: uint16(concurrency), + TransactionalValidation: blob.TransferValidationTypeComputeCRC64(), + // If Progress is non-nil, this function is called periodically as bytes are uploaded. + Progress: func(bytesTransferred int64) { + if bytesTransferred <= 0 || bytesTransferred > int64(fileSize) { + errTransferred = fmt.Errorf("invalid bytes transferred %d", bytesTransferred) + } + }, + }) + assert.NoError(t, errTransferred) + _require.NoError(err) + + // UploadFile does not accept user generated checksum, should return UnsupportedChecksum + _, err = client.UploadFile(context.Background(), containerName, blobName, file, + &blockblob.UploadFileOptions{ + BlockSize: int64(blockSize), + Concurrency: uint16(concurrency), + TransactionalValidation: blob.TransferValidationTypeCRC64(crc64Value), + // If Progress is non-nil, this function is called periodically as bytes are uploaded. + Progress: func(bytesTransferred int64) { + if bytesTransferred <= 0 || bytesTransferred > int64(fileSize) { + errTransferred = fmt.Errorf("invalid bytes transferred %d", bytesTransferred) + } + }, + }) + _require.NotNil(err) + _require.Error(err, bloberror.UnsupportedChecksum) + + md5Value := md5.Sum(fileData) + contentMD5 := md5Value[:] + + // UploadFile does not accept user generated checksum, should return UnsupportedChecksum + _, err = client.UploadFile(context.Background(), containerName, blobName, file, + &blockblob.UploadFileOptions{ + BlockSize: int64(blockSize), + Concurrency: uint16(concurrency), + TransactionalValidation: blob.TransferValidationTypeMD5(contentMD5), + // If Progress is non-nil, this function is called periodically as bytes are uploaded. + Progress: func(bytesTransferred int64) { + if bytesTransferred <= 0 || bytesTransferred > int64(fileSize) { + errTransferred = fmt.Errorf("invalid bytes transferred %d", bytesTransferred) + } + }, + }) + _require.NotNil(err) + _require.Error(err, bloberror.UnsupportedChecksum) +} + +func (s *AZBlobUnrecordedTestsSuite) TestUploadFileInChunksChecksum() { + fileSize := 8 * 1024 + blockSize := 1024 + concurrency := 3 + _require := require.New(s.T()) + testName := s.T().Name() + performUploadAndDownloadFileTestWithChecksums(s.T(), _require, testName, fileSize, blockSize, concurrency, 0, 0) +} + func performUploadAndDownloadFileTest(t *testing.T, _require *require.Assertions, testName string, fileSize, blockSize, concurrency, downloadOffset, downloadCount int) { // Set up file to upload fileName := "BigFile.bin" diff --git a/sdk/storage/azblob/container/client.go b/sdk/storage/azblob/container/client.go index 2ac5a820ae1b..3058b5d49c00 100644 --- a/sdk/storage/azblob/container/client.go +++ b/sdk/storage/azblob/container/client.go @@ -44,10 +44,13 @@ type Client base.Client[generated.ContainerClient] func NewClient(containerURL 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.NewContainerClient(containerURL, pl, &cred)), nil + azClient, err := azcore.NewClient(shared.ContainerClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + return (*Client)(base.NewContainerClient(containerURL, azClient, &cred)), nil } // NewClientWithNoCredential creates an instance of Client with the specified values. @@ -56,9 +59,12 @@ func NewClient(containerURL string, cred azcore.TokenCredential, options *Client // - options - client options; pass nil to accept the default values func NewClientWithNoCredential(containerURL string, options *ClientOptions) (*Client, error) { conOptions := shared.GetClientOptions(options) - pl := runtime.NewPipeline(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions) - return (*Client)(base.NewContainerClient(containerURL, pl, nil)), nil + azClient, err := azcore.NewClient(shared.ContainerClient, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + return (*Client)(base.NewContainerClient(containerURL, azClient, nil)), nil } // NewClientWithSharedKeyCredential creates an instance of Client with the specified values. @@ -68,10 +74,13 @@ func NewClientWithNoCredential(containerURL string, options *ClientOptions) (*Cl func NewClientWithSharedKeyCredential(containerURL 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.NewContainerClient(containerURL, pl, cred)), nil + azClient, err := azcore.NewClient(shared.ContainerClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + return (*Client)(base.NewContainerClient(containerURL, azClient, cred)), nil } // NewClientFromConnectionString creates an instance of Client with the specified values. @@ -124,7 +133,7 @@ func (c *Client) URL() string { func (c *Client) NewBlobClient(blobName string) *blob.Client { blobName = url.PathEscape(blobName) blobURL := runtime.JoinPaths(c.URL(), blobName) - return (*blob.Client)(base.NewBlobClient(blobURL, c.generated().Pipeline(), c.credential())) + return (*blob.Client)(base.NewBlobClient(blobURL, c.generated().InternalClient().WithClientName(shared.BlobClient), c.credential())) } // NewAppendBlobClient creates a new appendblob.Client object by concatenating blobName to the end of @@ -133,7 +142,7 @@ func (c *Client) NewBlobClient(blobName string) *blob.Client { func (c *Client) NewAppendBlobClient(blobName string) *appendblob.Client { blobName = url.PathEscape(blobName) blobURL := runtime.JoinPaths(c.URL(), blobName) - return (*appendblob.Client)(base.NewAppendBlobClient(blobURL, c.generated().Pipeline(), c.sharedKey())) + return (*appendblob.Client)(base.NewAppendBlobClient(blobURL, c.generated().InternalClient().WithClientName(shared.AppendBlobClient), c.sharedKey())) } // NewBlockBlobClient creates a new blockblob.Client object by concatenating blobName to the end of @@ -142,7 +151,7 @@ func (c *Client) NewAppendBlobClient(blobName string) *appendblob.Client { func (c *Client) NewBlockBlobClient(blobName string) *blockblob.Client { blobName = url.PathEscape(blobName) blobURL := runtime.JoinPaths(c.URL(), blobName) - return (*blockblob.Client)(base.NewBlockBlobClient(blobURL, c.generated().Pipeline(), c.sharedKey())) + return (*blockblob.Client)(base.NewBlockBlobClient(blobURL, c.generated().InternalClient().WithClientName(shared.BlockBlobClient), c.sharedKey())) } // NewPageBlobClient creates a new pageblob.Client object by concatenating blobName to the end of @@ -151,7 +160,7 @@ func (c *Client) NewBlockBlobClient(blobName string) *blockblob.Client { func (c *Client) NewPageBlobClient(blobName string) *pageblob.Client { blobName = url.PathEscape(blobName) blobURL := runtime.JoinPaths(c.URL(), blobName) - return (*pageblob.Client)(base.NewPageBlobClient(blobURL, c.generated().Pipeline(), c.sharedKey())) + return (*pageblob.Client)(base.NewPageBlobClient(blobURL, c.generated().InternalClient().WithClientName(shared.PageBlobClient), c.sharedKey())) } // Create creates a new container within a storage account. If a container with the same name already exists, the operation fails. @@ -272,7 +281,7 @@ func (c *Client) NewListBlobsFlatPager(o *ListBlobsFlatOptions) *runtime.Pager[L if err != nil { return ListBlobsFlatResponse{}, err } - resp, err := c.generated().Pipeline().Do(req) + resp, err := c.generated().InternalClient().Pipeline().Do(req) if err != nil { return ListBlobsFlatResponse{}, err } @@ -308,7 +317,7 @@ func (c *Client) NewListBlobsHierarchyPager(delimiter string, o *ListBlobsHierar if err != nil { return ListBlobsHierarchyResponse{}, err } - resp, err := c.generated().Pipeline().Do(req) + resp, err := c.generated().InternalClient().Pipeline().Do(req) if err != nil { return ListBlobsHierarchyResponse{}, err } @@ -412,3 +421,12 @@ func (c *Client) SubmitBatch(ctx context.Context, bb *BatchBuilder, options *Sub Version: resp.Version, }, nil } + +// FilterBlobs operation finds all blobs in the container whose tags match a given search expression. +// https://docs.microsoft.com/en-us/rest/api/storageservices/find-blobs-by-tags-container +// eg. "dog='germanshepherd' and penguin='emperorpenguin'" +func (c *Client) FilterBlobs(ctx context.Context, where string, o *FilterBlobsOptions) (FilterBlobsResponse, error) { + containerClientFilterBlobsOptions := o.format() + resp, err := c.generated().FilterBlobs(ctx, where, containerClientFilterBlobsOptions) + return resp, err +} diff --git a/sdk/storage/azblob/container/client_test.go b/sdk/storage/azblob/container/client_test.go index 566a7a38fe64..7d4bf53213ee 100644 --- a/sdk/storage/azblob/container/client_test.go +++ b/sdk/storage/azblob/container/client_test.go @@ -9,6 +9,7 @@ package container_test import ( "context" "fmt" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/appendblob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas" "net/url" "os" @@ -748,6 +749,102 @@ func (s *ContainerRecordedTestsSuite) TestContainerListBlobsInvalidDelimiter() { } } +func (s *ContainerRecordedTestsSuite) TestContainerListBlobsDelimiterPrefixVersion() { + _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) + + blobNames := []string{"a/1", "a/2", "b/1", "blob"} + blobMap := testcommon.BlobListToMap(blobNames) + for _, name := range blobNames { + testcommon.CreateNewBlockBlob(context.Background(), _require, name, containerClient) + } + + opts := container.ListBlobsHierarchyOptions{ + Include: container.ListBlobsInclude{Versions: true}, + Marker: nil, + MaxResults: nil, + Prefix: to.Ptr("a/"), + } + + pager := containerClient.NewListBlobsHierarchyPager("/", &opts) + for pager.More() { + resp, err := pager.NextPage(context.Background()) + _require.NoError(err) + + _require.Equal(len(resp.Segment.BlobItems), 2) + for _, blobs := range resp.Segment.BlobItems { + _require.Equal(blobMap[*(blobs.Name)], true) + _require.NotNil(blobs.VersionID) // checks if blob has version id + } + if err != nil { + break + } + } +} + +func (s *ContainerRecordedTestsSuite) TestContainerListFlatBlobsInvalidBlobName() { + _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) + + blobName := "dir1/dir2/file\uFFFF.blob" + _ = testcommon.CreateNewBlockBlob(context.Background(), _require, blobName, containerClient) + + pager := containerClient.NewListBlobsFlatPager(nil) + for pager.More() { + resp, err := pager.NextPage(context.Background()) + _require.NoError(err) + + _require.Equal(len(resp.Segment.BlobItems), 1) + _require.Equal(*resp.Segment.BlobItems[0].Name, blobName) + } +} + +func (s *ContainerRecordedTestsSuite) TestContainerListHierarchyBlobsInvalidBlobName() { + _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) + + blobName := "dir1/dir2/file\uFFFF.blob" + _ = testcommon.CreateNewBlockBlob(context.Background(), _require, blobName, containerClient) + + pager := containerClient.NewListBlobsHierarchyPager(".b", nil) + for pager.More() { + resp, err := pager.NextPage(context.Background()) + _require.NoError(err) + + _require.Equal(len(resp.Segment.BlobItems), 0) + _require.Equal(len(resp.Segment.BlobPrefixes), 1) + _require.Equal(*resp.Segment.BlobPrefixes[0].Name, "dir1/dir2/file\uFFFF.b") + } + + // empty delimiter + pager1 := containerClient.NewListBlobsHierarchyPager("", nil) + for pager1.More() { + resp, err := pager1.NextPage(context.Background()) + _require.NoError(err) + + _require.Equal(len(resp.Segment.BlobItems), 1) + _require.Equal(*resp.Segment.BlobItems[0].Name, blobName) + } +} + func (s *ContainerRecordedTestsSuite) TestContainerListBlobsWithSnapshots() { _require := require.New(s.T()) testName := s.T().Name() @@ -1344,6 +1441,60 @@ func (s *ContainerRecordedTestsSuite) TestBlobListWrapper() { _require.EqualValues(files, found) } +func (s *ContainerRecordedTestsSuite) TestBlobListColdTier() { + _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.GetContainerClient(containerName, svcClient) + + _, err = containerClient.Create(context.Background(), nil) + _require.NoError(err) + defer testcommon.DeleteContainer(context.Background(), _require, containerClient) + + for _, tier := range []blob.AccessTier{blob.AccessTierCool, blob.AccessTierHot, blob.AccessTierCold, blob.AccessTierArchive} { + files := []string{"a123", "b234", "c345"} + testcommon.CreateNewBlobsListTier(context.Background(), _require, files, containerClient, &tier) + + // List blobs flat + found := make([]string, 0) + pager := containerClient.NewListBlobsFlatPager(nil) + for pager.More() { + resp, err := pager.NextPage(context.Background()) + _require.NoError(err) + + for _, blob := range resp.Segment.BlobItems { + _require.Equal(blob.Properties.AccessTier, &tier) + found = append(found, *blob.Name) + } + } + + sort.Strings(files) + sort.Strings(found) + _require.EqualValues(files, found) + + // Try listing blobs with hierarchical listing + found = make([]string, 0) + pg := containerClient.NewListBlobsHierarchyPager("/", nil) + for pg.More() { + resp, err := pg.NextPage(context.Background()) + _require.NoError(err) + + for _, blob := range resp.Segment.BlobItems { + _require.Equal(blob.Properties.AccessTier, &tier) + found = append(found, *blob.Name) + } + } + + sort.Strings(files) + sort.Strings(found) + _require.EqualValues(files, found) + + } +} + func (s *ContainerRecordedTestsSuite) TestBlobListWrapperListingError() { _require := require.New(s.T()) testName := s.T().Name() @@ -1567,10 +1718,10 @@ func (s *ContainerUnrecordedTestsSuite) TestContainerSetPermissionsPublicAccessN _, err = containerClient.SetAccessPolicy(context.Background(), nil) _require.Nil(err) - bsu2, err := service.NewClientWithNoCredential(svcClient.URL(), nil) + svcClient2, err := testcommon.GetServiceClientNoCredential(s.T(), svcClient.URL(), nil) _require.Nil(err) - containerClient2 := bsu2.NewContainerClient(containerName) + containerClient2 := svcClient2.NewContainerClient(containerName) // Get permissions via the original container URL so the request succeeds resp, err := containerClient.GetAccessPolicy(context.Background(), nil) @@ -1581,14 +1732,15 @@ func (s *ContainerUnrecordedTestsSuite) TestContainerSetPermissionsPublicAccessN pager := containerClient2.NewListBlobsFlatPager(nil) for pager.More() { _, err = pager.NextPage(context.Background()) - _require.NotNil(err) - testcommon.ValidateBlobErrorCode(_require, err, bloberror.NoAuthenticationInformation) + _require.Error(err) + // testcommon.ValidateBlobErrorCode(_require, err, bloberror.NoAuthenticationInformation) break } blobClient2 := containerClient2.NewBlockBlobClient(blobName) _, err = blobClient2.DownloadStream(context.Background(), nil) - testcommon.ValidateBlobErrorCode(_require, err, bloberror.NoAuthenticationInformation) + _require.Error(err) + // testcommon.ValidateBlobErrorCode(_require, err, bloberror.NoAuthenticationInformation) } func (s *ContainerRecordedTestsSuite) TestContainerSetPermissionsPublicAccessTypeBlob() { @@ -2246,6 +2398,149 @@ func (s *ContainerUnrecordedTestsSuite) TestSASContainerClient() { _require.Nil(err) } +func (s *ContainerUnrecordedTestsSuite) TestFilterBlobsByTags() { + _require := require.New(s.T()) + testName := s.T().Name() + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + containerClient := testcommon.CreateNewContainer(context.Background(), _require, testcommon.GenerateContainerName(testName), svcClient) + defer testcommon.DeleteContainer(context.Background(), _require, containerClient) + + // Adding SAS and options + permissions := sas.ContainerPermissions{ + Read: true, + Add: true, + Write: true, + Create: true, + Delete: true, + Tag: true, + FilterByTags: true, + } + expiry := time.Now().Add(time.Hour) + + // ContainerSASURL is created with GetSASURL + sasUrl, err := containerClient.GetSASURL(permissions, expiry, nil) + _require.Nil(err) + + // Create container client with sasUrl + containerSasClient, err := container.NewClientWithNoCredential(sasUrl, nil) + _require.Nil(err) + + abClient := containerSasClient.NewAppendBlobClient(testcommon.GenerateBlobName(testName)) + + createAppendBlobOptions := appendblob.CreateOptions{ + Tags: testcommon.BasicBlobTagsMap, + } + createResp, err := abClient.Create(context.Background(), &createAppendBlobOptions) + _require.Nil(err) + _require.NotNil(createResp.VersionID) + time.Sleep(10 * time.Second) + + // Use container client to filter blobs by tag + where := "\"azure\"='blob'" + opts := container.FilterBlobsOptions{MaxResults: to.Ptr(int32(10)), Marker: to.Ptr("")} + lResp, err := containerSasClient.FilterBlobs(context.Background(), where, &opts) + _require.Nil(err) + _require.Len(lResp.FilterBlobSegment.Blobs[0].Tags.BlobTagSet, 1) + _require.Equal(*lResp.FilterBlobSegment.Blobs[0].Tags.BlobTagSet[0].Key, "azure") + _require.Equal(*lResp.FilterBlobSegment.Blobs[0].Tags.BlobTagSet[0].Value, "blob") +} + +func (s *ContainerUnrecordedTestsSuite) TestFilterBlobsByTagsNegative() { + _require := require.New(s.T()) + testName := s.T().Name() + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + containerClient := testcommon.CreateNewContainer(context.Background(), _require, testcommon.GenerateContainerName(testName), svcClient) + defer testcommon.DeleteContainer(context.Background(), _require, containerClient) + + // Adding SAS and options + permissions := sas.ContainerPermissions{ + Read: true, + Add: true, + Write: true, + Create: true, + Delete: true, + Tag: true, + } + expiry := time.Now().Add(time.Hour) + + // ContainerSASURL is created with GetSASURL + sasUrl, err := containerClient.GetSASURL(permissions, expiry, nil) + _require.Nil(err) + + // Create container client with sasUrl + containerSasClient, err := container.NewClientWithNoCredential(sasUrl, nil) + _require.Nil(err) + + abClient := containerSasClient.NewAppendBlobClient(testcommon.GenerateBlobName(testName)) + + createAppendBlobOptions := appendblob.CreateOptions{ + Tags: testcommon.BasicBlobTagsMap, + } + createResp, err := abClient.Create(context.Background(), &createAppendBlobOptions) + _require.Nil(err) + _require.NotNil(createResp.VersionID) + time.Sleep(10 * time.Second) + + // Use container client to filter blobs by tag + where := "\"azure\"='blob'" + _, err = containerSasClient.FilterBlobs(context.Background(), where, nil) + _require.Error(err) +} + +func (s *ContainerUnrecordedTestsSuite) TestFilterBlobsOnContainer() { + _require := require.New(s.T()) + testName := s.T().Name() + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) + _require.NoError(err) + + containerClient := testcommon.CreateNewContainer(context.Background(), _require, testcommon.GenerateContainerName(testName)+"1", svcClient) + defer testcommon.DeleteContainer(context.Background(), _require, containerClient) + + blobTagsMap1 := map[string]string{ + "tag2": "tagsecond", + "tag3": "tagthird", + } + blobTagsMap2 := map[string]string{ + "tag1": "firsttag", + "tag2": "secondtag", + "tag3": "thirdtag", + } + + blobName1 := testcommon.GenerateBlobName(testName) + "1" + blobClient1 := testcommon.CreateNewBlockBlob(context.Background(), _require, blobName1, containerClient) + _, err = blobClient1.SetTags(context.Background(), blobTagsMap1, nil) + _require.Nil(err) + + blobName2 := testcommon.GenerateBlobName(testName) + "2" + blobClient2 := testcommon.CreateNewBlockBlob(context.Background(), _require, blobName2, containerClient) + _, err = blobClient2.SetTags(context.Background(), blobTagsMap2, nil) + _require.Nil(err) + time.Sleep(10 * time.Second) + + blobTagsResp, err := blobClient2.GetTags(context.Background(), nil) + _require.Nil(err) + blobTagsSet := blobTagsResp.BlobTagSet + _require.NotNil(blobTagsSet) + + // Test invalid tag + where := "\"tag4\"='fourthtag'" + lResp, err := containerClient.FilterBlobs(context.Background(), where, nil) + _require.Nil(err) + _require.Equal(len(lResp.Blobs), 0) + + // Test multiple valid tags + where = "\"tag1\"='firsttag'AND\"tag2\"='secondtag'" + lResp, err = containerClient.FilterBlobs(context.Background(), where, nil) + _require.Nil(err) + _require.Len(lResp.FilterBlobSegment.Blobs[0].Tags.BlobTagSet, 2) + _require.Equal(lResp.FilterBlobSegment.Blobs[0].Tags.BlobTagSet[0], blobTagsSet[0]) + _require.Equal(lResp.FilterBlobSegment.Blobs[0].Tags.BlobTagSet[1], blobTagsSet[1]) +} + func (s *ContainerUnrecordedTestsSuite) TestSASContainerClientTags() { _require := require.New(s.T()) testName := s.T().Name() diff --git a/sdk/storage/azblob/container/models.go b/sdk/storage/azblob/container/models.go index f1724861ef9e..61d936ab73db 100644 --- a/sdk/storage/azblob/container/models.go +++ b/sdk/storage/azblob/container/models.go @@ -397,3 +397,31 @@ type SubmitBatchOptions struct { func (o *SubmitBatchOptions) format() *generated.ContainerClientSubmitBatchOptions { return nil } + +// --------------------------------------------------------------------------------------------------------------------- + +// FilterBlobsOptions provides set of options for Client.FilterBlobs. +type FilterBlobsOptions struct { + // A string value that identifies the portion of the list of containers to be returned with the next listing operation. The + // operation returns the NextMarker value within the response body if the listing + // operation did not return all containers remaining to be listed with the current page. The NextMarker value can be used + // as the value for the marker parameter in a subsequent call to request the next + // page of list items. The marker value is opaque to the client. + Marker *string + // Specifies the maximum number of containers to return. If the request does not specify maxresults, or specifies a value + // greater than 5000, the server will return up to 5000 items. Note that if the + // listing operation crosses a partition boundary, then the service will return a continuation token for retrieving the remainder + // of the results. For this reason, it is possible that the service will + // return fewer results than specified by maxresults, or than the default of 5000. + MaxResults *int32 +} + +func (o *FilterBlobsOptions) format() *generated.ContainerClientFilterBlobsOptions { + if o == nil { + return nil + } + return &generated.ContainerClientFilterBlobsOptions{ + Marker: o.Marker, + Maxresults: o.MaxResults, + } +} diff --git a/sdk/storage/azblob/container/responses.go b/sdk/storage/azblob/container/responses.go index 4d1e406ea22b..9aaefe277fb9 100644 --- a/sdk/storage/azblob/container/responses.go +++ b/sdk/storage/azblob/container/responses.go @@ -64,3 +64,6 @@ type SubmitBatchResponse struct { // BatchResponseItem contains the response for the individual sub-requests. type BatchResponseItem = exported.BatchResponseItem + +// FilterBlobsResponse contains the response from method Client.FilterBlobs. +type FilterBlobsResponse = generated.ContainerClientFilterBlobsResponse diff --git a/sdk/storage/azblob/go.mod b/sdk/storage/azblob/go.mod index 721c7fd1358c..79e976b21b9b 100644 --- a/sdk/storage/azblob/go.mod +++ b/sdk/storage/azblob/go.mod @@ -3,7 +3,7 @@ module github.com/Azure/azure-sdk-for-go/sdk/storage/azblob go 1.18 require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0 diff --git a/sdk/storage/azblob/go.sum b/sdk/storage/azblob/go.sum index 13942c628a39..c5df56945436 100644 --- a/sdk/storage/azblob/go.sum +++ b/sdk/storage/azblob/go.sum @@ -1,5 +1,5 @@ -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 h1:8kDqDngH+DmVBiCtIjCFTGa7MBnsIOkF9IccInFEbjk= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 h1:8q4SaHjFsClSvuVne0ID/5Ka8u3fcIHyqkLjcFpNRHQ= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= diff --git a/sdk/storage/azblob/internal/base/clients.go b/sdk/storage/azblob/internal/base/clients.go index 6c3cc5c93803..0bdbaefaf228 100644 --- a/sdk/storage/azblob/internal/base/clients.go +++ b/sdk/storage/azblob/internal/base/clients.go @@ -8,7 +8,6 @@ package base import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/generated" ) @@ -44,23 +43,23 @@ func NewClient[T any](inner *T) *Client[T] { return &Client[T]{inner: inner} } -func NewServiceClient(containerURL string, pipeline runtime.Pipeline, credential any) *Client[generated.ServiceClient] { +func NewServiceClient(containerURL string, azClient *azcore.Client, credential any) *Client[generated.ServiceClient] { return &Client[generated.ServiceClient]{ - inner: generated.NewServiceClient(containerURL, pipeline), + inner: generated.NewServiceClient(containerURL, azClient), credential: credential, } } -func NewContainerClient(containerURL string, pipeline runtime.Pipeline, credential any) *Client[generated.ContainerClient] { +func NewContainerClient(containerURL string, azClient *azcore.Client, credential any) *Client[generated.ContainerClient] { return &Client[generated.ContainerClient]{ - inner: generated.NewContainerClient(containerURL, pipeline), + inner: generated.NewContainerClient(containerURL, azClient), credential: credential, } } -func NewBlobClient(blobURL string, pipeline runtime.Pipeline, credential any) *Client[generated.BlobClient] { +func NewBlobClient(blobURL string, azClient *azcore.Client, credential any) *Client[generated.BlobClient] { return &Client[generated.BlobClient]{ - inner: generated.NewBlobClient(blobURL, pipeline), + inner: generated.NewBlobClient(blobURL, azClient), credential: credential, } } @@ -75,26 +74,26 @@ func InnerClients[T, U any](client *CompositeClient[T, U]) (*Client[T], *U) { return &Client[T]{inner: client.innerT}, client.innerU } -func NewAppendBlobClient(blobURL string, pipeline runtime.Pipeline, sharedKey *exported.SharedKeyCredential) *CompositeClient[generated.BlobClient, generated.AppendBlobClient] { +func NewAppendBlobClient(blobURL string, azClient *azcore.Client, sharedKey *exported.SharedKeyCredential) *CompositeClient[generated.BlobClient, generated.AppendBlobClient] { return &CompositeClient[generated.BlobClient, generated.AppendBlobClient]{ - innerT: generated.NewBlobClient(blobURL, pipeline), - innerU: generated.NewAppendBlobClient(blobURL, pipeline), + innerT: generated.NewBlobClient(blobURL, azClient), + innerU: generated.NewAppendBlobClient(blobURL, azClient), sharedKey: sharedKey, } } -func NewBlockBlobClient(blobURL string, pipeline runtime.Pipeline, sharedKey *exported.SharedKeyCredential) *CompositeClient[generated.BlobClient, generated.BlockBlobClient] { +func NewBlockBlobClient(blobURL string, azClient *azcore.Client, sharedKey *exported.SharedKeyCredential) *CompositeClient[generated.BlobClient, generated.BlockBlobClient] { return &CompositeClient[generated.BlobClient, generated.BlockBlobClient]{ - innerT: generated.NewBlobClient(blobURL, pipeline), - innerU: generated.NewBlockBlobClient(blobURL, pipeline), + innerT: generated.NewBlobClient(blobURL, azClient), + innerU: generated.NewBlockBlobClient(blobURL, azClient), sharedKey: sharedKey, } } -func NewPageBlobClient(blobURL string, pipeline runtime.Pipeline, sharedKey *exported.SharedKeyCredential) *CompositeClient[generated.BlobClient, generated.PageBlobClient] { +func NewPageBlobClient(blobURL string, azClient *azcore.Client, sharedKey *exported.SharedKeyCredential) *CompositeClient[generated.BlobClient, generated.PageBlobClient] { return &CompositeClient[generated.BlobClient, generated.PageBlobClient]{ - innerT: generated.NewBlobClient(blobURL, pipeline), - innerU: generated.NewPageBlobClient(blobURL, pipeline), + innerT: generated.NewBlobClient(blobURL, azClient), + innerU: generated.NewPageBlobClient(blobURL, azClient), sharedKey: sharedKey, } } diff --git a/sdk/storage/azblob/internal/generated/appendblob_client.go b/sdk/storage/azblob/internal/generated/appendblob_client.go index 3b6184fea67c..288df7edda47 100644 --- a/sdk/storage/azblob/internal/generated/appendblob_client.go +++ b/sdk/storage/azblob/internal/generated/appendblob_client.go @@ -8,12 +8,25 @@ package generated -import "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" +import ( + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) func (client *AppendBlobClient) Endpoint() string { return client.endpoint } -func (client *AppendBlobClient) Pipeline() runtime.Pipeline { - return client.pl +func (client *AppendBlobClient) InternalClient() *azcore.Client { + return client.internal +} + +// NewAppendBlobClient creates a new instance of AppendBlobClient with the specified values. +// - endpoint - The URL of the service account, container, or blob that is the target of the desired operation. +// - azClient - azcore.Client is a basic HTTP client. It consists of a pipeline and tracing provider. +func NewAppendBlobClient(endpoint string, azClient *azcore.Client) *AppendBlobClient { + client := &AppendBlobClient{ + internal: azClient, + endpoint: endpoint, + } + return client } diff --git a/sdk/storage/azblob/internal/generated/autorest.md b/sdk/storage/azblob/internal/generated/autorest.md index 3044a608a21c..28485e4b8bfa 100644 --- a/sdk/storage/azblob/internal/generated/autorest.md +++ b/sdk/storage/azblob/internal/generated/autorest.md @@ -7,7 +7,7 @@ go: true clear-output-folder: false version: "^3.0.0" license-header: MICROSOFT_MIT_NO_VERSION -input-file: "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/e515b6251fdc21015282d2e84b85beec7c091763/specification/storage/data-plane/Microsoft.BlobStorage/preview/2020-10-02/blob.json" +input-file: "https://raw.githubusercontent.com/Azure/azure-rest-api-specs/080b332b7572514a2e100dd2fa1fb86cb8edcb08/specification/storage/data-plane/Microsoft.BlobStorage/preview/2021-12-02/blob.json" credential-scope: "https://storage.azure.com/.default" output-folder: ../generated file-prefix: "zz_" @@ -19,7 +19,26 @@ modelerfour: seal-single-value-enum-by-default: true lenient-model-deduplication: true export-clients: true -use: "@autorest/go@4.0.0-preview.45" +use: "@autorest/go@4.0.0-preview.49" +``` + +### Undo breaking change with BlobName +``` yaml +directive: +- from: zz_models.go + where: $ + transform: >- + return $. + replace(/Name\s+\*BlobName/g, `Name *string`); +``` + +### Removing UnmarshalXML for BlobItems to create customer UnmarshalXML function +```yaml +directive: +- from: swagger-document + where: $.definitions + transform: > + $.BlobItemInternal["x-ms-go-omit-serde-methods"] = true; ``` ### Remove pager methods and export various generated methods in container client diff --git a/sdk/storage/azblob/internal/generated/blob_client.go b/sdk/storage/azblob/internal/generated/blob_client.go index 478962de1552..343073b2e660 100644 --- a/sdk/storage/azblob/internal/generated/blob_client.go +++ b/sdk/storage/azblob/internal/generated/blob_client.go @@ -8,8 +8,8 @@ package generated import ( "context" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "time" ) @@ -20,8 +20,8 @@ func (client *BlobClient) Endpoint() string { return client.endpoint } -func (client *BlobClient) Pipeline() runtime.Pipeline { - return client.pl +func (client *BlobClient) InternalClient() *azcore.Client { + return client.internal } func (client *BlobClient) DeleteCreateRequest(ctx context.Context, options *BlobClientDeleteOptions, leaseAccessConditions *LeaseAccessConditions, modifiedAccessConditions *ModifiedAccessConditions) (*policy.Request, error) { @@ -31,3 +31,14 @@ func (client *BlobClient) DeleteCreateRequest(ctx context.Context, options *Blob func (client *BlobClient) SetTierCreateRequest(ctx context.Context, tier AccessTier, options *BlobClientSetTierOptions, leaseAccessConditions *LeaseAccessConditions, modifiedAccessConditions *ModifiedAccessConditions) (*policy.Request, error) { return client.setTierCreateRequest(ctx, tier, options, leaseAccessConditions, modifiedAccessConditions) } + +// NewBlobClient creates a new instance of BlobClient with the specified values. +// - endpoint - The URL of the service account, container, or blob that is the target of the desired operation. +// - azClient - azcore.Client is a basic HTTP client. It consists of a pipeline and tracing provider. +func NewBlobClient(endpoint string, azClient *azcore.Client) *BlobClient { + client := &BlobClient{ + internal: azClient, + endpoint: endpoint, + } + return client +} diff --git a/sdk/storage/azblob/internal/generated/block_blob_client.go b/sdk/storage/azblob/internal/generated/block_blob_client.go index a43e327ec44d..873d9a419fb4 100644 --- a/sdk/storage/azblob/internal/generated/block_blob_client.go +++ b/sdk/storage/azblob/internal/generated/block_blob_client.go @@ -8,12 +8,25 @@ package generated -import "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" +import ( + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) func (client *BlockBlobClient) Endpoint() string { return client.endpoint } -func (client *BlockBlobClient) Pipeline() runtime.Pipeline { - return client.pl +func (client *BlockBlobClient) Internal() *azcore.Client { + return client.internal +} + +// NewBlockBlobClient creates a new instance of BlockBlobClient with the specified values. +// - endpoint - The URL of the service account, container, or blob that is the target of the desired operation. +// - azClient - azcore.Client is a basic HTTP client. It consists of a pipeline and tracing provider. +func NewBlockBlobClient(endpoint string, azClient *azcore.Client) *BlockBlobClient { + client := &BlockBlobClient{ + internal: azClient, + endpoint: endpoint, + } + return client } diff --git a/sdk/storage/azblob/internal/generated/container_client.go b/sdk/storage/azblob/internal/generated/container_client.go index bbbf828a07af..d43b2c782590 100644 --- a/sdk/storage/azblob/internal/generated/container_client.go +++ b/sdk/storage/azblob/internal/generated/container_client.go @@ -6,12 +6,25 @@ package generated -import "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" +import ( + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) func (client *ContainerClient) Endpoint() string { return client.endpoint } -func (client *ContainerClient) Pipeline() runtime.Pipeline { - return client.pl +func (client *ContainerClient) InternalClient() *azcore.Client { + return client.internal +} + +// NewContainerClient creates a new instance of ContainerClient with the specified values. +// - endpoint - The URL of the service account, container, or blob that is the target of the desired operation. +// - pl - the pipeline used for sending requests and handling responses. +func NewContainerClient(endpoint string, azClient *azcore.Client) *ContainerClient { + client := &ContainerClient{ + internal: azClient, + endpoint: endpoint, + } + return client } diff --git a/sdk/storage/azblob/internal/generated/models.go b/sdk/storage/azblob/internal/generated/models.go index 759d92630f56..aaef9f53ba67 100644 --- a/sdk/storage/azblob/internal/generated/models.go +++ b/sdk/storage/azblob/internal/generated/models.go @@ -6,6 +6,12 @@ package generated +import ( + "encoding/xml" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" + "net/url" +) + type TransactionalContentSetter interface { SetCRC64([]byte) SetMD5([]byte) @@ -35,6 +41,14 @@ func (p *PageBlobClientUploadPagesOptions) SetMD5(v []byte) { p.TransactionalContentMD5 = v } +func (b *BlockBlobClientUploadOptions) SetCRC64(v []byte) { + b.TransactionalContentCRC64 = v +} + +func (b *BlockBlobClientUploadOptions) SetMD5(v []byte) { + b.TransactionalContentMD5 = v +} + type SourceContentSetter interface { SetSourceContentCRC64(v []byte) SetSourceContentMD5(v []byte) @@ -63,3 +77,65 @@ func (p *PageBlobClientUploadPagesFromURLOptions) SetSourceContentCRC64(v []byte func (p *PageBlobClientUploadPagesFromURLOptions) SetSourceContentMD5(v []byte) { p.SourceContentMD5 = v } + +// Custom UnmarshalXML functions for types that need special handling. + +// UnmarshalXML implements the xml.Unmarshaller interface for type BlobPrefix. +func (b *BlobPrefix) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error { + type alias BlobPrefix + aux := &struct { + *alias + BlobName *BlobName `xml:"Name"` + }{ + alias: (*alias)(b), + } + if err := dec.DecodeElement(aux, &start); err != nil { + return err + } + if aux.BlobName != nil { + if aux.BlobName.Encoded != nil && *aux.BlobName.Encoded { + name, err := url.QueryUnescape(*aux.BlobName.Content) + + // name, err := base64.StdEncoding.DecodeString(*aux.BlobName.Content) + if err != nil { + return err + } + b.Name = to.Ptr(string(name)) + } else { + b.Name = aux.BlobName.Content + } + } + return nil +} + +// UnmarshalXML implements the xml.Unmarshaller interface for type BlobItem. +func (b *BlobItem) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error { + type alias BlobItem + aux := &struct { + *alias + BlobName *BlobName `xml:"Name"` + Metadata additionalProperties `xml:"Metadata"` + OrMetadata additionalProperties `xml:"OrMetadata"` + }{ + alias: (*alias)(b), + } + if err := dec.DecodeElement(aux, &start); err != nil { + return err + } + b.Metadata = (map[string]*string)(aux.Metadata) + b.OrMetadata = (map[string]*string)(aux.OrMetadata) + if aux.BlobName != nil { + if aux.BlobName.Encoded != nil && *aux.BlobName.Encoded { + name, err := url.QueryUnescape(*aux.BlobName.Content) + + // name, err := base64.StdEncoding.DecodeString(*aux.BlobName.Content) + if err != nil { + return err + } + b.Name = to.Ptr(string(name)) + } else { + b.Name = aux.BlobName.Content + } + } + return nil +} diff --git a/sdk/storage/azblob/internal/generated/pageblob_client.go b/sdk/storage/azblob/internal/generated/pageblob_client.go index 8a212cc3d4e2..a7c76208aa25 100644 --- a/sdk/storage/azblob/internal/generated/pageblob_client.go +++ b/sdk/storage/azblob/internal/generated/pageblob_client.go @@ -6,12 +6,25 @@ package generated -import "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" +import ( + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) func (client *PageBlobClient) Endpoint() string { return client.endpoint } -func (client *PageBlobClient) Pipeline() runtime.Pipeline { - return client.pl +func (client *PageBlobClient) InternalClient() *azcore.Client { + return client.internal +} + +// NewPageBlobClient creates a new instance of PageBlobClient with the specified values. +// - endpoint - The URL of the service account, container, or blob that is the target of the desired operation. +// - azClient - azcore.Client is a basic HTTP client. It consists of a pipeline and tracing provider. +func NewPageBlobClient(endpoint string, azClient *azcore.Client) *PageBlobClient { + client := &PageBlobClient{ + internal: azClient, + endpoint: endpoint, + } + return client } diff --git a/sdk/storage/azblob/internal/generated/service_client.go b/sdk/storage/azblob/internal/generated/service_client.go index 1f449b955e82..32c15a2b097c 100644 --- a/sdk/storage/azblob/internal/generated/service_client.go +++ b/sdk/storage/azblob/internal/generated/service_client.go @@ -6,12 +6,25 @@ package generated -import "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" +import ( + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) func (client *ServiceClient) Endpoint() string { return client.endpoint } -func (client *ServiceClient) Pipeline() runtime.Pipeline { - return client.pl +func (client *ServiceClient) InternalClient() *azcore.Client { + return client.internal +} + +// NewServiceClient creates a new instance of ServiceClient with the specified values. +// - endpoint - The URL of the service account, container, or blob that is the target of the desired operation. +// - azClient - azcore.Client is a basic HTTP client. It consists of a pipeline and tracing provider. +func NewServiceClient(endpoint string, azClient *azcore.Client) *ServiceClient { + client := &ServiceClient{ + internal: azClient, + endpoint: endpoint, + } + return client } diff --git a/sdk/storage/azblob/internal/generated/zz_appendblob_client.go b/sdk/storage/azblob/internal/generated/zz_appendblob_client.go index d0ddb9064d85..ea666ea50284 100644 --- a/sdk/storage/azblob/internal/generated/zz_appendblob_client.go +++ b/sdk/storage/azblob/internal/generated/zz_appendblob_client.go @@ -22,21 +22,10 @@ import ( ) // AppendBlobClient contains the methods for the AppendBlob group. -// Don't use this type directly, use NewAppendBlobClient() instead. +// Don't use this type directly, use a constructor function instead. type AppendBlobClient struct { + internal *azcore.Client endpoint string - pl runtime.Pipeline -} - -// NewAppendBlobClient creates a new instance of AppendBlobClient with the specified values. -// - endpoint - The URL of the service account, container, or blob that is the target of the desired operation. -// - pl - the pipeline used for sending requests and handling responses. -func NewAppendBlobClient(endpoint string, pl runtime.Pipeline) *AppendBlobClient { - client := &AppendBlobClient{ - endpoint: endpoint, - pl: pl, - } - return client } // AppendBlock - The Append Block operation commits a new block of data to the end of an existing append blob. The Append @@ -44,7 +33,7 @@ func NewAppendBlobClient(endpoint string, pl runtime.Pipeline) *AppendBlobClient // AppendBlob. Append Block is supported only on version 2015-02-21 version or later. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - contentLength - The length of the request. // - body - Initial data // - options - AppendBlobClientAppendBlockOptions contains the optional parameters for the AppendBlobClient.AppendBlock method. @@ -59,7 +48,7 @@ func (client *AppendBlobClient) AppendBlock(ctx context.Context, contentLength i if err != nil { return AppendBlobClientAppendBlockResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return AppendBlobClientAppendBlockResponse{}, err } @@ -124,12 +113,15 @@ func (client *AppendBlobClient) appendBlockCreateRequest(ctx context.Context, co if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } req.Raw().Header["Accept"] = []string{"application/xml"} - return req, req.SetBody(body, "application/octet-stream") + if err := req.SetBody(body, "application/octet-stream"); err != nil { + return nil, err + } + return req, nil } // appendBlockHandleResponse handles the AppendBlock response. @@ -207,7 +199,7 @@ func (client *AppendBlobClient) appendBlockHandleResponse(resp *http.Response) ( // created with x-ms-blob-type set to AppendBlob. Append Block is supported only on version 2015-02-21 version or later. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - sourceURL - Specify a URL to the copy source. // - contentLength - The length of the request. // - options - AppendBlobClientAppendBlockFromURLOptions contains the optional parameters for the AppendBlobClient.AppendBlockFromURL @@ -225,7 +217,7 @@ func (client *AppendBlobClient) AppendBlockFromURL(ctx context.Context, sourceUR if err != nil { return AppendBlobClientAppendBlockFromURLResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return AppendBlobClientAppendBlockFromURLResponse{}, err } @@ -309,7 +301,7 @@ func (client *AppendBlobClient) appendBlockFromURLCreateRequest(ctx context.Cont if sourceModifiedAccessConditions != nil && sourceModifiedAccessConditions.SourceIfNoneMatch != nil { req.Raw().Header["x-ms-source-if-none-match"] = []string{string(*sourceModifiedAccessConditions.SourceIfNoneMatch)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -390,7 +382,7 @@ func (client *AppendBlobClient) appendBlockFromURLHandleResponse(resp *http.Resp // Create - The Create Append Blob operation creates a new append blob. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - contentLength - The length of the request. // - options - AppendBlobClientCreateOptions contains the optional parameters for the AppendBlobClient.Create method. // - BlobHTTPHeaders - BlobHTTPHeaders contains a group of parameters for the BlobClient.SetHTTPHeaders method. @@ -403,7 +395,7 @@ func (client *AppendBlobClient) Create(ctx context.Context, contentLength int64, if err != nil { return AppendBlobClientCreateResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return AppendBlobClientCreateResponse{}, err } @@ -481,7 +473,7 @@ func (client *AppendBlobClient) createCreateRequest(ctx context.Context, content if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -560,7 +552,7 @@ func (client *AppendBlobClient) createHandleResponse(resp *http.Response) (Appen // or later. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - AppendBlobClientSealOptions contains the optional parameters for the AppendBlobClient.Seal method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. // - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method. @@ -571,7 +563,7 @@ func (client *AppendBlobClient) Seal(ctx context.Context, options *AppendBlobCli if err != nil { return AppendBlobClientSealResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return AppendBlobClientSealResponse{}, err } @@ -593,7 +585,7 @@ func (client *AppendBlobClient) sealCreateRequest(ctx context.Context, options * reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } diff --git a/sdk/storage/azblob/internal/generated/zz_blob_client.go b/sdk/storage/azblob/internal/generated/zz_blob_client.go index 67402b5a5ab3..8e8ed79c7df5 100644 --- a/sdk/storage/azblob/internal/generated/zz_blob_client.go +++ b/sdk/storage/azblob/internal/generated/zz_blob_client.go @@ -23,28 +23,17 @@ import ( ) // BlobClient contains the methods for the Blob group. -// Don't use this type directly, use NewBlobClient() instead. +// Don't use this type directly, use a constructor function instead. type BlobClient struct { + internal *azcore.Client endpoint string - pl runtime.Pipeline -} - -// NewBlobClient creates a new instance of BlobClient with the specified values. -// - endpoint - The URL of the service account, container, or blob that is the target of the desired operation. -// - pl - the pipeline used for sending requests and handling responses. -func NewBlobClient(endpoint string, pl runtime.Pipeline) *BlobClient { - client := &BlobClient{ - endpoint: endpoint, - pl: pl, - } - return client } // AbortCopyFromURL - The Abort Copy From URL operation aborts a pending Copy From URL operation, and leaves a destination // blob with zero length and full metadata. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - copyID - The copy identifier provided in the x-ms-copy-id header of the original Copy Blob operation. // - options - BlobClientAbortCopyFromURLOptions contains the optional parameters for the BlobClient.AbortCopyFromURL method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. @@ -53,7 +42,7 @@ func (client *BlobClient) AbortCopyFromURL(ctx context.Context, copyID string, o if err != nil { return BlobClientAbortCopyFromURLResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientAbortCopyFromURLResponse{}, err } @@ -80,7 +69,7 @@ func (client *BlobClient) abortCopyFromURLCreateRequest(ctx context.Context, cop if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -113,7 +102,7 @@ func (client *BlobClient) abortCopyFromURLHandleResponse(resp *http.Response) (B // AcquireLease - [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - duration - Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite // lease can be between 15 and 60 seconds. A lease duration cannot be changed using // renew or change. @@ -124,7 +113,7 @@ func (client *BlobClient) AcquireLease(ctx context.Context, duration int32, opti if err != nil { return BlobClientAcquireLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientAcquireLeaseResponse{}, err } @@ -166,7 +155,7 @@ func (client *BlobClient) acquireLeaseCreateRequest(ctx context.Context, duratio if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -212,7 +201,7 @@ func (client *BlobClient) acquireLeaseHandleResponse(resp *http.Response) (BlobC // BreakLease - [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - BlobClientBreakLeaseOptions contains the optional parameters for the BlobClient.BreakLease method. // - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method. func (client *BlobClient) BreakLease(ctx context.Context, options *BlobClientBreakLeaseOptions, modifiedAccessConditions *ModifiedAccessConditions) (BlobClientBreakLeaseResponse, error) { @@ -220,7 +209,7 @@ func (client *BlobClient) BreakLease(ctx context.Context, options *BlobClientBre if err != nil { return BlobClientBreakLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientBreakLeaseResponse{}, err } @@ -261,7 +250,7 @@ func (client *BlobClient) breakLeaseCreateRequest(ctx context.Context, options * if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -312,7 +301,7 @@ func (client *BlobClient) breakLeaseHandleResponse(resp *http.Response) (BlobCli // ChangeLease - [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - leaseID - Specifies the current lease ID on the resource. // - proposedLeaseID - Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the proposed // lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID @@ -324,7 +313,7 @@ func (client *BlobClient) ChangeLease(ctx context.Context, leaseID string, propo if err != nil { return BlobClientChangeLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientChangeLeaseResponse{}, err } @@ -364,7 +353,7 @@ func (client *BlobClient) changeLeaseCreateRequest(ctx context.Context, leaseID if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -411,7 +400,7 @@ func (client *BlobClient) changeLeaseHandleResponse(resp *http.Response) (BlobCl // until the copy is complete. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - copySource - Specifies the name of the source page blob snapshot. This value is a URL of up to 2 KB in length that specifies // a page blob snapshot. The value should be URL-encoded as it would appear in a request // URI. The source blob must either be public or must be authenticated via a shared access signature. @@ -420,12 +409,13 @@ func (client *BlobClient) changeLeaseHandleResponse(resp *http.Response) (BlobCl // method. // - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. -func (client *BlobClient) CopyFromURL(ctx context.Context, copySource string, options *BlobClientCopyFromURLOptions, sourceModifiedAccessConditions *SourceModifiedAccessConditions, modifiedAccessConditions *ModifiedAccessConditions, leaseAccessConditions *LeaseAccessConditions) (BlobClientCopyFromURLResponse, error) { - req, err := client.copyFromURLCreateRequest(ctx, copySource, options, sourceModifiedAccessConditions, modifiedAccessConditions, leaseAccessConditions) +// - CPKScopeInfo - CPKScopeInfo contains a group of parameters for the BlobClient.SetMetadata method. +func (client *BlobClient) CopyFromURL(ctx context.Context, copySource string, options *BlobClientCopyFromURLOptions, sourceModifiedAccessConditions *SourceModifiedAccessConditions, modifiedAccessConditions *ModifiedAccessConditions, leaseAccessConditions *LeaseAccessConditions, cpkScopeInfo *CPKScopeInfo) (BlobClientCopyFromURLResponse, error) { + req, err := client.copyFromURLCreateRequest(ctx, copySource, options, sourceModifiedAccessConditions, modifiedAccessConditions, leaseAccessConditions, cpkScopeInfo) if err != nil { return BlobClientCopyFromURLResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientCopyFromURLResponse{}, err } @@ -436,7 +426,7 @@ func (client *BlobClient) CopyFromURL(ctx context.Context, copySource string, op } // copyFromURLCreateRequest creates the CopyFromURL request. -func (client *BlobClient) copyFromURLCreateRequest(ctx context.Context, copySource string, options *BlobClientCopyFromURLOptions, sourceModifiedAccessConditions *SourceModifiedAccessConditions, modifiedAccessConditions *ModifiedAccessConditions, leaseAccessConditions *LeaseAccessConditions) (*policy.Request, error) { +func (client *BlobClient) copyFromURLCreateRequest(ctx context.Context, copySource string, options *BlobClientCopyFromURLOptions, sourceModifiedAccessConditions *SourceModifiedAccessConditions, modifiedAccessConditions *ModifiedAccessConditions, leaseAccessConditions *LeaseAccessConditions, cpkScopeInfo *CPKScopeInfo) (*policy.Request, error) { req, err := runtime.NewRequest(ctx, http.MethodPut, client.endpoint) if err != nil { return nil, err @@ -488,7 +478,7 @@ func (client *BlobClient) copyFromURLCreateRequest(ctx context.Context, copySour if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -510,6 +500,12 @@ func (client *BlobClient) copyFromURLCreateRequest(ctx context.Context, copySour if options != nil && options.CopySourceAuthorization != nil { req.Raw().Header["x-ms-copy-source-authorization"] = []string{*options.CopySourceAuthorization} } + if cpkScopeInfo != nil && cpkScopeInfo.EncryptionScope != nil { + req.Raw().Header["x-ms-encryption-scope"] = []string{*cpkScopeInfo.EncryptionScope} + } + if options != nil && options.CopySourceTags != nil { + req.Raw().Header["x-ms-copy-source-tag-option"] = []string{string(*options.CopySourceTags)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -566,13 +562,16 @@ func (client *BlobClient) copyFromURLHandleResponse(resp *http.Response) (BlobCl } result.ContentCRC64 = contentCRC64 } + if val := resp.Header.Get("x-ms-encryption-scope"); val != "" { + result.EncryptionScope = &val + } return result, nil } // CreateSnapshot - The Create Snapshot operation creates a read-only snapshot of a blob // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - BlobClientCreateSnapshotOptions contains the optional parameters for the BlobClient.CreateSnapshot method. // - CPKInfo - CPKInfo contains a group of parameters for the BlobClient.Download method. // - CPKScopeInfo - CPKScopeInfo contains a group of parameters for the BlobClient.SetMetadata method. @@ -583,7 +582,7 @@ func (client *BlobClient) CreateSnapshot(ctx context.Context, options *BlobClien if err != nil { return BlobClientCreateSnapshotResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientCreateSnapshotResponse{}, err } @@ -642,7 +641,7 @@ func (client *BlobClient) createSnapshotCreateRequest(ctx context.Context, optio if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -708,7 +707,7 @@ func (client *BlobClient) createSnapshotHandleResponse(resp *http.Response) (Blo // return an HTTP status code of 404 (ResourceNotFound). // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - BlobClientDeleteOptions contains the optional parameters for the BlobClient.Delete method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. // - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method. @@ -717,7 +716,7 @@ func (client *BlobClient) Delete(ctx context.Context, options *BlobClientDeleteO if err != nil { return BlobClientDeleteResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientDeleteResponse{}, err } @@ -768,7 +767,7 @@ func (client *BlobClient) deleteCreateRequest(ctx context.Context, options *Blob if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -801,7 +800,7 @@ func (client *BlobClient) deleteHandleResponse(resp *http.Response) (BlobClientD // DeleteImmutabilityPolicy - The Delete Immutability Policy operation deletes the immutability policy on the blob // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - BlobClientDeleteImmutabilityPolicyOptions contains the optional parameters for the BlobClient.DeleteImmutabilityPolicy // method. func (client *BlobClient) DeleteImmutabilityPolicy(ctx context.Context, options *BlobClientDeleteImmutabilityPolicyOptions) (BlobClientDeleteImmutabilityPolicyResponse, error) { @@ -809,7 +808,7 @@ func (client *BlobClient) DeleteImmutabilityPolicy(ctx context.Context, options if err != nil { return BlobClientDeleteImmutabilityPolicyResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientDeleteImmutabilityPolicyResponse{}, err } @@ -831,7 +830,7 @@ func (client *BlobClient) deleteImmutabilityPolicyCreateRequest(ctx context.Cont reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -865,7 +864,7 @@ func (client *BlobClient) deleteImmutabilityPolicyHandleResponse(resp *http.Resp // can also call Download to read a snapshot. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - BlobClientDownloadOptions contains the optional parameters for the BlobClient.Download method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. // - CPKInfo - CPKInfo contains a group of parameters for the BlobClient.Download method. @@ -875,7 +874,7 @@ func (client *BlobClient) Download(ctx context.Context, options *BlobClientDownl if err != nil { return BlobClientDownloadResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientDownloadResponse{}, err } @@ -939,7 +938,7 @@ func (client *BlobClient) downloadCreateRequest(ctx context.Context, options *Bl if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -1163,14 +1162,14 @@ func (client *BlobClient) downloadHandleResponse(resp *http.Response) (BlobClien // GetAccountInfo - Returns the sku name and account kind // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - BlobClientGetAccountInfoOptions contains the optional parameters for the BlobClient.GetAccountInfo method. func (client *BlobClient) GetAccountInfo(ctx context.Context, options *BlobClientGetAccountInfoOptions) (BlobClientGetAccountInfoResponse, error) { req, err := client.getAccountInfoCreateRequest(ctx, options) if err != nil { return BlobClientGetAccountInfoResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientGetAccountInfoResponse{}, err } @@ -1190,7 +1189,7 @@ func (client *BlobClient) getAccountInfoCreateRequest(ctx context.Context, optio reqQP.Set("restype", "account") reqQP.Set("comp", "properties") req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -1227,7 +1226,7 @@ func (client *BlobClient) getAccountInfoHandleResponse(resp *http.Response) (Blo // for the blob. It does not return the content of the blob. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - BlobClientGetPropertiesOptions contains the optional parameters for the BlobClient.GetProperties method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. // - CPKInfo - CPKInfo contains a group of parameters for the BlobClient.Download method. @@ -1237,7 +1236,7 @@ func (client *BlobClient) GetProperties(ctx context.Context, options *BlobClient if err != nil { return BlobClientGetPropertiesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientGetPropertiesResponse{}, err } @@ -1291,7 +1290,7 @@ func (client *BlobClient) getPropertiesCreateRequest(ctx context.Context, option if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -1542,7 +1541,7 @@ func (client *BlobClient) getPropertiesHandleResponse(resp *http.Response) (Blob // GetTags - The Get Tags operation enables users to get the tags associated with a blob. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - BlobClientGetTagsOptions contains the optional parameters for the BlobClient.GetTags method. // - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. @@ -1551,7 +1550,7 @@ func (client *BlobClient) GetTags(ctx context.Context, options *BlobClientGetTag if err != nil { return BlobClientGetTagsResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientGetTagsResponse{}, err } @@ -1579,7 +1578,7 @@ func (client *BlobClient) getTagsCreateRequest(ctx context.Context, options *Blo reqQP.Set("versionid", *options.VersionID) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -1621,7 +1620,7 @@ func (client *BlobClient) getTagsHandleResponse(resp *http.Response) (BlobClient // Query - The Query operation enables users to select/project on blob data by providing simple query expressions. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - BlobClientQueryOptions contains the optional parameters for the BlobClient.Query method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. // - CPKInfo - CPKInfo contains a group of parameters for the BlobClient.Download method. @@ -1631,7 +1630,7 @@ func (client *BlobClient) Query(ctx context.Context, options *BlobClientQueryOpt if err != nil { return BlobClientQueryResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientQueryResponse{}, err } @@ -1684,13 +1683,16 @@ func (client *BlobClient) queryCreateRequest(ctx context.Context, options *BlobC if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } req.Raw().Header["Accept"] = []string{"application/xml"} if options != nil && options.QueryRequest != nil { - return req, runtime.MarshalAsXML(req, *options.QueryRequest) + if err := runtime.MarshalAsXML(req, *options.QueryRequest); err != nil { + return nil, err + } + return req, nil } return req, nil } @@ -1849,7 +1851,7 @@ func (client *BlobClient) queryHandleResponse(resp *http.Response) (BlobClientQu // ReleaseLease - [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - leaseID - Specifies the current lease ID on the resource. // - options - BlobClientReleaseLeaseOptions contains the optional parameters for the BlobClient.ReleaseLease method. // - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method. @@ -1858,7 +1860,7 @@ func (client *BlobClient) ReleaseLease(ctx context.Context, leaseID string, opti if err != nil { return BlobClientReleaseLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientReleaseLeaseResponse{}, err } @@ -1897,7 +1899,7 @@ func (client *BlobClient) releaseLeaseCreateRequest(ctx context.Context, leaseID if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -1940,7 +1942,7 @@ func (client *BlobClient) releaseLeaseHandleResponse(resp *http.Response) (BlobC // RenewLease - [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - leaseID - Specifies the current lease ID on the resource. // - options - BlobClientRenewLeaseOptions contains the optional parameters for the BlobClient.RenewLease method. // - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method. @@ -1949,7 +1951,7 @@ func (client *BlobClient) RenewLease(ctx context.Context, leaseID string, option if err != nil { return BlobClientRenewLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientRenewLeaseResponse{}, err } @@ -1988,7 +1990,7 @@ func (client *BlobClient) renewLeaseCreateRequest(ctx context.Context, leaseID s if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -2034,7 +2036,7 @@ func (client *BlobClient) renewLeaseHandleResponse(resp *http.Response) (BlobCli // SetExpiry - Sets the time a blob will expire and be deleted. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - expiryOptions - Required. Indicates mode of the expiry time // - options - BlobClientSetExpiryOptions contains the optional parameters for the BlobClient.SetExpiry method. func (client *BlobClient) SetExpiry(ctx context.Context, expiryOptions ExpiryOptions, options *BlobClientSetExpiryOptions) (BlobClientSetExpiryResponse, error) { @@ -2042,7 +2044,7 @@ func (client *BlobClient) SetExpiry(ctx context.Context, expiryOptions ExpiryOpt if err != nil { return BlobClientSetExpiryResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientSetExpiryResponse{}, err } @@ -2064,7 +2066,7 @@ func (client *BlobClient) setExpiryCreateRequest(ctx context.Context, expiryOpti reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -2111,7 +2113,7 @@ func (client *BlobClient) setExpiryHandleResponse(resp *http.Response) (BlobClie // SetHTTPHeaders - The Set HTTP Headers operation sets system properties on the blob // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - BlobClientSetHTTPHeadersOptions contains the optional parameters for the BlobClient.SetHTTPHeaders method. // - BlobHTTPHeaders - BlobHTTPHeaders contains a group of parameters for the BlobClient.SetHTTPHeaders method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. @@ -2121,7 +2123,7 @@ func (client *BlobClient) SetHTTPHeaders(ctx context.Context, options *BlobClien if err != nil { return BlobClientSetHTTPHeadersResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientSetHTTPHeadersResponse{}, err } @@ -2179,7 +2181,7 @@ func (client *BlobClient) setHTTPHeadersCreateRequest(ctx context.Context, optio if blobHTTPHeaders != nil && blobHTTPHeaders.BlobContentDisposition != nil { req.Raw().Header["x-ms-blob-content-disposition"] = []string{*blobHTTPHeaders.BlobContentDisposition} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -2229,7 +2231,7 @@ func (client *BlobClient) setHTTPHeadersHandleResponse(resp *http.Response) (Blo // SetImmutabilityPolicy - The Set Immutability Policy operation sets the immutability policy on the blob // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - BlobClientSetImmutabilityPolicyOptions contains the optional parameters for the BlobClient.SetImmutabilityPolicy // method. // - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method. @@ -2238,7 +2240,7 @@ func (client *BlobClient) SetImmutabilityPolicy(ctx context.Context, options *Bl if err != nil { return BlobClientSetImmutabilityPolicyResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientSetImmutabilityPolicyResponse{}, err } @@ -2260,7 +2262,7 @@ func (client *BlobClient) setImmutabilityPolicyCreateRequest(ctx context.Context reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -2312,7 +2314,7 @@ func (client *BlobClient) setImmutabilityPolicyHandleResponse(resp *http.Respons // SetLegalHold - The Set Legal Hold operation sets a legal hold on the blob. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - legalHold - Specified if a legal hold should be set on the blob. // - options - BlobClientSetLegalHoldOptions contains the optional parameters for the BlobClient.SetLegalHold method. func (client *BlobClient) SetLegalHold(ctx context.Context, legalHold bool, options *BlobClientSetLegalHoldOptions) (BlobClientSetLegalHoldResponse, error) { @@ -2320,7 +2322,7 @@ func (client *BlobClient) SetLegalHold(ctx context.Context, legalHold bool, opti if err != nil { return BlobClientSetLegalHoldResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientSetLegalHoldResponse{}, err } @@ -2342,7 +2344,7 @@ func (client *BlobClient) setLegalHoldCreateRequest(ctx context.Context, legalHo reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -2384,7 +2386,7 @@ func (client *BlobClient) setLegalHoldHandleResponse(resp *http.Response) (BlobC // pairs // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - BlobClientSetMetadataOptions contains the optional parameters for the BlobClient.SetMetadata method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. // - CPKInfo - CPKInfo contains a group of parameters for the BlobClient.Download method. @@ -2395,7 +2397,7 @@ func (client *BlobClient) SetMetadata(ctx context.Context, options *BlobClientSe if err != nil { return BlobClientSetMetadataResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientSetMetadataResponse{}, err } @@ -2454,7 +2456,7 @@ func (client *BlobClient) setMetadataCreateRequest(ctx context.Context, options if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -2513,7 +2515,7 @@ func (client *BlobClient) setMetadataHandleResponse(resp *http.Response) (BlobCl // SetTags - The Set Tags operation enables users to set tags on a blob. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - tags - Blob tags // - options - BlobClientSetTagsOptions contains the optional parameters for the BlobClient.SetTags method. // - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method. @@ -2523,7 +2525,7 @@ func (client *BlobClient) SetTags(ctx context.Context, tags BlobTags, options *B if err != nil { return BlobClientSetTagsResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientSetTagsResponse{}, err } @@ -2548,7 +2550,7 @@ func (client *BlobClient) setTagsCreateRequest(ctx context.Context, tags BlobTag reqQP.Set("versionid", *options.VersionID) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.TransactionalContentMD5 != nil { req.Raw().Header["Content-MD5"] = []string{base64.StdEncoding.EncodeToString(options.TransactionalContentMD5)} } @@ -2565,7 +2567,10 @@ func (client *BlobClient) setTagsCreateRequest(ctx context.Context, tags BlobTag req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } req.Raw().Header["Accept"] = []string{"application/xml"} - return req, runtime.MarshalAsXML(req, tags) + if err := runtime.MarshalAsXML(req, tags); err != nil { + return nil, err + } + return req, nil } // setTagsHandleResponse handles the SetTags response. @@ -2596,7 +2601,7 @@ func (client *BlobClient) setTagsHandleResponse(resp *http.Response) (BlobClient // storage type. This operation does not update the blob's ETag. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - tier - Indicates the tier to be set on the blob. // - options - BlobClientSetTierOptions contains the optional parameters for the BlobClient.SetTier method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. @@ -2606,7 +2611,7 @@ func (client *BlobClient) SetTier(ctx context.Context, tier AccessTier, options if err != nil { return BlobClientSetTierResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientSetTierResponse{}, err } @@ -2638,7 +2643,7 @@ func (client *BlobClient) setTierCreateRequest(ctx context.Context, tier AccessT if options != nil && options.RehydratePriority != nil { req.Raw().Header["x-ms-rehydrate-priority"] = []string{string(*options.RehydratePriority)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -2670,7 +2675,7 @@ func (client *BlobClient) setTierHandleResponse(resp *http.Response) (BlobClient // StartCopyFromURL - The Start Copy From URL operation copies a blob or an internet resource to a new blob. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - copySource - Specifies the name of the source page blob snapshot. This value is a URL of up to 2 KB in length that specifies // a page blob snapshot. The value should be URL-encoded as it would appear in a request // URI. The source blob must either be public or must be authenticated via a shared access signature. @@ -2684,7 +2689,7 @@ func (client *BlobClient) StartCopyFromURL(ctx context.Context, copySource strin if err != nil { return BlobClientStartCopyFromURLResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientStartCopyFromURLResponse{}, err } @@ -2752,7 +2757,7 @@ func (client *BlobClient) startCopyFromURLCreateRequest(ctx context.Context, cop if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -2819,14 +2824,14 @@ func (client *BlobClient) startCopyFromURLHandleResponse(resp *http.Response) (B // Undelete - Undelete a blob that was previously soft deleted // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - BlobClientUndeleteOptions contains the optional parameters for the BlobClient.Undelete method. func (client *BlobClient) Undelete(ctx context.Context, options *BlobClientUndeleteOptions) (BlobClientUndeleteResponse, error) { req, err := client.undeleteCreateRequest(ctx, options) if err != nil { return BlobClientUndeleteResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlobClientUndeleteResponse{}, err } @@ -2848,7 +2853,7 @@ func (client *BlobClient) undeleteCreateRequest(ctx context.Context, options *Bl reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } diff --git a/sdk/storage/azblob/internal/generated/zz_blockblob_client.go b/sdk/storage/azblob/internal/generated/zz_blockblob_client.go index 7e81d15403d9..8fbd03a84965 100644 --- a/sdk/storage/azblob/internal/generated/zz_blockblob_client.go +++ b/sdk/storage/azblob/internal/generated/zz_blockblob_client.go @@ -22,21 +22,10 @@ import ( ) // BlockBlobClient contains the methods for the BlockBlob group. -// Don't use this type directly, use NewBlockBlobClient() instead. +// Don't use this type directly, use a constructor function instead. type BlockBlobClient struct { + internal *azcore.Client endpoint string - pl runtime.Pipeline -} - -// NewBlockBlobClient creates a new instance of BlockBlobClient with the specified values. -// - endpoint - The URL of the service account, container, or blob that is the target of the desired operation. -// - pl - the pipeline used for sending requests and handling responses. -func NewBlockBlobClient(endpoint string, pl runtime.Pipeline) *BlockBlobClient { - client := &BlockBlobClient{ - endpoint: endpoint, - pl: pl, - } - return client } // CommitBlockList - The Commit Block List operation writes a blob by specifying the list of block IDs that make up the blob. @@ -48,7 +37,7 @@ func NewBlockBlobClient(endpoint string, pl runtime.Pipeline) *BlockBlobClient { // belong to. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - blocks - Blob Blocks. // - options - BlockBlobClientCommitBlockListOptions contains the optional parameters for the BlockBlobClient.CommitBlockList // method. @@ -62,7 +51,7 @@ func (client *BlockBlobClient) CommitBlockList(ctx context.Context, blocks Block if err != nil { return BlockBlobClientCommitBlockListResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlockBlobClientCommitBlockListResponse{}, err } @@ -148,7 +137,7 @@ func (client *BlockBlobClient) commitBlockListCreateRequest(ctx context.Context, if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -165,7 +154,10 @@ func (client *BlockBlobClient) commitBlockListCreateRequest(ctx context.Context, req.Raw().Header["x-ms-legal-hold"] = []string{strconv.FormatBool(*options.LegalHold)} } req.Raw().Header["Accept"] = []string{"application/xml"} - return req, runtime.MarshalAsXML(req, blocks) + if err := runtime.MarshalAsXML(req, blocks); err != nil { + return nil, err + } + return req, nil } // commitBlockListHandleResponse handles the CommitBlockList response. @@ -233,7 +225,7 @@ func (client *BlockBlobClient) commitBlockListHandleResponse(resp *http.Response // GetBlockList - The Get Block List operation retrieves the list of blocks that have been uploaded as part of a block blob // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - listType - Specifies whether to return the list of committed blocks, the list of uncommitted blocks, or both lists together. // - options - BlockBlobClientGetBlockListOptions contains the optional parameters for the BlockBlobClient.GetBlockList method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. @@ -243,7 +235,7 @@ func (client *BlockBlobClient) GetBlockList(ctx context.Context, listType BlockL if err != nil { return BlockBlobClientGetBlockListResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlockBlobClientGetBlockListResponse{}, err } @@ -275,7 +267,7 @@ func (client *BlockBlobClient) getBlockListCreateRequest(ctx context.Context, li if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -335,7 +327,7 @@ func (client *BlockBlobClient) getBlockListHandleResponse(resp *http.Response) ( // Block from URL API in conjunction with Put Block List. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - contentLength - The length of the request. // - copySource - Specifies the name of the source page blob snapshot. This value is a URL of up to 2 KB in length that specifies // a page blob snapshot. The value should be URL-encoded as it would appear in a request @@ -354,7 +346,7 @@ func (client *BlockBlobClient) PutBlobFromURL(ctx context.Context, contentLength if err != nil { return BlockBlobClientPutBlobFromURLResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlockBlobClientPutBlobFromURLResponse{}, err } @@ -453,7 +445,7 @@ func (client *BlockBlobClient) putBlobFromURLCreateRequest(ctx context.Context, if sourceModifiedAccessConditions != nil && sourceModifiedAccessConditions.SourceIfTags != nil { req.Raw().Header["x-ms-source-if-tags"] = []string{*sourceModifiedAccessConditions.SourceIfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -470,6 +462,9 @@ func (client *BlockBlobClient) putBlobFromURLCreateRequest(ctx context.Context, if options != nil && options.CopySourceAuthorization != nil { req.Raw().Header["x-ms-copy-source-authorization"] = []string{*options.CopySourceAuthorization} } + if options != nil && options.CopySourceTags != nil { + req.Raw().Header["x-ms-copy-source-tag-option"] = []string{string(*options.CopySourceTags)} + } req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -532,7 +527,7 @@ func (client *BlockBlobClient) putBlobFromURLHandleResponse(resp *http.Response) // StageBlock - The Stage Block operation creates a new block to be committed as part of a blob // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - blockID - A valid Base64 string value that identifies the block. Prior to encoding, the string must be less than or equal // to 64 bytes in size. For a given blob, the length of the value specified for the blockid // parameter must be the same size for each block. @@ -547,7 +542,7 @@ func (client *BlockBlobClient) StageBlock(ctx context.Context, blockID string, c if err != nil { return BlockBlobClientStageBlockResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlockBlobClientStageBlockResponse{}, err } @@ -592,12 +587,15 @@ func (client *BlockBlobClient) stageBlockCreateRequest(ctx context.Context, bloc if cpkScopeInfo != nil && cpkScopeInfo.EncryptionScope != nil { req.Raw().Header["x-ms-encryption-scope"] = []string{*cpkScopeInfo.EncryptionScope} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } req.Raw().Header["Accept"] = []string{"application/xml"} - return req, req.SetBody(body, "application/octet-stream") + if err := req.SetBody(body, "application/octet-stream"); err != nil { + return nil, err + } + return req, nil } // stageBlockHandleResponse handles the StageBlock response. @@ -653,7 +651,7 @@ func (client *BlockBlobClient) stageBlockHandleResponse(resp *http.Response) (Bl // are read from a URL. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - blockID - A valid Base64 string value that identifies the block. Prior to encoding, the string must be less than or equal // to 64 bytes in size. For a given blob, the length of the value specified for the blockid // parameter must be the same size for each block. @@ -671,7 +669,7 @@ func (client *BlockBlobClient) StageBlockFromURL(ctx context.Context, blockID st if err != nil { return BlockBlobClientStageBlockFromURLResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlockBlobClientStageBlockFromURLResponse{}, err } @@ -732,7 +730,7 @@ func (client *BlockBlobClient) stageBlockFromURLCreateRequest(ctx context.Contex if sourceModifiedAccessConditions != nil && sourceModifiedAccessConditions.SourceIfNoneMatch != nil { req.Raw().Header["x-ms-source-if-none-match"] = []string{string(*sourceModifiedAccessConditions.SourceIfNoneMatch)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -798,7 +796,7 @@ func (client *BlockBlobClient) stageBlockFromURLHandleResponse(resp *http.Respon // the content of a block blob, use the Put Block List operation. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - contentLength - The length of the request. // - body - Initial data // - options - BlockBlobClientUploadOptions contains the optional parameters for the BlockBlobClient.Upload method. @@ -812,7 +810,7 @@ func (client *BlockBlobClient) Upload(ctx context.Context, contentLength int64, if err != nil { return BlockBlobClientUploadResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return BlockBlobClientUploadResponse{}, err } @@ -896,7 +894,7 @@ func (client *BlockBlobClient) uploadCreateRequest(ctx context.Context, contentL if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -912,8 +910,14 @@ func (client *BlockBlobClient) uploadCreateRequest(ctx context.Context, contentL if options != nil && options.LegalHold != nil { req.Raw().Header["x-ms-legal-hold"] = []string{strconv.FormatBool(*options.LegalHold)} } + if options != nil && options.TransactionalContentCRC64 != nil { + req.Raw().Header["x-ms-content-crc64"] = []string{base64.StdEncoding.EncodeToString(options.TransactionalContentCRC64)} + } req.Raw().Header["Accept"] = []string{"application/xml"} - return req, req.SetBody(body, "application/octet-stream") + if err := req.SetBody(body, "application/octet-stream"); err != nil { + return nil, err + } + return req, nil } // uploadHandleResponse handles the Upload response. diff --git a/sdk/storage/azblob/internal/generated/zz_constants.go b/sdk/storage/azblob/internal/generated/zz_constants.go index 74e6cf1e8590..c1c89ec99e82 100644 --- a/sdk/storage/azblob/internal/generated/zz_constants.go +++ b/sdk/storage/azblob/internal/generated/zz_constants.go @@ -13,6 +13,7 @@ type AccessTier string const ( AccessTierArchive AccessTier = "Archive" + AccessTierCold AccessTier = "Cold" AccessTierCool AccessTier = "Cool" AccessTierHot AccessTier = "Hot" AccessTierP10 AccessTier = "P10" @@ -33,6 +34,7 @@ const ( func PossibleAccessTierValues() []AccessTier { return []AccessTier{ AccessTierArchive, + AccessTierCold, AccessTierCool, AccessTierHot, AccessTierP10, @@ -53,21 +55,21 @@ func PossibleAccessTierValues() []AccessTier { type AccountKind string const ( - AccountKindStorage AccountKind = "Storage" AccountKindBlobStorage AccountKind = "BlobStorage" - AccountKindStorageV2 AccountKind = "StorageV2" - AccountKindFileStorage AccountKind = "FileStorage" AccountKindBlockBlobStorage AccountKind = "BlockBlobStorage" + AccountKindFileStorage AccountKind = "FileStorage" + AccountKindStorage AccountKind = "Storage" + AccountKindStorageV2 AccountKind = "StorageV2" ) // PossibleAccountKindValues returns the possible values for the AccountKind const type. func PossibleAccountKindValues() []AccountKind { return []AccountKind{ - AccountKindStorage, AccountKindBlobStorage, - AccountKindStorageV2, - AccountKindFileStorage, AccountKindBlockBlobStorage, + AccountKindFileStorage, + AccountKindStorage, + AccountKindStorageV2, } } @@ -86,20 +88,35 @@ func PossibleArchiveStatusValues() []ArchiveStatus { } } +type BlobCopySourceTags string + +const ( + BlobCopySourceTagsCOPY BlobCopySourceTags = "COPY" + BlobCopySourceTagsREPLACE BlobCopySourceTags = "REPLACE" +) + +// PossibleBlobCopySourceTagsValues returns the possible values for the BlobCopySourceTags const type. +func PossibleBlobCopySourceTagsValues() []BlobCopySourceTags { + return []BlobCopySourceTags{ + BlobCopySourceTagsCOPY, + BlobCopySourceTagsREPLACE, + } +} + // BlobGeoReplicationStatus - The status of the secondary location type BlobGeoReplicationStatus string const ( - BlobGeoReplicationStatusLive BlobGeoReplicationStatus = "live" BlobGeoReplicationStatusBootstrap BlobGeoReplicationStatus = "bootstrap" + BlobGeoReplicationStatusLive BlobGeoReplicationStatus = "live" BlobGeoReplicationStatusUnavailable BlobGeoReplicationStatus = "unavailable" ) // PossibleBlobGeoReplicationStatusValues returns the possible values for the BlobGeoReplicationStatus const type. func PossibleBlobGeoReplicationStatusValues() []BlobGeoReplicationStatus { return []BlobGeoReplicationStatus{ - BlobGeoReplicationStatusLive, BlobGeoReplicationStatusBootstrap, + BlobGeoReplicationStatusLive, BlobGeoReplicationStatusUnavailable, } } @@ -107,53 +124,53 @@ func PossibleBlobGeoReplicationStatusValues() []BlobGeoReplicationStatus { type BlobType string const ( + BlobTypeAppendBlob BlobType = "AppendBlob" BlobTypeBlockBlob BlobType = "BlockBlob" BlobTypePageBlob BlobType = "PageBlob" - BlobTypeAppendBlob BlobType = "AppendBlob" ) // PossibleBlobTypeValues returns the possible values for the BlobType const type. func PossibleBlobTypeValues() []BlobType { return []BlobType{ + BlobTypeAppendBlob, BlobTypeBlockBlob, BlobTypePageBlob, - BlobTypeAppendBlob, } } type BlockListType string const ( + BlockListTypeAll BlockListType = "all" BlockListTypeCommitted BlockListType = "committed" BlockListTypeUncommitted BlockListType = "uncommitted" - BlockListTypeAll BlockListType = "all" ) // PossibleBlockListTypeValues returns the possible values for the BlockListType const type. func PossibleBlockListTypeValues() []BlockListType { return []BlockListType{ + BlockListTypeAll, BlockListTypeCommitted, BlockListTypeUncommitted, - BlockListTypeAll, } } type CopyStatusType string const ( - CopyStatusTypePending CopyStatusType = "pending" - CopyStatusTypeSuccess CopyStatusType = "success" CopyStatusTypeAborted CopyStatusType = "aborted" CopyStatusTypeFailed CopyStatusType = "failed" + CopyStatusTypePending CopyStatusType = "pending" + CopyStatusTypeSuccess CopyStatusType = "success" ) // PossibleCopyStatusTypeValues returns the possible values for the CopyStatusType const type. func PossibleCopyStatusTypeValues() []CopyStatusType { return []CopyStatusType{ - CopyStatusTypePending, - CopyStatusTypeSuccess, CopyStatusTypeAborted, CopyStatusTypeFailed, + CopyStatusTypePending, + CopyStatusTypeSuccess, } } @@ -190,15 +207,15 @@ func PossibleDeleteTypeValues() []DeleteType { type EncryptionAlgorithmType string const ( - EncryptionAlgorithmTypeNone EncryptionAlgorithmType = "None" EncryptionAlgorithmTypeAES256 EncryptionAlgorithmType = "AES256" + EncryptionAlgorithmTypeNone EncryptionAlgorithmType = "None" ) // PossibleEncryptionAlgorithmTypeValues returns the possible values for the EncryptionAlgorithmType const type. func PossibleEncryptionAlgorithmTypeValues() []EncryptionAlgorithmType { return []EncryptionAlgorithmType{ - EncryptionAlgorithmTypeNone, EncryptionAlgorithmTypeAES256, + EncryptionAlgorithmTypeNone, } } @@ -221,50 +238,65 @@ func PossibleExpiryOptionsValues() []ExpiryOptions { } } +type FilterBlobsIncludeItem string + +const ( + FilterBlobsIncludeItemNone FilterBlobsIncludeItem = "none" + FilterBlobsIncludeItemVersions FilterBlobsIncludeItem = "versions" +) + +// PossibleFilterBlobsIncludeItemValues returns the possible values for the FilterBlobsIncludeItem const type. +func PossibleFilterBlobsIncludeItemValues() []FilterBlobsIncludeItem { + return []FilterBlobsIncludeItem{ + FilterBlobsIncludeItemNone, + FilterBlobsIncludeItemVersions, + } +} + type ImmutabilityPolicyMode string const ( + ImmutabilityPolicyModeLocked ImmutabilityPolicyMode = "Locked" ImmutabilityPolicyModeMutable ImmutabilityPolicyMode = "Mutable" ImmutabilityPolicyModeUnlocked ImmutabilityPolicyMode = "Unlocked" - ImmutabilityPolicyModeLocked ImmutabilityPolicyMode = "Locked" ) // PossibleImmutabilityPolicyModeValues returns the possible values for the ImmutabilityPolicyMode const type. func PossibleImmutabilityPolicyModeValues() []ImmutabilityPolicyMode { return []ImmutabilityPolicyMode{ + ImmutabilityPolicyModeLocked, ImmutabilityPolicyModeMutable, ImmutabilityPolicyModeUnlocked, - ImmutabilityPolicyModeLocked, } } type ImmutabilityPolicySetting string const ( - ImmutabilityPolicySettingUnlocked ImmutabilityPolicySetting = "Unlocked" ImmutabilityPolicySettingLocked ImmutabilityPolicySetting = "Locked" + ImmutabilityPolicySettingUnlocked ImmutabilityPolicySetting = "Unlocked" ) // PossibleImmutabilityPolicySettingValues returns the possible values for the ImmutabilityPolicySetting const type. func PossibleImmutabilityPolicySettingValues() []ImmutabilityPolicySetting { return []ImmutabilityPolicySetting{ - ImmutabilityPolicySettingUnlocked, ImmutabilityPolicySettingLocked, + ImmutabilityPolicySettingUnlocked, } } type LeaseDurationType string const ( - LeaseDurationTypeInfinite LeaseDurationType = "infinite" LeaseDurationTypeFixed LeaseDurationType = "fixed" + LeaseDurationTypeInfinite LeaseDurationType = "infinite" ) // PossibleLeaseDurationTypeValues returns the possible values for the LeaseDurationType const type. func PossibleLeaseDurationTypeValues() []LeaseDurationType { return []LeaseDurationType{ - LeaseDurationTypeInfinite, LeaseDurationTypeFixed, + LeaseDurationTypeInfinite, } } @@ -272,20 +304,20 @@ type LeaseStateType string const ( LeaseStateTypeAvailable LeaseStateType = "available" - LeaseStateTypeLeased LeaseStateType = "leased" - LeaseStateTypeExpired LeaseStateType = "expired" LeaseStateTypeBreaking LeaseStateType = "breaking" LeaseStateTypeBroken LeaseStateType = "broken" + LeaseStateTypeExpired LeaseStateType = "expired" + LeaseStateTypeLeased LeaseStateType = "leased" ) // PossibleLeaseStateTypeValues returns the possible values for the LeaseStateType const type. func PossibleLeaseStateTypeValues() []LeaseStateType { return []LeaseStateType{ LeaseStateTypeAvailable, - LeaseStateTypeLeased, - LeaseStateTypeExpired, LeaseStateTypeBreaking, LeaseStateTypeBroken, + LeaseStateTypeExpired, + LeaseStateTypeLeased, } } @@ -309,14 +341,14 @@ type ListBlobsIncludeItem string const ( ListBlobsIncludeItemCopy ListBlobsIncludeItem = "copy" ListBlobsIncludeItemDeleted ListBlobsIncludeItem = "deleted" + ListBlobsIncludeItemDeletedwithversions ListBlobsIncludeItem = "deletedwithversions" + ListBlobsIncludeItemImmutabilitypolicy ListBlobsIncludeItem = "immutabilitypolicy" + ListBlobsIncludeItemLegalhold ListBlobsIncludeItem = "legalhold" ListBlobsIncludeItemMetadata ListBlobsIncludeItem = "metadata" ListBlobsIncludeItemSnapshots ListBlobsIncludeItem = "snapshots" + ListBlobsIncludeItemTags ListBlobsIncludeItem = "tags" ListBlobsIncludeItemUncommittedblobs ListBlobsIncludeItem = "uncommittedblobs" ListBlobsIncludeItemVersions ListBlobsIncludeItem = "versions" - ListBlobsIncludeItemTags ListBlobsIncludeItem = "tags" - ListBlobsIncludeItemImmutabilitypolicy ListBlobsIncludeItem = "immutabilitypolicy" - ListBlobsIncludeItemLegalhold ListBlobsIncludeItem = "legalhold" - ListBlobsIncludeItemDeletedwithversions ListBlobsIncludeItem = "deletedwithversions" ) // PossibleListBlobsIncludeItemValues returns the possible values for the ListBlobsIncludeItem const type. @@ -324,30 +356,30 @@ func PossibleListBlobsIncludeItemValues() []ListBlobsIncludeItem { return []ListBlobsIncludeItem{ ListBlobsIncludeItemCopy, ListBlobsIncludeItemDeleted, + ListBlobsIncludeItemDeletedwithversions, + ListBlobsIncludeItemImmutabilitypolicy, + ListBlobsIncludeItemLegalhold, ListBlobsIncludeItemMetadata, ListBlobsIncludeItemSnapshots, + ListBlobsIncludeItemTags, ListBlobsIncludeItemUncommittedblobs, ListBlobsIncludeItemVersions, - ListBlobsIncludeItemTags, - ListBlobsIncludeItemImmutabilitypolicy, - ListBlobsIncludeItemLegalhold, - ListBlobsIncludeItemDeletedwithversions, } } type ListContainersIncludeType string const ( - ListContainersIncludeTypeMetadata ListContainersIncludeType = "metadata" ListContainersIncludeTypeDeleted ListContainersIncludeType = "deleted" + ListContainersIncludeTypeMetadata ListContainersIncludeType = "metadata" ListContainersIncludeTypeSystem ListContainersIncludeType = "system" ) // PossibleListContainersIncludeTypeValues returns the possible values for the ListContainersIncludeType const type. func PossibleListContainersIncludeTypeValues() []ListContainersIncludeType { return []ListContainersIncludeType{ - ListContainersIncludeTypeMetadata, ListContainersIncludeTypeDeleted, + ListContainersIncludeTypeMetadata, ListContainersIncludeTypeSystem, } } @@ -404,18 +436,18 @@ func PossiblePublicAccessTypeValues() []PublicAccessType { type QueryFormatType string const ( + QueryFormatTypeArrow QueryFormatType = "arrow" QueryFormatTypeDelimited QueryFormatType = "delimited" QueryFormatTypeJSON QueryFormatType = "json" - QueryFormatTypeArrow QueryFormatType = "arrow" QueryFormatTypeParquet QueryFormatType = "parquet" ) // PossibleQueryFormatTypeValues returns the possible values for the QueryFormatType const type. func PossibleQueryFormatTypeValues() []QueryFormatType { return []QueryFormatType{ + QueryFormatTypeArrow, QueryFormatTypeDelimited, QueryFormatTypeJSON, - QueryFormatTypeArrow, QueryFormatTypeParquet, } } @@ -440,38 +472,38 @@ func PossibleRehydratePriorityValues() []RehydratePriority { type SKUName string const ( - SKUNameStandardLRS SKUName = "Standard_LRS" + SKUNamePremiumLRS SKUName = "Premium_LRS" SKUNameStandardGRS SKUName = "Standard_GRS" + SKUNameStandardLRS SKUName = "Standard_LRS" SKUNameStandardRAGRS SKUName = "Standard_RAGRS" SKUNameStandardZRS SKUName = "Standard_ZRS" - SKUNamePremiumLRS SKUName = "Premium_LRS" ) // PossibleSKUNameValues returns the possible values for the SKUName const type. func PossibleSKUNameValues() []SKUName { return []SKUName{ - SKUNameStandardLRS, + SKUNamePremiumLRS, SKUNameStandardGRS, + SKUNameStandardLRS, SKUNameStandardRAGRS, SKUNameStandardZRS, - SKUNamePremiumLRS, } } type SequenceNumberActionType string const ( + SequenceNumberActionTypeIncrement SequenceNumberActionType = "increment" SequenceNumberActionTypeMax SequenceNumberActionType = "max" SequenceNumberActionTypeUpdate SequenceNumberActionType = "update" - SequenceNumberActionTypeIncrement SequenceNumberActionType = "increment" ) // PossibleSequenceNumberActionTypeValues returns the possible values for the SequenceNumberActionType const type. func PossibleSequenceNumberActionTypeValues() []SequenceNumberActionType { return []SequenceNumberActionType{ + SequenceNumberActionTypeIncrement, SequenceNumberActionTypeMax, SequenceNumberActionTypeUpdate, - SequenceNumberActionTypeIncrement, } } diff --git a/sdk/storage/azblob/internal/generated/zz_container_client.go b/sdk/storage/azblob/internal/generated/zz_container_client.go index 5fcac5135f53..8942fd6a5b10 100644 --- a/sdk/storage/azblob/internal/generated/zz_container_client.go +++ b/sdk/storage/azblob/internal/generated/zz_container_client.go @@ -25,28 +25,17 @@ import ( ) // ContainerClient contains the methods for the Container group. -// Don't use this type directly, use NewContainerClient() instead. +// Don't use this type directly, use a constructor function instead. type ContainerClient struct { + internal *azcore.Client endpoint string - pl runtime.Pipeline -} - -// NewContainerClient creates a new instance of ContainerClient with the specified values. -// - endpoint - The URL of the service account, container, or blob that is the target of the desired operation. -// - pl - the pipeline used for sending requests and handling responses. -func NewContainerClient(endpoint string, pl runtime.Pipeline) *ContainerClient { - client := &ContainerClient{ - endpoint: endpoint, - pl: pl, - } - return client } // AcquireLease - [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 // to 60 seconds, or can be infinite // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - duration - Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite // lease can be between 15 and 60 seconds. A lease duration cannot be changed using // renew or change. @@ -57,7 +46,7 @@ func (client *ContainerClient) AcquireLease(ctx context.Context, duration int32, if err != nil { return ContainerClientAcquireLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientAcquireLeaseResponse{}, err } @@ -91,7 +80,7 @@ func (client *ContainerClient) acquireLeaseCreateRequest(ctx context.Context, du if modifiedAccessConditions != nil && modifiedAccessConditions.IfUnmodifiedSince != nil { req.Raw().Header["If-Unmodified-Since"] = []string{(*modifiedAccessConditions.IfUnmodifiedSince).In(gmt).Format(time.RFC1123)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -138,7 +127,7 @@ func (client *ContainerClient) acquireLeaseHandleResponse(resp *http.Response) ( // to 60 seconds, or can be infinite // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - ContainerClientBreakLeaseOptions contains the optional parameters for the ContainerClient.BreakLease method. // - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method. func (client *ContainerClient) BreakLease(ctx context.Context, options *ContainerClientBreakLeaseOptions, modifiedAccessConditions *ModifiedAccessConditions) (ContainerClientBreakLeaseResponse, error) { @@ -146,7 +135,7 @@ func (client *ContainerClient) BreakLease(ctx context.Context, options *Containe if err != nil { return ContainerClientBreakLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientBreakLeaseResponse{}, err } @@ -179,7 +168,7 @@ func (client *ContainerClient) breakLeaseCreateRequest(ctx context.Context, opti if modifiedAccessConditions != nil && modifiedAccessConditions.IfUnmodifiedSince != nil { req.Raw().Header["If-Unmodified-Since"] = []string{(*modifiedAccessConditions.IfUnmodifiedSince).In(gmt).Format(time.RFC1123)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -231,7 +220,7 @@ func (client *ContainerClient) breakLeaseHandleResponse(resp *http.Response) (Co // to 60 seconds, or can be infinite // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - leaseID - Specifies the current lease ID on the resource. // - proposedLeaseID - Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the proposed // lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID @@ -243,7 +232,7 @@ func (client *ContainerClient) ChangeLease(ctx context.Context, leaseID string, if err != nil { return ContainerClientChangeLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientChangeLeaseResponse{}, err } @@ -275,7 +264,7 @@ func (client *ContainerClient) changeLeaseCreateRequest(ctx context.Context, lea if modifiedAccessConditions != nil && modifiedAccessConditions.IfUnmodifiedSince != nil { req.Raw().Header["If-Unmodified-Since"] = []string{(*modifiedAccessConditions.IfUnmodifiedSince).In(gmt).Format(time.RFC1123)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -322,7 +311,7 @@ func (client *ContainerClient) changeLeaseHandleResponse(resp *http.Response) (C // fails // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - ContainerClientCreateOptions contains the optional parameters for the ContainerClient.Create method. // - ContainerCPKScopeInfo - ContainerCPKScopeInfo contains a group of parameters for the ContainerClient.Create method. func (client *ContainerClient) Create(ctx context.Context, options *ContainerClientCreateOptions, containerCPKScopeInfo *ContainerCPKScopeInfo) (ContainerClientCreateResponse, error) { @@ -330,7 +319,7 @@ func (client *ContainerClient) Create(ctx context.Context, options *ContainerCli if err != nil { return ContainerClientCreateResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientCreateResponse{}, err } @@ -362,7 +351,7 @@ func (client *ContainerClient) createCreateRequest(ctx context.Context, options if options != nil && options.Access != nil { req.Raw().Header["x-ms-blob-public-access"] = []string{string(*options.Access)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -412,7 +401,7 @@ func (client *ContainerClient) createHandleResponse(resp *http.Response) (Contai // deleted during garbage collection // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - ContainerClientDeleteOptions contains the optional parameters for the ContainerClient.Delete method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. // - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method. @@ -421,7 +410,7 @@ func (client *ContainerClient) Delete(ctx context.Context, options *ContainerCli if err != nil { return ContainerClientDeleteResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientDeleteResponse{}, err } @@ -452,7 +441,7 @@ func (client *ContainerClient) deleteCreateRequest(ctx context.Context, options if modifiedAccessConditions != nil && modifiedAccessConditions.IfUnmodifiedSince != nil { req.Raw().Header["If-Unmodified-Since"] = []string{(*modifiedAccessConditions.IfUnmodifiedSince).In(gmt).Format(time.RFC1123)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -482,11 +471,89 @@ func (client *ContainerClient) deleteHandleResponse(resp *http.Response) (Contai return result, nil } +// FilterBlobs - The Filter Blobs operation enables callers to list blobs in a container whose tags match a given search expression. +// Filter blobs searches within the given container. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2021-12-02 +// - where - Filters the results to return only to return only blobs whose tags match the specified expression. +// - options - ContainerClientFilterBlobsOptions contains the optional parameters for the ContainerClient.FilterBlobs method. +func (client *ContainerClient) FilterBlobs(ctx context.Context, where string, options *ContainerClientFilterBlobsOptions) (ContainerClientFilterBlobsResponse, error) { + req, err := client.filterBlobsCreateRequest(ctx, where, options) + if err != nil { + return ContainerClientFilterBlobsResponse{}, err + } + resp, err := client.internal.Pipeline().Do(req) + if err != nil { + return ContainerClientFilterBlobsResponse{}, err + } + if !runtime.HasStatusCode(resp, http.StatusOK) { + return ContainerClientFilterBlobsResponse{}, runtime.NewResponseError(resp) + } + return client.filterBlobsHandleResponse(resp) +} + +// filterBlobsCreateRequest creates the FilterBlobs request. +func (client *ContainerClient) filterBlobsCreateRequest(ctx context.Context, where string, options *ContainerClientFilterBlobsOptions) (*policy.Request, error) { + req, err := runtime.NewRequest(ctx, http.MethodGet, client.endpoint) + if err != nil { + return nil, err + } + reqQP := req.Raw().URL.Query() + reqQP.Set("restype", "container") + reqQP.Set("comp", "blobs") + if options != nil && options.Timeout != nil { + reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) + } + reqQP.Set("where", where) + if options != nil && options.Marker != nil { + reqQP.Set("marker", *options.Marker) + } + if options != nil && options.Maxresults != nil { + reqQP.Set("maxresults", strconv.FormatInt(int64(*options.Maxresults), 10)) + } + if options != nil && options.Include != nil { + reqQP.Set("include", strings.Join(strings.Fields(strings.Trim(fmt.Sprint(options.Include), "[]")), ",")) + } + req.Raw().URL.RawQuery = reqQP.Encode() + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} + if options != nil && options.RequestID != nil { + req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} + } + req.Raw().Header["Accept"] = []string{"application/xml"} + return req, nil +} + +// filterBlobsHandleResponse handles the FilterBlobs response. +func (client *ContainerClient) filterBlobsHandleResponse(resp *http.Response) (ContainerClientFilterBlobsResponse, error) { + result := ContainerClientFilterBlobsResponse{} + if val := resp.Header.Get("x-ms-client-request-id"); val != "" { + result.ClientRequestID = &val + } + if val := resp.Header.Get("x-ms-request-id"); val != "" { + result.RequestID = &val + } + if val := resp.Header.Get("x-ms-version"); val != "" { + result.Version = &val + } + if val := resp.Header.Get("Date"); val != "" { + date, err := time.Parse(time.RFC1123, val) + if err != nil { + return ContainerClientFilterBlobsResponse{}, err + } + result.Date = &date + } + if err := runtime.UnmarshalAsXML(resp, &result.FilterBlobSegment); err != nil { + return ContainerClientFilterBlobsResponse{}, err + } + return result, nil +} + // GetAccessPolicy - gets the permissions for the specified container. The permissions indicate whether container data may // be accessed publicly. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - ContainerClientGetAccessPolicyOptions contains the optional parameters for the ContainerClient.GetAccessPolicy // method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. @@ -495,7 +562,7 @@ func (client *ContainerClient) GetAccessPolicy(ctx context.Context, options *Con if err != nil { return ContainerClientGetAccessPolicyResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientGetAccessPolicyResponse{}, err } @@ -521,7 +588,7 @@ func (client *ContainerClient) getAccessPolicyCreateRequest(ctx context.Context, if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -570,7 +637,7 @@ func (client *ContainerClient) getAccessPolicyHandleResponse(resp *http.Response // GetAccountInfo - Returns the sku name and account kind // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - ContainerClientGetAccountInfoOptions contains the optional parameters for the ContainerClient.GetAccountInfo // method. func (client *ContainerClient) GetAccountInfo(ctx context.Context, options *ContainerClientGetAccountInfoOptions) (ContainerClientGetAccountInfoResponse, error) { @@ -578,7 +645,7 @@ func (client *ContainerClient) GetAccountInfo(ctx context.Context, options *Cont if err != nil { return ContainerClientGetAccountInfoResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientGetAccountInfoResponse{}, err } @@ -598,7 +665,7 @@ func (client *ContainerClient) getAccountInfoCreateRequest(ctx context.Context, reqQP.Set("restype", "account") reqQP.Set("comp", "properties") req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -635,7 +702,7 @@ func (client *ContainerClient) getAccountInfoHandleResponse(resp *http.Response) // does not include the container's list of blobs // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - ContainerClientGetPropertiesOptions contains the optional parameters for the ContainerClient.GetProperties method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. func (client *ContainerClient) GetProperties(ctx context.Context, options *ContainerClientGetPropertiesOptions, leaseAccessConditions *LeaseAccessConditions) (ContainerClientGetPropertiesResponse, error) { @@ -643,7 +710,7 @@ func (client *ContainerClient) GetProperties(ctx context.Context, options *Conta if err != nil { return ContainerClientGetPropertiesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientGetPropertiesResponse{}, err } @@ -668,7 +735,7 @@ func (client *ContainerClient) getPropertiesCreateRequest(ctx context.Context, o if leaseAccessConditions != nil && leaseAccessConditions.LeaseID != nil { req.Raw().Header["x-ms-lease-id"] = []string{*leaseAccessConditions.LeaseID} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -761,7 +828,7 @@ func (client *ContainerClient) getPropertiesHandleResponse(resp *http.Response) // NewListBlobFlatSegmentPager - [Update] The List Blobs operation returns a list of the blobs under the specified container // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - ContainerClientListBlobFlatSegmentOptions contains the optional parameters for the ContainerClient.NewListBlobFlatSegmentPager // method. // @@ -790,7 +857,7 @@ func (client *ContainerClient) ListBlobFlatSegmentCreateRequest(ctx context.Cont reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -828,7 +895,7 @@ func (client *ContainerClient) ListBlobFlatSegmentHandleResponse(resp *http.Resp // NewListBlobHierarchySegmentPager - [Update] The List Blobs operation returns a list of the blobs under the specified container // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - delimiter - When the request includes this parameter, the operation returns a BlobPrefix element in the response body that // acts as a placeholder for all blobs whose names begin with the same substring up to the // appearance of the delimiter character. The delimiter may be a single character or a string. @@ -850,7 +917,7 @@ func (client *ContainerClient) NewListBlobHierarchySegmentPager(delimiter string if err != nil { return ContainerClientListBlobHierarchySegmentResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientListBlobHierarchySegmentResponse{}, err } @@ -888,7 +955,7 @@ func (client *ContainerClient) ListBlobHierarchySegmentCreateRequest(ctx context reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -928,7 +995,7 @@ func (client *ContainerClient) ListBlobHierarchySegmentHandleResponse(resp *http // to 60 seconds, or can be infinite // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - leaseID - Specifies the current lease ID on the resource. // - options - ContainerClientReleaseLeaseOptions contains the optional parameters for the ContainerClient.ReleaseLease method. // - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method. @@ -937,7 +1004,7 @@ func (client *ContainerClient) ReleaseLease(ctx context.Context, leaseID string, if err != nil { return ContainerClientReleaseLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientReleaseLeaseResponse{}, err } @@ -968,7 +1035,7 @@ func (client *ContainerClient) releaseLeaseCreateRequest(ctx context.Context, le if modifiedAccessConditions != nil && modifiedAccessConditions.IfUnmodifiedSince != nil { req.Raw().Header["If-Unmodified-Since"] = []string{(*modifiedAccessConditions.IfUnmodifiedSince).In(gmt).Format(time.RFC1123)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -1011,7 +1078,7 @@ func (client *ContainerClient) releaseLeaseHandleResponse(resp *http.Response) ( // Rename - Renames an existing container. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - sourceContainerName - Required. Specifies the name of the container to rename. // - options - ContainerClientRenameOptions contains the optional parameters for the ContainerClient.Rename method. func (client *ContainerClient) Rename(ctx context.Context, sourceContainerName string, options *ContainerClientRenameOptions) (ContainerClientRenameResponse, error) { @@ -1019,7 +1086,7 @@ func (client *ContainerClient) Rename(ctx context.Context, sourceContainerName s if err != nil { return ContainerClientRenameResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientRenameResponse{}, err } @@ -1042,7 +1109,7 @@ func (client *ContainerClient) renameCreateRequest(ctx context.Context, sourceCo reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -1080,7 +1147,7 @@ func (client *ContainerClient) renameHandleResponse(resp *http.Response) (Contai // to 60 seconds, or can be infinite // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - leaseID - Specifies the current lease ID on the resource. // - options - ContainerClientRenewLeaseOptions contains the optional parameters for the ContainerClient.RenewLease method. // - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method. @@ -1089,7 +1156,7 @@ func (client *ContainerClient) RenewLease(ctx context.Context, leaseID string, o if err != nil { return ContainerClientRenewLeaseResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientRenewLeaseResponse{}, err } @@ -1120,7 +1187,7 @@ func (client *ContainerClient) renewLeaseCreateRequest(ctx context.Context, leas if modifiedAccessConditions != nil && modifiedAccessConditions.IfUnmodifiedSince != nil { req.Raw().Header["If-Unmodified-Since"] = []string{(*modifiedAccessConditions.IfUnmodifiedSince).In(gmt).Format(time.RFC1123)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -1166,14 +1233,14 @@ func (client *ContainerClient) renewLeaseHandleResponse(resp *http.Response) (Co // Restore - Restores a previously-deleted container. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - ContainerClientRestoreOptions contains the optional parameters for the ContainerClient.Restore method. func (client *ContainerClient) Restore(ctx context.Context, options *ContainerClientRestoreOptions) (ContainerClientRestoreResponse, error) { req, err := client.restoreCreateRequest(ctx, options) if err != nil { return ContainerClientRestoreResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientRestoreResponse{}, err } @@ -1196,7 +1263,7 @@ func (client *ContainerClient) restoreCreateRequest(ctx context.Context, options reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -1236,7 +1303,7 @@ func (client *ContainerClient) restoreHandleResponse(resp *http.Response) (Conta // may be accessed publicly. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - containerACL - the acls for the container // - options - ContainerClientSetAccessPolicyOptions contains the optional parameters for the ContainerClient.SetAccessPolicy // method. @@ -1247,7 +1314,7 @@ func (client *ContainerClient) SetAccessPolicy(ctx context.Context, containerACL if err != nil { return ContainerClientSetAccessPolicyResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientSetAccessPolicyResponse{}, err } @@ -1282,7 +1349,7 @@ func (client *ContainerClient) setAccessPolicyCreateRequest(ctx context.Context, if modifiedAccessConditions != nil && modifiedAccessConditions.IfUnmodifiedSince != nil { req.Raw().Header["If-Unmodified-Since"] = []string{(*modifiedAccessConditions.IfUnmodifiedSince).In(gmt).Format(time.RFC1123)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -1291,7 +1358,10 @@ func (client *ContainerClient) setAccessPolicyCreateRequest(ctx context.Context, XMLName xml.Name `xml:"SignedIdentifiers"` ContainerACL *[]*SignedIdentifier `xml:"SignedIdentifier"` } - return req, runtime.MarshalAsXML(req, wrapper{ContainerACL: &containerACL}) + if err := runtime.MarshalAsXML(req, wrapper{ContainerACL: &containerACL}); err != nil { + return nil, err + } + return req, nil } // setAccessPolicyHandleResponse handles the SetAccessPolicy response. @@ -1329,7 +1399,7 @@ func (client *ContainerClient) setAccessPolicyHandleResponse(resp *http.Response // SetMetadata - operation sets one or more user-defined name-value pairs for the specified container. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - ContainerClientSetMetadataOptions contains the optional parameters for the ContainerClient.SetMetadata method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. // - ModifiedAccessConditions - ModifiedAccessConditions contains a group of parameters for the ContainerClient.Delete method. @@ -1338,7 +1408,7 @@ func (client *ContainerClient) SetMetadata(ctx context.Context, options *Contain if err != nil { return ContainerClientSetMetadataResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientSetMetadataResponse{}, err } @@ -1374,7 +1444,7 @@ func (client *ContainerClient) setMetadataCreateRequest(ctx context.Context, opt if modifiedAccessConditions != nil && modifiedAccessConditions.IfModifiedSince != nil { req.Raw().Header["If-Modified-Since"] = []string{(*modifiedAccessConditions.IfModifiedSince).In(gmt).Format(time.RFC1123)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -1417,7 +1487,7 @@ func (client *ContainerClient) setMetadataHandleResponse(resp *http.Response) (C // SubmitBatch - The Batch operation allows multiple API calls to be embedded into a single HTTP request. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - contentLength - The length of the request. // - multipartContentType - Required. The value of this header must be multipart/mixed with a batch boundary. Example header // value: multipart/mixed; boundary=batch_ @@ -1428,7 +1498,7 @@ func (client *ContainerClient) SubmitBatch(ctx context.Context, contentLength in if err != nil { return ContainerClientSubmitBatchResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ContainerClientSubmitBatchResponse{}, err } @@ -1454,12 +1524,15 @@ func (client *ContainerClient) submitBatchCreateRequest(ctx context.Context, con runtime.SkipBodyDownload(req) req.Raw().Header["Content-Length"] = []string{strconv.FormatInt(contentLength, 10)} req.Raw().Header["Content-Type"] = []string{multipartContentType} - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } req.Raw().Header["Accept"] = []string{"application/xml"} - return req, req.SetBody(body, multipartContentType) + if err := req.SetBody(body, multipartContentType); err != nil { + return nil, err + } + return req, nil } // submitBatchHandleResponse handles the SubmitBatch response. diff --git a/sdk/storage/azblob/internal/generated/zz_models.go b/sdk/storage/azblob/internal/generated/zz_models.go index 022807f53c5f..1fed5f630bd0 100644 --- a/sdk/storage/azblob/internal/generated/zz_models.go +++ b/sdk/storage/azblob/internal/generated/zz_models.go @@ -181,6 +181,8 @@ type BlobClientCopyFromURLOptions struct { BlobTagsString *string // Only Bearer type is supported. Credentials should be a valid OAuth access token to copy source. CopySourceAuthorization *string + // Optional, default 'replace'. Indicates if source tags should be copied or replaced with the tags specified by x-ms-tags. + CopySourceTags *BlobCopySourceTags // Specifies the date time when the blobs immutability policy is set to expire. ImmutabilityPolicyExpiry *time.Time // Specifies the immutability policy mode to set on the blob. @@ -554,6 +556,14 @@ type BlobItem struct { VersionID *string `xml:"VersionId"` } +type BlobName struct { + // The name of the blob. + Content *string `xml:",chardata"` + + // Indicates if the blob name is encoded. + Encoded *bool `xml:"Encoded,attr"` +} + type BlobPrefix struct { // REQUIRED Name *string `xml:"Name"` @@ -689,6 +699,8 @@ type BlockBlobClientPutBlobFromURLOptions struct { CopySourceAuthorization *string // Optional, default is true. Indicates if properties from the source blob should be copied. CopySourceBlobProperties *bool + // Optional, default 'replace'. Indicates if source tags should be copied or replaced with the tags specified by x-ms-tags. + CopySourceTags *BlobCopySourceTags // Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the // operation will copy the metadata from the source blob or file to the destination // blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata, and metadata @@ -767,6 +779,8 @@ type BlockBlobClientUploadOptions struct { // The timeout parameter is expressed in seconds. For more information, see Setting Timeouts for Blob Service Operations. // [https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations] Timeout *int32 + // Specify the transactional crc64 for the body, to be validated by the service. + TransactionalContentCRC64 []byte // Specify the transactional md5 for the body, to be validated by the service. TransactionalContentMD5 []byte } @@ -860,6 +874,30 @@ type ContainerClientDeleteOptions struct { Timeout *int32 } +// ContainerClientFilterBlobsOptions contains the optional parameters for the ContainerClient.FilterBlobs method. +type ContainerClientFilterBlobsOptions struct { + // Include this parameter to specify one or more datasets to include in the response. + Include []FilterBlobsIncludeItem + // A string value that identifies the portion of the list of containers to be returned with the next listing operation. The + // operation returns the NextMarker value within the response body if the listing + // operation did not return all containers remaining to be listed with the current page. The NextMarker value can be used + // as the value for the marker parameter in a subsequent call to request the next + // page of list items. The marker value is opaque to the client. + Marker *string + // Specifies the maximum number of containers to return. If the request does not specify maxresults, or specifies a value + // greater than 5000, the server will return up to 5000 items. Note that if the + // listing operation crosses a partition boundary, then the service will return a continuation token for retrieving the remainder + // of the results. For this reason, it is possible that the service will + // return fewer results than specified by maxresults, or than the default of 5000. + Maxresults *int32 + // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage + // analytics logging is enabled. + RequestID *string + // The timeout parameter is expressed in seconds. For more information, see Setting Timeouts for Blob Service Operations. + // [https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations] + Timeout *int32 +} + // ContainerClientGetAccessPolicyOptions contains the optional parameters for the ContainerClient.GetAccessPolicy method. type ContainerClientGetAccessPolicyOptions struct { // Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage @@ -1140,10 +1178,12 @@ type FilterBlobItem struct { ContainerName *string `xml:"ContainerName"` // REQUIRED - Name *string `xml:"Name"` + Name *string `xml:"Name"` + IsCurrentVersion *bool `xml:"IsCurrentVersion"` // Blob tags - Tags *BlobTags `xml:"Tags"` + Tags *BlobTags `xml:"Tags"` + VersionID *string `xml:"VersionId"` } // FilterBlobSegment - The result of a Filter Blobs API call @@ -1533,6 +1573,8 @@ type SequenceNumberAccessConditions struct { // ServiceClientFilterBlobsOptions contains the optional parameters for the ServiceClient.FilterBlobs method. type ServiceClientFilterBlobsOptions struct { + // Include this parameter to specify one or more datasets to include in the response. + Include []FilterBlobsIncludeItem // A string value that identifies the portion of the list of containers to be returned with the next listing operation. The // operation returns the NextMarker value within the response body if the listing // operation did not return all containers remaining to be listed with the current page. The NextMarker value can be used @@ -1674,7 +1716,7 @@ type StaticWebsite struct { } type StorageError struct { - Message *string `json:"Message,omitempty"` + Message *string } // StorageServiceProperties - Storage Service Properties. diff --git a/sdk/storage/azblob/internal/generated/zz_models_serde.go b/sdk/storage/azblob/internal/generated/zz_models_serde.go index e5b6cda2b913..dc5dba1037a5 100644 --- a/sdk/storage/azblob/internal/generated/zz_models_serde.go +++ b/sdk/storage/azblob/internal/generated/zz_models_serde.go @@ -101,24 +101,6 @@ func (b BlobHierarchyListSegment) MarshalXML(enc *xml.Encoder, start xml.StartEl return enc.EncodeElement(aux, start) } -// UnmarshalXML implements the xml.Unmarshaller interface for type BlobItem. -func (b *BlobItem) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error { - type alias BlobItem - aux := &struct { - *alias - Metadata additionalProperties `xml:"Metadata"` - OrMetadata additionalProperties `xml:"OrMetadata"` - }{ - alias: (*alias)(b), - } - if err := dec.DecodeElement(aux, &start); err != nil { - return err - } - b.Metadata = (map[string]*string)(aux.Metadata) - b.OrMetadata = (map[string]*string)(aux.OrMetadata) - return nil -} - // MarshalXML implements the xml.Marshaller interface for type BlobProperties. func (b BlobProperties) MarshalXML(enc *xml.Encoder, start xml.StartElement) error { type alias BlobProperties @@ -470,6 +452,16 @@ func populate(m map[string]any, k string, v any) { } } +func populateAny(m map[string]any, k string, v any) { + if v == nil { + return + } else if azcore.IsNullValue(v) { + m[k] = nil + } else { + m[k] = v + } +} + func unpopulate(data json.RawMessage, fn string, v any) error { if data == nil { return nil diff --git a/sdk/storage/azblob/internal/generated/zz_pageblob_client.go b/sdk/storage/azblob/internal/generated/zz_pageblob_client.go index b209e99f0232..9fd39f0c9630 100644 --- a/sdk/storage/azblob/internal/generated/zz_pageblob_client.go +++ b/sdk/storage/azblob/internal/generated/zz_pageblob_client.go @@ -22,27 +22,16 @@ import ( ) // PageBlobClient contains the methods for the PageBlob group. -// Don't use this type directly, use NewPageBlobClient() instead. +// Don't use this type directly, use a constructor function instead. type PageBlobClient struct { + internal *azcore.Client endpoint string - pl runtime.Pipeline -} - -// NewPageBlobClient creates a new instance of PageBlobClient with the specified values. -// - endpoint - The URL of the service account, container, or blob that is the target of the desired operation. -// - pl - the pipeline used for sending requests and handling responses. -func NewPageBlobClient(endpoint string, pl runtime.Pipeline) *PageBlobClient { - client := &PageBlobClient{ - endpoint: endpoint, - pl: pl, - } - return client } // ClearPages - The Clear Pages operation clears a set of pages from a page blob // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - contentLength - The length of the request. // - options - PageBlobClientClearPagesOptions contains the optional parameters for the PageBlobClient.ClearPages method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. @@ -56,7 +45,7 @@ func (client *PageBlobClient) ClearPages(ctx context.Context, contentLength int6 if err != nil { return PageBlobClientClearPagesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return PageBlobClientClearPagesResponse{}, err } @@ -122,7 +111,7 @@ func (client *PageBlobClient) clearPagesCreateRequest(ctx context.Context, conte if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -190,7 +179,7 @@ func (client *PageBlobClient) clearPagesHandleResponse(resp *http.Response) (Pag // 2016-05-31. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - copySource - Specifies the name of the source page blob snapshot. This value is a URL of up to 2 KB in length that specifies // a page blob snapshot. The value should be URL-encoded as it would appear in a request // URI. The source blob must either be public or must be authenticated via a shared access signature. @@ -202,7 +191,7 @@ func (client *PageBlobClient) CopyIncremental(ctx context.Context, copySource st if err != nil { return PageBlobClientCopyIncrementalResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return PageBlobClientCopyIncrementalResponse{}, err } @@ -240,7 +229,7 @@ func (client *PageBlobClient) copyIncrementalCreateRequest(ctx context.Context, req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } req.Raw().Header["x-ms-copy-source"] = []string{copySource} - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -289,7 +278,7 @@ func (client *PageBlobClient) copyIncrementalHandleResponse(resp *http.Response) // Create - The Create operation creates a new page blob. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - contentLength - The length of the request. // - blobContentLength - This header specifies the maximum size for the page blob, up to 1 TB. The page blob size must be aligned // to a 512-byte boundary. @@ -304,7 +293,7 @@ func (client *PageBlobClient) Create(ctx context.Context, contentLength int64, b if err != nil { return PageBlobClientCreateResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return PageBlobClientCreateResponse{}, err } @@ -389,7 +378,7 @@ func (client *PageBlobClient) createCreateRequest(ctx context.Context, contentLe if options != nil && options.BlobSequenceNumber != nil { req.Raw().Header["x-ms-blob-sequence-number"] = []string{strconv.FormatInt(*options.BlobSequenceNumber, 10)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -467,7 +456,7 @@ func (client *PageBlobClient) createHandleResponse(resp *http.Response) (PageBlo // NewGetPageRangesPager - The Get Page Ranges operation returns the list of valid page ranges for a page blob or snapshot // of a page blob // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - PageBlobClientGetPageRangesOptions contains the optional parameters for the PageBlobClient.NewGetPageRangesPager // method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. @@ -488,7 +477,7 @@ func (client *PageBlobClient) NewGetPageRangesPager(options *PageBlobClientGetPa if err != nil { return PageBlobClientGetPageRangesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return PageBlobClientGetPageRangesResponse{}, err } @@ -542,7 +531,7 @@ func (client *PageBlobClient) GetPageRangesCreateRequest(ctx context.Context, op if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -595,7 +584,7 @@ func (client *PageBlobClient) GetPageRangesHandleResponse(resp *http.Response) ( // NewGetPageRangesDiffPager - The Get Page Ranges Diff operation returns the list of valid page ranges for a page blob that // were changed between target blob and previous snapshot. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - PageBlobClientGetPageRangesDiffOptions contains the optional parameters for the PageBlobClient.NewGetPageRangesDiffPager // method. // - LeaseAccessConditions - LeaseAccessConditions contains a group of parameters for the ContainerClient.GetProperties method. @@ -616,7 +605,7 @@ func (client *PageBlobClient) NewGetPageRangesDiffPager(options *PageBlobClientG if err != nil { return PageBlobClientGetPageRangesDiffResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return PageBlobClientGetPageRangesDiffResponse{}, err } @@ -676,7 +665,7 @@ func (client *PageBlobClient) GetPageRangesDiffCreateRequest(ctx context.Context if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -729,7 +718,7 @@ func (client *PageBlobClient) GetPageRangesDiffHandleResponse(resp *http.Respons // Resize - Resize the Blob // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - blobContentLength - This header specifies the maximum size for the page blob, up to 1 TB. The page blob size must be aligned // to a 512-byte boundary. // - options - PageBlobClientResizeOptions contains the optional parameters for the PageBlobClient.Resize method. @@ -742,7 +731,7 @@ func (client *PageBlobClient) Resize(ctx context.Context, blobContentLength int6 if err != nil { return PageBlobClientResizeResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return PageBlobClientResizeResponse{}, err } @@ -795,7 +784,7 @@ func (client *PageBlobClient) resizeCreateRequest(ctx context.Context, blobConte req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } req.Raw().Header["x-ms-blob-content-length"] = []string{strconv.FormatInt(blobContentLength, 10)} - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -845,7 +834,7 @@ func (client *PageBlobClient) resizeHandleResponse(resp *http.Response) (PageBlo // UpdateSequenceNumber - Update the sequence number of the blob // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - sequenceNumberAction - Required if the x-ms-blob-sequence-number header is set for the request. This property applies to // page blobs only. This property indicates how the service should modify the blob's sequence number // - options - PageBlobClientUpdateSequenceNumberOptions contains the optional parameters for the PageBlobClient.UpdateSequenceNumber @@ -857,7 +846,7 @@ func (client *PageBlobClient) UpdateSequenceNumber(ctx context.Context, sequence if err != nil { return PageBlobClientUpdateSequenceNumberResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return PageBlobClientUpdateSequenceNumberResponse{}, err } @@ -901,7 +890,7 @@ func (client *PageBlobClient) updateSequenceNumberCreateRequest(ctx context.Cont if options != nil && options.BlobSequenceNumber != nil { req.Raw().Header["x-ms-blob-sequence-number"] = []string{strconv.FormatInt(*options.BlobSequenceNumber, 10)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -951,7 +940,7 @@ func (client *PageBlobClient) updateSequenceNumberHandleResponse(resp *http.Resp // UploadPages - The Upload Pages operation writes a range of pages to a page blob // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - contentLength - The length of the request. // - body - Initial data // - options - PageBlobClientUploadPagesOptions contains the optional parameters for the PageBlobClient.UploadPages method. @@ -966,7 +955,7 @@ func (client *PageBlobClient) UploadPages(ctx context.Context, contentLength int if err != nil { return PageBlobClientUploadPagesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return PageBlobClientUploadPagesResponse{}, err } @@ -1038,12 +1027,15 @@ func (client *PageBlobClient) uploadPagesCreateRequest(ctx context.Context, cont if modifiedAccessConditions != nil && modifiedAccessConditions.IfTags != nil { req.Raw().Header["x-ms-if-tags"] = []string{*modifiedAccessConditions.IfTags} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } req.Raw().Header["Accept"] = []string{"application/xml"} - return req, req.SetBody(body, "application/octet-stream") + if err := req.SetBody(body, "application/octet-stream"); err != nil { + return nil, err + } + return req, nil } // uploadPagesHandleResponse handles the UploadPages response. @@ -1116,7 +1108,7 @@ func (client *PageBlobClient) uploadPagesHandleResponse(resp *http.Response) (Pa // a URL // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - sourceURL - Specify a URL to the copy source. // - sourceRange - Bytes of source data in the specified range. The length of this range should match the ContentLength header // and x-ms-range/Range destination range header. @@ -1138,7 +1130,7 @@ func (client *PageBlobClient) UploadPagesFromURL(ctx context.Context, sourceURL if err != nil { return PageBlobClientUploadPagesFromURLResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return PageBlobClientUploadPagesFromURLResponse{}, err } @@ -1222,7 +1214,7 @@ func (client *PageBlobClient) uploadPagesFromURLCreateRequest(ctx context.Contex if sourceModifiedAccessConditions != nil && sourceModifiedAccessConditions.SourceIfNoneMatch != nil { req.Raw().Header["x-ms-source-if-none-match"] = []string{string(*sourceModifiedAccessConditions.SourceIfNoneMatch)} } - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } diff --git a/sdk/storage/azblob/internal/generated/zz_response_types.go b/sdk/storage/azblob/internal/generated/zz_response_types.go index 386c943e4105..625f3133fedc 100644 --- a/sdk/storage/azblob/internal/generated/zz_response_types.go +++ b/sdk/storage/azblob/internal/generated/zz_response_types.go @@ -266,6 +266,9 @@ type BlobClientCopyFromURLResponse struct { // ETag contains the information returned from the ETag header response. ETag *azcore.ETag + // EncryptionScope contains the information returned from the x-ms-encryption-scope header response. + EncryptionScope *string + // LastModified contains the information returned from the Last-Modified header response. LastModified *time.Time @@ -1310,6 +1313,22 @@ type ContainerClientDeleteResponse struct { Version *string } +// ContainerClientFilterBlobsResponse contains the response from method ContainerClient.FilterBlobs. +type ContainerClientFilterBlobsResponse struct { + FilterBlobSegment + // ClientRequestID contains the information returned from the x-ms-client-request-id header response. + ClientRequestID *string `xml:"ClientRequestID"` + + // Date contains the information returned from the Date header response. + Date *time.Time `xml:"Date"` + + // RequestID contains the information returned from the x-ms-request-id header response. + RequestID *string `xml:"RequestID"` + + // Version contains the information returned from the x-ms-version header response. + Version *string `xml:"Version"` +} + // ContainerClientGetAccessPolicyResponse contains the response from method ContainerClient.GetAccessPolicy. type ContainerClientGetAccessPolicyResponse struct { // BlobPublicAccess contains the information returned from the x-ms-blob-public-access header response. diff --git a/sdk/storage/azblob/internal/generated/zz_service_client.go b/sdk/storage/azblob/internal/generated/zz_service_client.go index b700211c5e0d..57c59a684c59 100644 --- a/sdk/storage/azblob/internal/generated/zz_service_client.go +++ b/sdk/storage/azblob/internal/generated/zz_service_client.go @@ -12,6 +12,7 @@ package generated import ( "context" "fmt" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "io" @@ -22,21 +23,10 @@ import ( ) // ServiceClient contains the methods for the Service group. -// Don't use this type directly, use NewServiceClient() instead. +// Don't use this type directly, use a constructor function instead. type ServiceClient struct { + internal *azcore.Client endpoint string - pl runtime.Pipeline -} - -// NewServiceClient creates a new instance of ServiceClient with the specified values. -// - endpoint - The URL of the service account, container, or blob that is the target of the desired operation. -// - pl - the pipeline used for sending requests and handling responses. -func NewServiceClient(endpoint string, pl runtime.Pipeline) *ServiceClient { - client := &ServiceClient{ - endpoint: endpoint, - pl: pl, - } - return client } // FilterBlobs - The Filter Blobs operation enables callers to list blobs across all containers whose tags match a given search @@ -44,7 +34,7 @@ func NewServiceClient(endpoint string, pl runtime.Pipeline) *ServiceClient { // be scoped within the expression to a single container. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - where - Filters the results to return only to return only blobs whose tags match the specified expression. // - options - ServiceClientFilterBlobsOptions contains the optional parameters for the ServiceClient.FilterBlobs method. func (client *ServiceClient) FilterBlobs(ctx context.Context, where string, options *ServiceClientFilterBlobsOptions) (ServiceClientFilterBlobsResponse, error) { @@ -52,7 +42,7 @@ func (client *ServiceClient) FilterBlobs(ctx context.Context, where string, opti if err != nil { return ServiceClientFilterBlobsResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ServiceClientFilterBlobsResponse{}, err } @@ -80,8 +70,11 @@ func (client *ServiceClient) filterBlobsCreateRequest(ctx context.Context, where if options != nil && options.Maxresults != nil { reqQP.Set("maxresults", strconv.FormatInt(int64(*options.Maxresults), 10)) } + if options != nil && options.Include != nil { + reqQP.Set("include", strings.Join(strings.Fields(strings.Trim(fmt.Sprint(options.Include), "[]")), ",")) + } req.Raw().URL.RawQuery = strings.Replace(reqQP.Encode(), "+", "%20", -1) - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -117,14 +110,14 @@ func (client *ServiceClient) filterBlobsHandleResponse(resp *http.Response) (Ser // GetAccountInfo - Returns the sku name and account kind // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - ServiceClientGetAccountInfoOptions contains the optional parameters for the ServiceClient.GetAccountInfo method. func (client *ServiceClient) GetAccountInfo(ctx context.Context, options *ServiceClientGetAccountInfoOptions) (ServiceClientGetAccountInfoResponse, error) { req, err := client.getAccountInfoCreateRequest(ctx, options) if err != nil { return ServiceClientGetAccountInfoResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ServiceClientGetAccountInfoResponse{}, err } @@ -144,7 +137,7 @@ func (client *ServiceClient) getAccountInfoCreateRequest(ctx context.Context, op reqQP.Set("restype", "account") reqQP.Set("comp", "properties") req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} req.Raw().Header["Accept"] = []string{"application/xml"} return req, nil } @@ -188,14 +181,14 @@ func (client *ServiceClient) getAccountInfoHandleResponse(resp *http.Response) ( // CORS (Cross-Origin Resource Sharing) rules. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - ServiceClientGetPropertiesOptions contains the optional parameters for the ServiceClient.GetProperties method. func (client *ServiceClient) GetProperties(ctx context.Context, options *ServiceClientGetPropertiesOptions) (ServiceClientGetPropertiesResponse, error) { req, err := client.getPropertiesCreateRequest(ctx, options) if err != nil { return ServiceClientGetPropertiesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ServiceClientGetPropertiesResponse{}, err } @@ -218,7 +211,7 @@ func (client *ServiceClient) getPropertiesCreateRequest(ctx context.Context, opt reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -248,14 +241,14 @@ func (client *ServiceClient) getPropertiesHandleResponse(resp *http.Response) (S // location endpoint when read-access geo-redundant replication is enabled for the storage account. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - ServiceClientGetStatisticsOptions contains the optional parameters for the ServiceClient.GetStatistics method. func (client *ServiceClient) GetStatistics(ctx context.Context, options *ServiceClientGetStatisticsOptions) (ServiceClientGetStatisticsResponse, error) { req, err := client.getStatisticsCreateRequest(ctx, options) if err != nil { return ServiceClientGetStatisticsResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ServiceClientGetStatisticsResponse{}, err } @@ -278,7 +271,7 @@ func (client *ServiceClient) getStatisticsCreateRequest(ctx context.Context, opt reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -315,7 +308,7 @@ func (client *ServiceClient) getStatisticsHandleResponse(resp *http.Response) (S // bearer token authentication. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - keyInfo - Key information // - options - ServiceClientGetUserDelegationKeyOptions contains the optional parameters for the ServiceClient.GetUserDelegationKey // method. @@ -324,7 +317,7 @@ func (client *ServiceClient) GetUserDelegationKey(ctx context.Context, keyInfo K if err != nil { return ServiceClientGetUserDelegationKeyResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ServiceClientGetUserDelegationKeyResponse{}, err } @@ -347,12 +340,15 @@ func (client *ServiceClient) getUserDelegationKeyCreateRequest(ctx context.Conte reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } req.Raw().Header["Accept"] = []string{"application/xml"} - return req, runtime.MarshalAsXML(req, keyInfo) + if err := runtime.MarshalAsXML(req, keyInfo); err != nil { + return nil, err + } + return req, nil } // getUserDelegationKeyHandleResponse handles the GetUserDelegationKey response. @@ -383,7 +379,7 @@ func (client *ServiceClient) getUserDelegationKeyHandleResponse(resp *http.Respo // NewListContainersSegmentPager - The List Containers Segment operation returns a list of the containers under the specified // account // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - options - ServiceClientListContainersSegmentOptions contains the optional parameters for the ServiceClient.NewListContainersSegmentPager // method. // @@ -411,7 +407,7 @@ func (client *ServiceClient) ListContainersSegmentCreateRequest(ctx context.Cont reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } @@ -441,7 +437,7 @@ func (client *ServiceClient) ListContainersSegmentHandleResponse(resp *http.Resp // and CORS (Cross-Origin Resource Sharing) rules // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - storageServiceProperties - The StorageService properties. // - options - ServiceClientSetPropertiesOptions contains the optional parameters for the ServiceClient.SetProperties method. func (client *ServiceClient) SetProperties(ctx context.Context, storageServiceProperties StorageServiceProperties, options *ServiceClientSetPropertiesOptions) (ServiceClientSetPropertiesResponse, error) { @@ -449,7 +445,7 @@ func (client *ServiceClient) SetProperties(ctx context.Context, storageServicePr if err != nil { return ServiceClientSetPropertiesResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ServiceClientSetPropertiesResponse{}, err } @@ -472,12 +468,15 @@ func (client *ServiceClient) setPropertiesCreateRequest(ctx context.Context, sto reqQP.Set("timeout", strconv.FormatInt(int64(*options.Timeout), 10)) } req.Raw().URL.RawQuery = reqQP.Encode() - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } req.Raw().Header["Accept"] = []string{"application/xml"} - return req, runtime.MarshalAsXML(req, storageServiceProperties) + if err := runtime.MarshalAsXML(req, storageServiceProperties); err != nil { + return nil, err + } + return req, nil } // setPropertiesHandleResponse handles the SetProperties response. @@ -498,7 +497,7 @@ func (client *ServiceClient) setPropertiesHandleResponse(resp *http.Response) (S // SubmitBatch - The Batch operation allows multiple API calls to be embedded into a single HTTP request. // If the operation fails it returns an *azcore.ResponseError type. // -// Generated from API version 2020-10-02 +// Generated from API version 2021-12-02 // - contentLength - The length of the request. // - multipartContentType - Required. The value of this header must be multipart/mixed with a batch boundary. Example header // value: multipart/mixed; boundary=batch_ @@ -509,7 +508,7 @@ func (client *ServiceClient) SubmitBatch(ctx context.Context, contentLength int6 if err != nil { return ServiceClientSubmitBatchResponse{}, err } - resp, err := client.pl.Do(req) + resp, err := client.internal.Pipeline().Do(req) if err != nil { return ServiceClientSubmitBatchResponse{}, err } @@ -534,12 +533,15 @@ func (client *ServiceClient) submitBatchCreateRequest(ctx context.Context, conte runtime.SkipBodyDownload(req) req.Raw().Header["Content-Length"] = []string{strconv.FormatInt(contentLength, 10)} req.Raw().Header["Content-Type"] = []string{multipartContentType} - req.Raw().Header["x-ms-version"] = []string{"2020-10-02"} + req.Raw().Header["x-ms-version"] = []string{"2021-12-02"} if options != nil && options.RequestID != nil { req.Raw().Header["x-ms-client-request-id"] = []string{*options.RequestID} } req.Raw().Header["Accept"] = []string{"application/xml"} - return req, req.SetBody(body, multipartContentType) + if err := req.SetBody(body, multipartContentType); err != nil { + return nil, err + } + return req, nil } // submitBatchHandleResponse handles the SubmitBatch response. diff --git a/sdk/storage/azblob/internal/shared/shared.go b/sdk/storage/azblob/internal/shared/shared.go index 02936ad0362b..1de60999ec55 100644 --- a/sdk/storage/azblob/internal/shared/shared.go +++ b/sdk/storage/azblob/internal/shared/shared.go @@ -44,6 +44,15 @@ const ( const crc64Polynomial uint64 = 0x9A6C9329AC4BC9B5 +const ( + AppendBlobClient = "azblob/appendblob.Client" + BlobClient = "azblob/blob.Client" + BlockBlobClient = "azblob/blockblob.Client" + ContainerClient = "azblob/container.Client" + PageBlobClient = "azblob/pageblob.Client" + ServiceClient = "azblob/service.Client" +) + var CRC64Table = crc64.MakeTable(crc64Polynomial) // CopyOptions returns a zero-value T if opts is nil. diff --git a/sdk/storage/azblob/internal/testcommon/clients_auth.go b/sdk/storage/azblob/internal/testcommon/clients_auth.go index 687c7e8a5fee..235c00220e9d 100644 --- a/sdk/storage/azblob/internal/testcommon/clients_auth.go +++ b/sdk/storage/azblob/internal/testcommon/clients_auth.go @@ -14,6 +14,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/appendblob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas" "strings" "testing" @@ -236,6 +237,14 @@ func CreateNewBlobs(ctx context.Context, _require *require.Assertions, blobNames } } +func CreateNewBlobsListTier(ctx context.Context, _require *require.Assertions, blobNames []string, containerClient *container.Client, tier *blob.AccessTier) { + for _, blobName := range blobNames { + bbClient := CreateNewBlockBlob(ctx, _require, blobName, containerClient) + _, err := bbClient.SetTier(ctx, *tier, nil) + _require.NoError(err) + } +} + func GetBlockBlobClient(blockBlobName string, containerClient *container.Client) *blockblob.Client { return containerClient.NewBlockBlobClient(blockBlobName) } @@ -269,6 +278,18 @@ func CreateNewBlockBlobWithCPK(ctx context.Context, _require *require.Assertions return } +func GetAppendBlobClient(appendBlobName string, containerClient *container.Client) *appendblob.Client { + return containerClient.NewAppendBlobClient(appendBlobName) +} + +func CreateNewAppendBlob(ctx context.Context, _require *require.Assertions, appendBlobName string, containerClient *container.Client) *appendblob.Client { + abClient := GetAppendBlobClient(appendBlobName, containerClient) + + _, err := abClient.Create(ctx, nil) + _require.Nil(err) + return abClient +} + // Some tests require setting service properties. It can take up to 30 seconds for the new properties to be reflected across all FEs. // We will enable the necessary property and try to run the test implementation. If it fails with an error that should be due to // those changes not being reflected yet, we will wait 30 seconds and try the test again. If it fails this time for any reason, diff --git a/sdk/storage/azblob/pageblob/client.go b/sdk/storage/azblob/pageblob/client.go index 69328dbeb5ba..7e534cee1859 100644 --- a/sdk/storage/azblob/pageblob/client.go +++ b/sdk/storage/azblob/pageblob/client.go @@ -37,10 +37,13 @@ type Client base.CompositeClient[generated.BlobClient, generated.PageBlobClient] 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.NewPageBlobClient(blobURL, pl, nil)), nil + azClient, err := azcore.NewClient(shared.PageBlobClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + return (*Client)(base.NewPageBlobClient(blobURL, azClient, nil)), nil } // NewClientWithNoCredential creates an instance of Client with the specified values. @@ -49,9 +52,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.NewPageBlobClient(blobURL, pl, nil)), nil + azClient, err := azcore.NewClient(shared.PageBlobClient, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + return (*Client)(base.NewPageBlobClient(blobURL, azClient, nil)), nil } // NewClientWithSharedKeyCredential creates an instance of Client with the specified values. @@ -61,10 +67,13 @@ 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}} - return (*Client)(base.NewPageBlobClient(blobURL, pl, cred)), nil + azClient, err := azcore.NewClient(shared.PageBlobClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + return (*Client)(base.NewPageBlobClient(blobURL, azClient, cred)), nil } // NewClientFromConnectionString creates an instance of Client with the specified values. @@ -119,7 +128,7 @@ func (pb *Client) WithSnapshot(snapshot string) (*Client, error) { } p.Snapshot = snapshot - return (*Client)(base.NewPageBlobClient(p.String(), pb.generated().Pipeline(), pb.sharedKey())), nil + return (*Client)(base.NewPageBlobClient(p.String(), pb.generated().InternalClient(), pb.sharedKey())), nil } // WithVersionID creates a new PageBlobURL object identical to the source but with the specified snapshot timestamp. @@ -131,7 +140,7 @@ func (pb *Client) WithVersionID(versionID string) (*Client, error) { } p.VersionID = versionID - return (*Client)(base.NewPageBlobClient(p.String(), pb.generated().Pipeline(), pb.sharedKey())), nil + return (*Client)(base.NewPageBlobClient(p.String(), pb.generated().InternalClient(), pb.sharedKey())), nil } // Create creates a page blob of the specified length. Call PutPage to upload data to a page blob. @@ -228,7 +237,7 @@ func (pb *Client) NewGetPageRangesPager(o *GetPageRangesOptions) *runtime.Pager[ if err != nil { return GetPageRangesResponse{}, err } - resp, err := pb.generated().Pipeline().Do(req) + resp, err := pb.generated().InternalClient().Pipeline().Do(req) if err != nil { return GetPageRangesResponse{}, err } @@ -261,7 +270,7 @@ func (pb *Client) NewGetPageRangesDiffPager(o *GetPageRangesDiffOptions) *runtim if err != nil { return GetPageRangesDiffResponse{}, err } - resp, err := pb.generated().Pipeline().Do(req) + resp, err := pb.generated().InternalClient().Pipeline().Do(req) if err != nil { return GetPageRangesDiffResponse{}, err } diff --git a/sdk/storage/azblob/pageblob/client_test.go b/sdk/storage/azblob/pageblob/client_test.go index 7b659b4bf4ee..a7195b050644 100644 --- a/sdk/storage/azblob/pageblob/client_test.go +++ b/sdk/storage/azblob/pageblob/client_test.go @@ -154,6 +154,33 @@ func (s *PageBlobRecordedTestsSuite) TestPutGetPages() { } } +func (s *PageBlobRecordedTestsSuite) TestBlobTierInferred() { + _require := require.New(s.T()) + testName := s.T().Name() + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountPremium, 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) + pbClient := createNewPageBlob(context.Background(), _require, blockBlobName, containerClient) + + resp, err := pbClient.GetProperties(context.Background(), nil) + _require.Nil(err) + _require.Equal(*resp.AccessTierInferred, true) + _require.NotEqual(*resp.AccessTier, "") + + _, err = pbClient.SetTier(context.Background(), blob.AccessTierP4, nil) + _require.Nil(err) + + resp, err = pbClient.GetProperties(context.Background(), nil) + _require.Nil(err) + _require.Nil(resp.AccessTierInferred) + _require.NotEqual(*resp.AccessTier, "") +} + // func (s *PageBlobUnrecordedTestsSuite) TestUploadPagesFromURL() { // _require := require.New(s.T()) // testName := s.T().Name() diff --git a/sdk/storage/azblob/sas/account.go b/sdk/storage/azblob/sas/account.go index 454a08cb9e58..4069bb132023 100644 --- a/sdk/storage/azblob/sas/account.go +++ b/sdk/storage/azblob/sas/account.go @@ -25,13 +25,14 @@ type UserDelegationCredential = exported.UserDelegationCredential // AccountSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage account. // For more information, see https://docs.microsoft.com/rest/api/storageservices/constructing-an-account-sas type AccountSignatureValues struct { - Version string `param:"sv"` // If not specified, this format to SASVersion - Protocol Protocol `param:"spr"` // See the SASProtocol* constants - StartTime time.Time `param:"st"` // Not specified if IsZero - ExpiryTime time.Time `param:"se"` // Not specified if IsZero - Permissions string `param:"sp"` // Create by initializing AccountPermissions and then call String() - IPRange IPRange `param:"sip"` - ResourceTypes string `param:"srt"` // Create by initializing AccountResourceTypes and then call String() + Version string `param:"sv"` // If not specified, this format to SASVersion + Protocol Protocol `param:"spr"` // See the SASProtocol* constants + StartTime time.Time `param:"st"` // Not specified if IsZero + ExpiryTime time.Time `param:"se"` // Not specified if IsZero + Permissions string `param:"sp"` // Create by initializing AccountPermissions and then call String() + IPRange IPRange `param:"sip"` + ResourceTypes string `param:"srt"` // Create by initializing AccountResourceTypes and then call String() + EncryptionScope string `param:"ses"` } // SignWithSharedKey uses an account's shared key credential to sign this signature values to produce @@ -68,6 +69,7 @@ func (v AccountSignatureValues) SignWithSharedKey(sharedKeyCredential *SharedKey v.IPRange.String(), string(v.Protocol), v.Version, + v.EncryptionScope, ""}, // That is right, the account SAS requires a terminating extra newline "\n") @@ -77,12 +79,13 @@ func (v AccountSignatureValues) SignWithSharedKey(sharedKeyCredential *SharedKey } p := QueryParameters{ // Common SAS parameters - version: v.Version, - protocol: v.Protocol, - startTime: v.StartTime, - expiryTime: v.ExpiryTime, - permissions: v.Permissions, - ipRange: v.IPRange, + version: v.Version, + protocol: v.Protocol, + startTime: v.StartTime, + expiryTime: v.ExpiryTime, + permissions: v.Permissions, + ipRange: v.IPRange, + encryptionScope: v.EncryptionScope, // Account-specific SAS parameters services: "b", // will always be "b" diff --git a/sdk/storage/azblob/sas/query_params.go b/sdk/storage/azblob/sas/query_params.go index 4d97372da6d0..4c23208e2e14 100644 --- a/sdk/storage/azblob/sas/query_params.go +++ b/sdk/storage/azblob/sas/query_params.go @@ -23,7 +23,7 @@ const ( var ( // Version is the default version encoded in the SAS token. - Version = "2020-02-10" + Version = "2021-12-02" ) // TimeFormats ISO 8601 format. @@ -143,6 +143,7 @@ type QueryParameters struct { authorizedObjectID string `param:"saoid"` unauthorizedObjectID string `param:"suoid"` correlationID string `param:"scid"` + encryptionScope string `param:"ses"` // private member used for startTime and expiryTime formatting. stTimeFormat string seTimeFormat string @@ -163,6 +164,11 @@ func (p *QueryParameters) SignedCorrelationID() string { return p.correlationID } +// EncryptionScope returns encryptionScope +func (p *QueryParameters) EncryptionScope() string { + return p.encryptionScope +} + // SignedOID returns signedOID. func (p *QueryParameters) SignedOID() string { return p.signedOID @@ -355,6 +361,9 @@ func (p *QueryParameters) Encode() string { if p.correlationID != "" { v.Add("scid", p.correlationID) } + if p.encryptionScope != "" { + v.Add("ses", p.encryptionScope) + } return v.Encode() } @@ -429,6 +438,8 @@ func NewQueryParameters(values url.Values, deleteSASParametersFromValues bool) Q p.unauthorizedObjectID = val case "scid": p.correlationID = val + case "ses": + p.encryptionScope = val default: isSASKey = false // We didn't recognize the query parameter } diff --git a/sdk/storage/azblob/sas/service.go b/sdk/storage/azblob/sas/service.go index 6c3ae263fc7a..45f730847d28 100644 --- a/sdk/storage/azblob/sas/service.go +++ b/sdk/storage/azblob/sas/service.go @@ -40,6 +40,7 @@ type BlobSignatureValues struct { AuthorizedObjectID string // saoid UnauthorizedObjectID string // suoid CorrelationID string // scid + EncryptionScope string `param:"ses"` } func getDirectoryDepth(path string) string { @@ -55,13 +56,7 @@ func (v BlobSignatureValues) SignWithSharedKey(sharedKeyCredential *SharedKeyCre return QueryParameters{}, errors.New("service SAS is missing at least one of these: ExpiryTime or Permissions") } - //Make sure the permission characters are in the correct order - perms, err := parseBlobPermissions(v.Permissions) - if err != nil { - return QueryParameters{}, err - } - v.Permissions = perms.String() - + // Parse the resource resource := "c" if !v.SnapshotTime.IsZero() { resource = "bs" @@ -76,6 +71,21 @@ func (v BlobSignatureValues) SignWithSharedKey(sharedKeyCredential *SharedKeyCre resource = "b" } + // make sure the permission characters are in the correct order + if resource == "c" { + perms, err := parseContainerPermissions(v.Permissions) + if err != nil { + return QueryParameters{}, err + } + v.Permissions = perms.String() + } else { + perms, err := parseBlobPermissions(v.Permissions) + if err != nil { + return QueryParameters{}, err + } + v.Permissions = perms.String() + } + if v.Version == "" { v.Version = Version } @@ -94,7 +104,8 @@ func (v BlobSignatureValues) SignWithSharedKey(sharedKeyCredential *SharedKeyCre string(v.Protocol), v.Version, resource, - snapshotTime, // signed timestamp + snapshotTime, // signed timestamp + v.EncryptionScope, v.CacheControl, // rscc v.ContentDisposition, // rscd v.ContentEncoding, // rsce @@ -109,12 +120,13 @@ func (v BlobSignatureValues) SignWithSharedKey(sharedKeyCredential *SharedKeyCre p := QueryParameters{ // Common SAS parameters - version: v.Version, - protocol: v.Protocol, - startTime: v.StartTime, - expiryTime: v.ExpiryTime, - permissions: v.Permissions, - ipRange: v.IPRange, + version: v.Version, + protocol: v.Protocol, + startTime: v.StartTime, + expiryTime: v.ExpiryTime, + permissions: v.Permissions, + ipRange: v.IPRange, + encryptionScope: v.EncryptionScope, // Container/Blob-specific SAS parameters resource: resource, @@ -202,7 +214,8 @@ func (v BlobSignatureValues) SignWithUserDelegation(userDelegationCredential *Us string(v.Protocol), v.Version, resource, - snapshotTime, // signed timestamp + snapshotTime, // signed timestamp + v.EncryptionScope, v.CacheControl, // rscc v.ContentDisposition, // rscd v.ContentEncoding, // rsce @@ -217,12 +230,13 @@ func (v BlobSignatureValues) SignWithUserDelegation(userDelegationCredential *Us p := QueryParameters{ // Common SAS parameters - version: v.Version, - protocol: v.Protocol, - startTime: v.StartTime, - expiryTime: v.ExpiryTime, - permissions: v.Permissions, - ipRange: v.IPRange, + version: v.Version, + protocol: v.Protocol, + startTime: v.StartTime, + expiryTime: v.ExpiryTime, + permissions: v.Permissions, + ipRange: v.IPRange, + encryptionScope: v.EncryptionScope, // Container/Blob-specific SAS parameters resource: resource, diff --git a/sdk/storage/azblob/service/client.go b/sdk/storage/azblob/service/client.go index fb7b8696a86c..461775347eeb 100644 --- a/sdk/storage/azblob/service/client.go +++ b/sdk/storage/azblob/service/client.go @@ -42,10 +42,13 @@ type Client base.Client[generated.ServiceClient] func NewClient(serviceURL 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.NewServiceClient(serviceURL, pl, &cred)), nil + azClient, err := azcore.NewClient(shared.ServiceClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + return (*Client)(base.NewServiceClient(serviceURL, azClient, &cred)), nil } // NewClientWithNoCredential creates an instance of Client with the specified values. @@ -54,9 +57,12 @@ func NewClient(serviceURL string, cred azcore.TokenCredential, options *ClientOp // - options - client options; pass nil to accept the default values func NewClientWithNoCredential(serviceURL string, options *ClientOptions) (*Client, error) { conOptions := shared.GetClientOptions(options) - pl := runtime.NewPipeline(exported.ModuleName, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions) - return (*Client)(base.NewServiceClient(serviceURL, pl, nil)), nil + azClient, err := azcore.NewClient(shared.ServiceClient, exported.ModuleVersion, runtime.PipelineOptions{}, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + return (*Client)(base.NewServiceClient(serviceURL, azClient, nil)), nil } // NewClientWithSharedKeyCredential creates an instance of Client with the specified values. @@ -66,10 +72,14 @@ func NewClientWithNoCredential(serviceURL string, options *ClientOptions) (*Clie func NewClientWithSharedKeyCredential(serviceURL 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.NewServiceClient(serviceURL, pl, cred)), nil + azClient, err := azcore.NewClient(shared.ServiceClient, exported.ModuleVersion, plOpts, &conOptions.ClientOptions) + if err != nil { + return nil, err + } + + return (*Client)(base.NewServiceClient(serviceURL, azClient, cred)), nil } // NewClientFromConnectionString creates an instance of Client with the specified values. @@ -135,7 +145,7 @@ func (s *Client) URL() string { // this Client's URL. The new container.Client uses the same request policy pipeline as the Client. func (s *Client) NewContainerClient(containerName string) *container.Client { containerURL := runtime.JoinPaths(s.generated().Endpoint(), containerName) - return (*container.Client)(base.NewContainerClient(containerURL, s.generated().Pipeline(), s.credential())) + return (*container.Client)(base.NewContainerClient(containerURL, s.generated().InternalClient().WithClientName(shared.ContainerClient), s.credential())) } // CreateContainer is a lifecycle method to creates a new container under the specified account. @@ -184,6 +194,9 @@ func (s *Client) NewListContainersPager(o *ListContainersOptions) *runtime.Pager if o.Include.Metadata { listOptions.Include = append(listOptions.Include, generated.ListContainersIncludeTypeMetadata) } + if o.Include.System { + listOptions.Include = append(listOptions.Include, generated.ListContainersIncludeTypeSystem) + } listOptions.Marker = o.Marker listOptions.Maxresults = o.MaxResults listOptions.Prefix = o.Prefix @@ -204,7 +217,7 @@ func (s *Client) NewListContainersPager(o *ListContainersOptions) *runtime.Pager if err != nil { return ListContainersResponse{}, err } - resp, err := s.generated().Pipeline().Do(req) + resp, err := s.generated().InternalClient().Pipeline().Do(req) if err != nil { return ListContainersResponse{}, err } diff --git a/sdk/storage/azblob/service/client_test.go b/sdk/storage/azblob/service/client_test.go index 7d9c77090956..f823c58f2fac 100644 --- a/sdk/storage/azblob/service/client_test.go +++ b/sdk/storage/azblob/service/client_test.go @@ -10,6 +10,7 @@ import ( "context" "fmt" "github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/appendblob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported" "io" @@ -160,6 +161,33 @@ func (s *ServiceUnrecordedTestsSuite) TestListContainersBasic() { _require.GreaterOrEqual(count, 0) } +func (s *ServiceRecordedTestsSuite) TestListContainersSystem() { + _require := require.New(s.T()) + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) + _require.Nil(err) + + listOptions := service.ListContainersOptions{Include: service.ListContainersInclude{System: true}} + pager := svcClient.NewListContainersPager(&listOptions) + + count := 0 + for pager.More() { + resp, err := pager.NextPage(context.Background()) + _require.Nil(err) + for _, c := range resp.ContainerItems { + _require.NotNil(c.Name) + if strings.Contains(*c.Name, "$") { + count += 1 + } + } + if err != nil { + break + } + } + + _require.Nil(err) + _require.GreaterOrEqual(count, 1) // every account will always have one system container, i.e. '$logs' +} + func (s *ServiceRecordedTestsSuite) TestSetPropertiesLogging() { _require := require.New(s.T()) svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDefault, nil) @@ -1058,6 +1086,78 @@ func (s *ServiceRecordedTestsSuite) TestAccountFilterBlobs() { _require.Len(resp.FilterBlobSegment.Blobs, 0) } +func (s *ServiceUnrecordedTestsSuite) TestFilterBlobsTagsWithServiceSAS() { + _require := require.New(s.T()) + testName := s.T().Name() + cred, _ := testcommon.GetGenericSharedKeyCredential(testcommon.TestAccountDefault) + + serviceClient, err := service.NewClientWithSharedKeyCredential(fmt.Sprintf("https://%s.blob.core.windows.net/", cred.AccountName()), cred, nil) + _require.Nil(err) + + // Note: Always set all permissions, services, types to true to ensure order of string formed is correct. + resources := sas.AccountResourceTypes{ + Object: true, + Service: true, + Container: true, + } + permissions := sas.AccountPermissions{ + Read: true, + Write: true, + Delete: true, + DeletePreviousVersion: true, + List: true, + Add: true, + Create: true, + Update: true, + Process: true, + Tag: true, + FilterByTags: true, + PermanentDelete: true, + } + expiry := time.Now().Add(time.Hour) + sasUrl, err := serviceClient.GetSASURL(resources, permissions, expiry, nil) + _require.Nil(err) + + svcClient, err := testcommon.GetServiceClientNoCredential(s.T(), sasUrl, nil) + _require.Nil(err) + + containerName := testcommon.GenerateContainerName(testName) + containerClient := testcommon.CreateNewContainer(context.Background(), _require, containerName, svcClient) + defer testcommon.DeleteContainer(context.Background(), _require, containerClient) + + abClient := testcommon.GetAppendBlobClient(testcommon.GenerateBlobName(testName), containerClient) + + createAppendBlobOptions := appendblob.CreateOptions{ + Tags: testcommon.SpecialCharBlobTagsMap, + } + createResp, err := abClient.Create(context.Background(), &createAppendBlobOptions) + _require.Nil(err) + _require.NotNil(createResp.VersionID) + time.Sleep(10 * time.Second) + + _, err = abClient.GetProperties(context.Background(), nil) + _require.Nil(err) + + blobGetTagsResponse, err := abClient.GetTags(context.Background(), nil) + _require.Nil(err) + blobTagsSet := blobGetTagsResponse.BlobTagSet + _require.NotNil(blobTagsSet) + _require.Len(blobTagsSet, len(testcommon.SpecialCharBlobTagsMap)) + for _, blobTag := range blobTagsSet { + _require.Equal(testcommon.SpecialCharBlobTagsMap[*blobTag.Key], *blobTag.Value) + } + + // Tags with spaces + where := "\"GO \"='.Net'" + lResp, err := svcClient.FilterBlobs(context.Background(), where, nil) + _require.Nil(err) + _require.Len(lResp.FilterBlobSegment.Blobs[0].Tags.BlobTagSet, 1) + _require.Equal(lResp.FilterBlobSegment.Blobs[0].Tags.BlobTagSet[0], blobTagsSet[2]) + + _, err = svcClient.DeleteContainer(context.Background(), containerName, nil) + _require.Nil(err) +} + func batchSetup(containerName string, svcClient *service.Client, bb *service.BatchBuilder, operationType exported.BlobBatchOperationType) ([]*container.Client, error) { var cntClients []*container.Client for i := 0; i < 5; i++ { diff --git a/sdk/storage/azblob/service/models.go b/sdk/storage/azblob/service/models.go index 22f49474dee6..b70724d79743 100644 --- a/sdk/storage/azblob/service/models.go +++ b/sdk/storage/azblob/service/models.go @@ -156,6 +156,9 @@ type ListContainersInclude struct { // Tells the service whether to return soft-deleted containers. Deleted bool + + // Tells the service whether to return system containers. + System bool } // --------------------------------------------------------------------------------------------------------------------- diff --git a/sdk/storage/azblob/testdata/perf/go.mod b/sdk/storage/azblob/testdata/perf/go.mod index 1ccc0daea6b1..6450502a3b95 100644 --- a/sdk/storage/azblob/testdata/perf/go.mod +++ b/sdk/storage/azblob/testdata/perf/go.mod @@ -3,7 +3,7 @@ module github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/testdata/perf go 1.18 require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 ) diff --git a/sdk/storage/azblob/testdata/perf/go.sum b/sdk/storage/azblob/testdata/perf/go.sum index 9a7a73da061e..8c0458dc68dc 100644 --- a/sdk/storage/azblob/testdata/perf/go.sum +++ b/sdk/storage/azblob/testdata/perf/go.sum @@ -1,5 +1,5 @@ -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 h1:8kDqDngH+DmVBiCtIjCFTGa7MBnsIOkF9IccInFEbjk= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 h1:8q4SaHjFsClSvuVne0ID/5Ka8u3fcIHyqkLjcFpNRHQ= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM=