diff --git a/sdk/storage/azdatalake/assets.json b/sdk/storage/azdatalake/assets.json index 67a2df2961e2..89fb3cdc8b61 100644 --- a/sdk/storage/azdatalake/assets.json +++ b/sdk/storage/azdatalake/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "go", "TagPrefix": "go/storage/azdatalake", - "Tag": "go/storage/azdatalake_9dd1cc3e0e" + "Tag": "go/storage/azdatalake_78f150eb1d" } \ No newline at end of file diff --git a/sdk/storage/azdatalake/directory/client.go b/sdk/storage/azdatalake/directory/client.go index 8c998a0f812b..da7982ab0b62 100644 --- a/sdk/storage/azdatalake/directory/client.go +++ b/sdk/storage/azdatalake/directory/client.go @@ -219,14 +219,14 @@ func (d *Client) renamePathInURL(newName string) (string, string, string) { lastIndex := strings.LastIndex(endpoint, separator) // Split the string based on the last occurrence of the separator firstPart := endpoint[:lastIndex] // From the beginning of the string to the last occurrence of the separator - newPathURL, newBlobURL := shared.GetURLs(runtime.JoinPaths(firstPart, newName)) + newBlobURL, newPathURL := shared.GetURLs(runtime.JoinPaths(firstPart, newName)) parsedNewURL, _ := url.Parse(d.DFSURL()) return parsedNewURL.Path, newPathURL, newBlobURL } // Rename renames a directory (dfs1) func (d *Client) Rename(ctx context.Context, newName string, options *RenameOptions) (RenameResponse, error) { - newPathWithoutURL, newBlobURL, newPathURL := d.renamePathInURL(newName) + newPathWithoutURL, newPathURL, newBlobURL := d.renamePathInURL(newName) lac, mac, smac, createOpts := path.FormatRenameOptions(options, newPathWithoutURL) var newBlobClient *blockblob.Client var err error diff --git a/sdk/storage/azdatalake/file/client.go b/sdk/storage/azdatalake/file/client.go index 7400838cf7fb..ca83eeecf698 100644 --- a/sdk/storage/azdatalake/file/client.go +++ b/sdk/storage/azdatalake/file/client.go @@ -224,14 +224,14 @@ func (f *Client) renamePathInURL(newName string) (string, string, string) { lastIndex := strings.LastIndex(endpoint, separator) // Split the string based on the last occurrence of the separator firstPart := endpoint[:lastIndex] // From the beginning of the string to the last occurrence of the separator - newPathURL, newBlobURL := shared.GetURLs(runtime.JoinPaths(firstPart, newName)) + newBlobURL, newPathURL := shared.GetURLs(runtime.JoinPaths(firstPart, newName)) parsedNewURL, _ := url.Parse(f.DFSURL()) return parsedNewURL.Path, newPathURL, newBlobURL } // Rename renames a file (dfs1) func (f *Client) Rename(ctx context.Context, newName string, options *RenameOptions) (RenameResponse, error) { - newPathWithoutURL, newBlobURL, newPathURL := f.renamePathInURL(newName) + newPathWithoutURL, newPathURL, newBlobURL := f.renamePathInURL(newName) lac, mac, smac, createOpts := path.FormatRenameOptions(options, newPathWithoutURL) var newBlobClient *blockblob.Client var err error diff --git a/sdk/storage/azdatalake/filesystem/client.go b/sdk/storage/azdatalake/filesystem/client.go index 6c21c0ed364e..46f6c22f06bb 100644 --- a/sdk/storage/azdatalake/filesystem/client.go +++ b/sdk/storage/azdatalake/filesystem/client.go @@ -184,7 +184,7 @@ func (fs *Client) BlobURL() string { // The new directory.Client uses the same request policy pipeline as the Client. func (fs *Client) NewDirectoryClient(directoryPath string) *directory.Client { dirURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), directoryPath) - dirURL, blobURL := shared.GetURLs(dirURL) + blobURL, dirURL := shared.GetURLs(dirURL) return (*directory.Client)(base.NewPathClient(dirURL, blobURL, fs.containerClient().NewBlockBlobClient(directoryPath), fs.generatedFSClientWithDFS().InternalClient().WithClientName(shared.DirectoryClient), fs.sharedKey(), fs.identityCredential(), fs.getClientOptions())) } @@ -192,7 +192,7 @@ func (fs *Client) NewDirectoryClient(directoryPath string) *directory.Client { // The new file.Client uses the same request policy pipeline as the Client. func (fs *Client) NewFileClient(filePath string) *file.Client { fileURL := runtime.JoinPaths(fs.generatedFSClientWithDFS().Endpoint(), filePath) - fileURL, blobURL := shared.GetURLs(filePath) + blobURL, fileURL := shared.GetURLs(fileURL) return (*file.Client)(base.NewPathClient(fileURL, blobURL, fs.containerClient().NewBlockBlobClient(filePath), fs.generatedFSClientWithDFS().InternalClient().WithClientName(shared.FileClient), fs.sharedKey(), fs.identityCredential(), fs.getClientOptions())) } diff --git a/sdk/storage/azdatalake/internal/testcommon/clients_auth.go b/sdk/storage/azdatalake/internal/testcommon/clients_auth.go index 20c2d683daa5..93a91257b1b8 100644 --- a/sdk/storage/azdatalake/internal/testcommon/clients_auth.go +++ b/sdk/storage/azdatalake/internal/testcommon/clients_auth.go @@ -141,6 +141,20 @@ func GetFileClient(fsName, fName string, t *testing.T, accountType TestAccountTy return fileClient, err } +func CreateNewFile(ctx context.Context, _require *require.Assertions, fileName string, filesystemClient *filesystem.Client) *file.Client { + fileClient := filesystemClient.NewFileClient(fileName) + _, err := fileClient.Create(ctx, nil) + _require.Nil(err) + return fileClient +} + +func CreateNewDir(ctx context.Context, _require *require.Assertions, dirName string, filesystemClient *filesystem.Client) *directory.Client { + dirClient := filesystemClient.NewDirectoryClient(dirName) + _, err := dirClient.Create(ctx, nil) + _require.Nil(err) + return dirClient +} + func GetDirClient(fsName, dirName string, t *testing.T, accountType TestAccountType, options *directory.ClientOptions) (*directory.Client, error) { if options == nil { options = &directory.ClientOptions{} diff --git a/sdk/storage/azdatalake/lease/filesystem_client.go b/sdk/storage/azdatalake/lease/client.go similarity index 66% rename from sdk/storage/azdatalake/lease/filesystem_client.go rename to sdk/storage/azdatalake/lease/client.go index 110171d15990..d59dfcf1a7da 100644 --- a/sdk/storage/azdatalake/lease/filesystem_client.go +++ b/sdk/storage/azdatalake/lease/client.go @@ -8,28 +8,36 @@ package lease import ( "context" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/lease" "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/filesystem" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/base" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/exported" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/generated" ) // FilesystemClient provides lease functionality for the underlying filesystem client. type FilesystemClient struct { - leaseID *string containerClient *lease.ContainerClient + leaseID *string } // FilesystemClientOptions contains the optional values when creating a FilesystemClient. -type FilesystemClientOptions struct { - // LeaseID contains a caller-provided lease ID. - LeaseID *string -} +type FilesystemClientOptions = lease.ContainerClientOptions // NewFilesystemClient creates a filesystem lease client for the provided filesystem client. // - client - an instance of a filesystem client // - options - client options; pass nil to accept the default values func NewFilesystemClient(client *filesystem.Client, options *FilesystemClientOptions) (*FilesystemClient, error) { - // TODO: set up container lease client - return nil, nil + _, _, containerClient := base.InnerClients((*base.CompositeClient[generated.FileSystemClient, generated.FileSystemClient, container.Client])(client)) + containerLeaseClient, err := lease.NewContainerClient(containerClient, options) + if err != nil { + return nil, exported.ConvertToDFSError(err) + } + return &FilesystemClient{ + containerClient: containerLeaseClient, + leaseID: containerLeaseClient.LeaseID(), + }, nil } // LeaseID returns leaseID of the client. @@ -42,7 +50,8 @@ func (c *FilesystemClient) LeaseID() *string { // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. func (c *FilesystemClient) AcquireLease(ctx context.Context, duration int32, o *FilesystemAcquireOptions) (FilesystemAcquireResponse, error) { opts := o.format() - return c.containerClient.AcquireLease(ctx, duration, opts) + resp, err := c.containerClient.AcquireLease(ctx, duration, opts) + return resp, exported.ConvertToDFSError(err) } // BreakLease breaks the filesystem's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) @@ -50,25 +59,33 @@ func (c *FilesystemClient) AcquireLease(ctx context.Context, duration int32, o * // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. func (c *FilesystemClient) BreakLease(ctx context.Context, o *FilesystemBreakOptions) (FilesystemBreakResponse, error) { opts := o.format() - return c.containerClient.BreakLease(ctx, opts) + resp, err := c.containerClient.BreakLease(ctx, opts) + return resp, exported.ConvertToDFSError(err) } // ChangeLease changes the filesystem's lease ID. // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. func (c *FilesystemClient) ChangeLease(ctx context.Context, proposedLeaseID string, o *FilesystemChangeOptions) (FilesystemChangeResponse, error) { opts := o.format() - return c.containerClient.ChangeLease(ctx, proposedLeaseID, opts) + resp, err := c.containerClient.ChangeLease(ctx, proposedLeaseID, opts) + if err != nil { + return resp, exported.ConvertToDFSError(err) + } + c.leaseID = &proposedLeaseID + return resp, nil } // RenewLease renews the filesystem's previously-acquired lease. // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. func (c *FilesystemClient) RenewLease(ctx context.Context, o *FilesystemRenewOptions) (FilesystemRenewResponse, error) { opts := o.format() - return c.containerClient.RenewLease(ctx, opts) + resp, err := c.containerClient.RenewLease(ctx, opts) + return resp, exported.ConvertToDFSError(err) } // ReleaseLease releases the filesystem's previously-acquired lease. func (c *FilesystemClient) ReleaseLease(ctx context.Context, o *FilesystemReleaseOptions) (FilesystemReleaseResponse, error) { opts := o.format() - return c.containerClient.ReleaseLease(ctx, opts) + resp, err := c.containerClient.ReleaseLease(ctx, opts) + return resp, exported.ConvertToDFSError(err) } diff --git a/sdk/storage/azdatalake/lease/client_test.go b/sdk/storage/azdatalake/lease/client_test.go new file mode 100644 index 000000000000..51f2183ea718 --- /dev/null +++ b/sdk/storage/azdatalake/lease/client_test.go @@ -0,0 +1,560 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package lease_test + +import ( + "context" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/file" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/filesystem" + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" + "github.com/Azure/azure-sdk-for-go/sdk/internal/recording" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/testcommon" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/lease" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +func Test(t *testing.T) { + recordMode := recording.GetRecordMode() + t.Logf("Running lease Tests in %s mode\n", recordMode) + if recordMode == recording.LiveMode { + suite.Run(t, &LeaseRecordedTestsSuite{}) + suite.Run(t, &LeaseUnrecordedTestsSuite{}) + } else if recordMode == recording.PlaybackMode { + suite.Run(t, &LeaseRecordedTestsSuite{}) + } else if recordMode == recording.RecordingMode { + suite.Run(t, &LeaseRecordedTestsSuite{}) + } +} + +func (s *LeaseRecordedTestsSuite) BeforeTest(suite string, test string) { + testcommon.BeforeTest(s.T(), suite, test) +} + +func (s *LeaseRecordedTestsSuite) AfterTest(suite string, test string) { + testcommon.AfterTest(s.T(), suite, test) +} + +func (s *LeaseUnrecordedTestsSuite) BeforeTest(suite string, test string) { + +} + +func (s *LeaseUnrecordedTestsSuite) AfterTest(suite string, test string) { + +} + +type LeaseRecordedTestsSuite struct { + suite.Suite +} + +type LeaseUnrecordedTestsSuite struct { + suite.Suite +} + +// var headersToIgnoreForLease = []string {"X-Ms-Proposed-Lease-Id", "X-Ms-Lease-Id"} +var proposedLeaseIDs = []*string{to.Ptr("c820a799-76d7-4ee2-6e15-546f19325c2c"), to.Ptr("326cc5e1-746e-4af8-4811-a50e6629a8ca")} + +func (s *LeaseRecordedTestsSuite) TestFilesystemAcquireLease() { + _require := require.New(s.T()) + testName := s.T().Name() + //ignoreHeaders(_context.recording, headersToIgnoreForLease) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + filesystemName := testcommon.GenerateFilesystemName(testName) + filesystemClient := testcommon.CreateNewFilesystem(context.Background(), _require, filesystemName, svcClient) + defer testcommon.DeleteFilesystem(context.Background(), _require, filesystemClient) + + filesystemLeaseClient, _ := lease.NewFilesystemClient(filesystemClient, &lease.FilesystemClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + + ctx := context.Background() + acquireLeaseResponse, err := filesystemLeaseClient.AcquireLease(ctx, int32(60), nil) + _require.Nil(err) + _require.NotNil(acquireLeaseResponse.LeaseID) + _require.EqualValues(*acquireLeaseResponse.LeaseID, *filesystemLeaseClient.LeaseID()) + + _, err = filesystemLeaseClient.ReleaseLease(ctx, nil) + _require.Nil(err) +} + +func (s *LeaseRecordedTestsSuite) TestFilesystemDeleteFilesystemWithoutLeaseId() { + _require := require.New(s.T()) + testName := s.T().Name() + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + filesystemName := testcommon.GenerateFilesystemName(testName) + filesystemClient := testcommon.CreateNewFilesystem(context.Background(), _require, filesystemName, svcClient) + defer testcommon.DeleteFilesystem(context.Background(), _require, filesystemClient) + + filesystemLeaseClient, _ := lease.NewFilesystemClient(filesystemClient, &lease.FilesystemClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + + ctx := context.Background() + acquireLeaseResponse, err := filesystemLeaseClient.AcquireLease(ctx, int32(60), nil) + _require.Nil(err) + _require.NotNil(acquireLeaseResponse.LeaseID) + _require.EqualValues(*acquireLeaseResponse.LeaseID, *filesystemLeaseClient.LeaseID()) + + _, err = filesystemClient.Delete(ctx, nil) + _require.NotNil(err) + + leaseID := filesystemLeaseClient.LeaseID() + _, err = filesystemClient.Delete(ctx, &filesystem.DeleteOptions{ + AccessConditions: &filesystem.AccessConditions{ + LeaseAccessConditions: &filesystem.LeaseAccessConditions{ + LeaseID: leaseID, + }, + }, + }) + _require.Nil(err) +} + +func (s *LeaseRecordedTestsSuite) TestFilesystemReleaseLease() { + _require := require.New(s.T()) + testName := s.T().Name() + + //ignoreHeaders(_context.recording, headersToIgnoreForLease) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + filesystemName := testcommon.GenerateFilesystemName(testName) + filesystemClient := testcommon.CreateNewFilesystem(context.Background(), _require, filesystemName, svcClient) + defer testcommon.DeleteFilesystem(context.Background(), _require, filesystemClient) + + filesystemLeaseClient, _ := lease.NewFilesystemClient(filesystemClient, &lease.FilesystemClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + + ctx := context.Background() + acquireLeaseResponse, err := filesystemLeaseClient.AcquireLease(ctx, int32(60), nil) + _require.Nil(err) + _require.NotNil(acquireLeaseResponse.LeaseID) + _require.EqualValues(*acquireLeaseResponse.LeaseID, *filesystemLeaseClient.LeaseID()) + + _, err = filesystemClient.Delete(ctx, nil) + _require.NotNil(err) + + _, err = filesystemLeaseClient.ReleaseLease(ctx, nil) + _require.Nil(err) + + _, err = filesystemClient.Delete(ctx, nil) + _require.Nil(err) +} + +func (s *LeaseRecordedTestsSuite) TestFilesystemRenewLease() { + _require := require.New(s.T()) + testName := s.T().Name() + + //ignoreHeaders(_context.recording, headersToIgnoreForLease) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + filesystemName := testcommon.GenerateFilesystemName(testName) + filesystemClient := testcommon.CreateNewFilesystem(context.Background(), _require, filesystemName, svcClient) + defer testcommon.DeleteFilesystem(context.Background(), _require, filesystemClient) + + filesystemLeaseClient, _ := lease.NewFilesystemClient(filesystemClient, &lease.FilesystemClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + + ctx := context.Background() + acquireLeaseResponse, err := filesystemLeaseClient.AcquireLease(ctx, int32(15), nil) + _require.Nil(err) + _require.NotNil(acquireLeaseResponse.LeaseID) + _require.EqualValues(*acquireLeaseResponse.LeaseID, *filesystemLeaseClient.LeaseID()) + + _, err = filesystemLeaseClient.RenewLease(ctx, nil) + _require.Nil(err) + + _, err = filesystemLeaseClient.ReleaseLease(ctx, nil) + _require.Nil(err) +} + +func (s *LeaseRecordedTestsSuite) TestFilesystemChangeLease() { + _require := require.New(s.T()) + testName := s.T().Name() + + //ignoreHeaders(_context.recording, headersToIgnoreForLease) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + fsName := testcommon.GenerateFilesystemName(testName) + fsClient := testcommon.CreateNewFilesystem(context.Background(), _require, fsName, svcClient) + defer testcommon.DeleteFilesystem(context.Background(), _require, fsClient) + + fsLeaseClient, _ := lease.NewFilesystemClient(fsClient, &lease.FilesystemClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + + ctx := context.Background() + acquireLeaseResponse, err := fsLeaseClient.AcquireLease(ctx, int32(15), nil) + _require.Nil(err) + _require.NotNil(acquireLeaseResponse.LeaseID) + _require.EqualValues(*acquireLeaseResponse.LeaseID, *fsLeaseClient.LeaseID()) + + changeLeaseResp, err := fsLeaseClient.ChangeLease(ctx, *proposedLeaseIDs[1], nil) + _require.Nil(err) + _require.EqualValues(changeLeaseResp.LeaseID, proposedLeaseIDs[1]) + _require.EqualValues(fsLeaseClient.LeaseID(), proposedLeaseIDs[1]) + + _, err = fsLeaseClient.RenewLease(ctx, nil) + _require.Nil(err) + + _, err = fsLeaseClient.ReleaseLease(ctx, nil) + _require.Nil(err) +} + +func (s *LeaseRecordedTestsSuite) TestFileAcquireLease() { + _require := require.New(s.T()) + testName := s.T().Name() + + //ignoreHeaders(_context.recording, headersToIgnoreForLease) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + filesystemName := testcommon.GenerateFilesystemName(testName) + filesystemClient := testcommon.CreateNewFilesystem(context.Background(), _require, filesystemName, svcClient) + defer testcommon.DeleteFilesystem(context.Background(), _require, filesystemClient) + + fileName := testcommon.GenerateFileName(testName) + fileClient := testcommon.CreateNewFile(context.Background(), _require, fileName, filesystemClient) + fileLeaseClient, err := lease.NewPathClient(fileClient, &lease.PathClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + _require.NoError(err) + + ctx := context.Background() + acquireLeaseResponse, err := fileLeaseClient.AcquireLease(ctx, int32(60), nil) + _require.Nil(err) + _require.NotNil(acquireLeaseResponse.LeaseID) + _require.EqualValues(acquireLeaseResponse.LeaseID, fileLeaseClient.LeaseID()) + + _, err = fileLeaseClient.ReleaseLease(ctx, nil) + _require.Nil(err) +} + +func (s *LeaseRecordedTestsSuite) TestDeleteFileWithoutLeaseId() { + _require := require.New(s.T()) + testName := s.T().Name() + + //ignoreHeaders(_context.recording, headersToIgnoreForLease) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + filesystemName := testcommon.GenerateFilesystemName(testName) + filesystemClient := testcommon.CreateNewFilesystem(context.Background(), _require, filesystemName, svcClient) + defer testcommon.DeleteFilesystem(context.Background(), _require, filesystemClient) + + fileName := testcommon.GenerateFileName(testName) + fileClient := testcommon.CreateNewFile(context.Background(), _require, fileName, filesystemClient) + fileLeaseClient, err := lease.NewPathClient(fileClient, &lease.PathClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + _require.NoError(err) + + ctx := context.Background() + acquireLeaseResponse, err := fileLeaseClient.AcquireLease(ctx, int32(60), nil) + _require.Nil(err) + _require.NotNil(acquireLeaseResponse.LeaseID) + _require.EqualValues(acquireLeaseResponse.LeaseID, fileLeaseClient.LeaseID()) + + _, err = fileClient.Delete(ctx, nil) + _require.NotNil(err) + + leaseID := fileLeaseClient.LeaseID() + _, err = fileClient.Delete(ctx, &file.DeleteOptions{ + AccessConditions: &file.AccessConditions{ + LeaseAccessConditions: &file.LeaseAccessConditions{ + LeaseID: leaseID, + }, + }, + }) + _require.Nil(err) +} + +func (s *LeaseRecordedTestsSuite) TestFileReleaseLease() { + _require := require.New(s.T()) + testName := s.T().Name() + + //ignoreHeaders(_context.recording, headersToIgnoreForLease) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + filesystemName := testcommon.GenerateFilesystemName(testName) + filesystemClient := testcommon.CreateNewFilesystem(context.Background(), _require, filesystemName, svcClient) + defer testcommon.DeleteFilesystem(context.Background(), _require, filesystemClient) + + fileName := testcommon.GenerateFileName(testName) + fileClient := testcommon.CreateNewFile(context.Background(), _require, fileName, filesystemClient) + fileLeaseClient, _ := lease.NewPathClient(fileClient, &lease.PathClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + + ctx := context.Background() + acquireLeaseResponse, err := fileLeaseClient.AcquireLease(ctx, int32(60), nil) + _require.Nil(err) + _require.NotNil(acquireLeaseResponse.LeaseID) + _require.EqualValues(acquireLeaseResponse.LeaseID, fileLeaseClient.LeaseID()) + + _, err = fileClient.Delete(ctx, nil) + _require.NotNil(err) + + _, err = fileLeaseClient.ReleaseLease(ctx, nil) + _require.Nil(err) + + _, err = fileClient.Delete(ctx, nil) + _require.Nil(err) +} + +func (s *LeaseRecordedTestsSuite) TestFileRenewLease() { + _require := require.New(s.T()) + testName := s.T().Name() + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + filesystemName := testcommon.GenerateFilesystemName(testName) + filesystemClient := testcommon.CreateNewFilesystem(context.Background(), _require, filesystemName, svcClient) + defer testcommon.DeleteFilesystem(context.Background(), _require, filesystemClient) + + fileName := testcommon.GenerateFileName(testName) + fileClient := testcommon.CreateNewFile(context.Background(), _require, fileName, filesystemClient) + fileLeaseClient, _ := lease.NewPathClient(fileClient, &lease.PathClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + + ctx := context.Background() + acquireLeaseResponse, err := fileLeaseClient.AcquireLease(ctx, int32(15), nil) + _require.Nil(err) + _require.NotNil(acquireLeaseResponse.LeaseID) + _require.EqualValues(acquireLeaseResponse.LeaseID, fileLeaseClient.LeaseID()) + + _, err = fileLeaseClient.RenewLease(ctx, nil) + _require.Nil(err) + + _, err = fileLeaseClient.ReleaseLease(ctx, nil) + _require.Nil(err) +} + +func (s *LeaseRecordedTestsSuite) TestFileChangeLease() { + _require := require.New(s.T()) + testName := s.T().Name() + + //ignoreHeaders(_context.recording, headersToIgnoreForLease) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + filesystemName := testcommon.GenerateFilesystemName(testName) + filesystemClient := testcommon.CreateNewFilesystem(context.Background(), _require, filesystemName, svcClient) + defer testcommon.DeleteFilesystem(context.Background(), _require, filesystemClient) + + fileName := testcommon.GenerateFileName(testName) + fileClient := testcommon.CreateNewFile(context.Background(), _require, fileName, filesystemClient) + fileLeaseClient, _ := lease.NewPathClient(fileClient, &lease.PathClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + + ctx := context.Background() + acquireLeaseResponse, err := fileLeaseClient.AcquireLease(ctx, int32(15), nil) + _require.Nil(err) + _require.NotNil(acquireLeaseResponse.LeaseID) + _require.Equal(*acquireLeaseResponse.LeaseID, *proposedLeaseIDs[0]) + + changeLeaseResp, err := fileLeaseClient.ChangeLease(ctx, *proposedLeaseIDs[1], nil) + _require.Nil(err) + _require.Equal(*changeLeaseResp.LeaseID, *proposedLeaseIDs[1]) + + _, err = fileLeaseClient.RenewLease(ctx, nil) + _require.Nil(err) + + _, err = fileLeaseClient.ReleaseLease(ctx, nil) + _require.Nil(err) +} + +func (s *LeaseRecordedTestsSuite) TestDirAcquireLease() { + _require := require.New(s.T()) + testName := s.T().Name() + + //ignoreHeaders(_context.recording, headersToIgnoreForLease) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + filesystemName := testcommon.GenerateFilesystemName(testName) + filesystemClient := testcommon.CreateNewFilesystem(context.Background(), _require, filesystemName, svcClient) + defer testcommon.DeleteFilesystem(context.Background(), _require, filesystemClient) + + dirName := testcommon.GenerateDirName(testName) + dirClient := testcommon.CreateNewDir(context.Background(), _require, dirName, filesystemClient) + dirLeaseClient, err := lease.NewPathClient(dirClient, &lease.PathClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + _require.NoError(err) + + ctx := context.Background() + acquireLeaseResponse, err := dirLeaseClient.AcquireLease(ctx, int32(60), nil) + _require.Nil(err) + _require.NotNil(acquireLeaseResponse.LeaseID) + _require.EqualValues(acquireLeaseResponse.LeaseID, dirLeaseClient.LeaseID()) + + _, err = dirLeaseClient.ReleaseLease(ctx, nil) + _require.Nil(err) +} + +func (s *LeaseRecordedTestsSuite) TestDeleteDirWithoutLeaseId() { + _require := require.New(s.T()) + testName := s.T().Name() + + //ignoreHeaders(_context.recording, headersToIgnoreForLease) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + filesystemName := testcommon.GenerateFilesystemName(testName) + filesystemClient := testcommon.CreateNewFilesystem(context.Background(), _require, filesystemName, svcClient) + defer testcommon.DeleteFilesystem(context.Background(), _require, filesystemClient) + + dirName := testcommon.GenerateDirName(testName) + dirClient := testcommon.CreateNewDir(context.Background(), _require, dirName, filesystemClient) + dirLeaseClient, err := lease.NewPathClient(dirClient, &lease.PathClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + _require.NoError(err) + + ctx := context.Background() + acquireLeaseResponse, err := dirLeaseClient.AcquireLease(ctx, int32(60), nil) + _require.Nil(err) + _require.NotNil(acquireLeaseResponse.LeaseID) + _require.EqualValues(acquireLeaseResponse.LeaseID, dirLeaseClient.LeaseID()) + + _, err = dirClient.Delete(ctx, nil) + _require.NotNil(err) + + leaseID := dirLeaseClient.LeaseID() + _, err = dirClient.Delete(ctx, &file.DeleteOptions{ + AccessConditions: &file.AccessConditions{ + LeaseAccessConditions: &file.LeaseAccessConditions{ + LeaseID: leaseID, + }, + }, + }) + _require.Nil(err) +} + +func (s *LeaseRecordedTestsSuite) TestDirReleaseLease() { + _require := require.New(s.T()) + testName := s.T().Name() + + //ignoreHeaders(_context.recording, headersToIgnoreForLease) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + filesystemName := testcommon.GenerateFilesystemName(testName) + filesystemClient := testcommon.CreateNewFilesystem(context.Background(), _require, filesystemName, svcClient) + defer testcommon.DeleteFilesystem(context.Background(), _require, filesystemClient) + + DirName := testcommon.GenerateDirName(testName) + DirClient := testcommon.CreateNewDir(context.Background(), _require, DirName, filesystemClient) + DirLeaseClient, _ := lease.NewPathClient(DirClient, &lease.PathClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + + ctx := context.Background() + acquireLeaseResponse, err := DirLeaseClient.AcquireLease(ctx, int32(60), nil) + _require.Nil(err) + _require.NotNil(acquireLeaseResponse.LeaseID) + _require.EqualValues(acquireLeaseResponse.LeaseID, DirLeaseClient.LeaseID()) + + _, err = DirClient.Delete(ctx, nil) + _require.NotNil(err) + + _, err = DirLeaseClient.ReleaseLease(ctx, nil) + _require.Nil(err) + + _, err = DirClient.Delete(ctx, nil) + _require.Nil(err) +} + +func (s *LeaseRecordedTestsSuite) TestDirRenewLease() { + _require := require.New(s.T()) + testName := s.T().Name() + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + filesystemName := testcommon.GenerateFilesystemName(testName) + filesystemClient := testcommon.CreateNewFilesystem(context.Background(), _require, filesystemName, svcClient) + defer testcommon.DeleteFilesystem(context.Background(), _require, filesystemClient) + + dirName := testcommon.GenerateDirName(testName) + dirClient := testcommon.CreateNewDir(context.Background(), _require, dirName, filesystemClient) + dirLeaseClient, _ := lease.NewPathClient(dirClient, &lease.PathClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + + ctx := context.Background() + acquireLeaseResponse, err := dirLeaseClient.AcquireLease(ctx, int32(15), nil) + _require.Nil(err) + _require.NotNil(acquireLeaseResponse.LeaseID) + _require.EqualValues(acquireLeaseResponse.LeaseID, dirLeaseClient.LeaseID()) + + _, err = dirLeaseClient.RenewLease(ctx, nil) + _require.Nil(err) + + _, err = dirLeaseClient.ReleaseLease(ctx, nil) + _require.Nil(err) +} + +func (s *LeaseRecordedTestsSuite) TestDirChangeLease() { + _require := require.New(s.T()) + testName := s.T().Name() + + //ignoreHeaders(_context.recording, headersToIgnoreForLease) + + svcClient, err := testcommon.GetServiceClient(s.T(), testcommon.TestAccountDatalake, nil) + _require.NoError(err) + + filesystemName := testcommon.GenerateFilesystemName(testName) + filesystemClient := testcommon.CreateNewFilesystem(context.Background(), _require, filesystemName, svcClient) + defer testcommon.DeleteFilesystem(context.Background(), _require, filesystemClient) + + dirName := testcommon.GenerateDirName(testName) + dirClient := testcommon.CreateNewDir(context.Background(), _require, dirName, filesystemClient) + dirLeaseClient, _ := lease.NewPathClient(dirClient, &lease.PathClientOptions{ + LeaseID: proposedLeaseIDs[0], + }) + + ctx := context.Background() + acquireLeaseResponse, err := dirLeaseClient.AcquireLease(ctx, int32(15), nil) + _require.Nil(err) + _require.NotNil(acquireLeaseResponse.LeaseID) + _require.Equal(*acquireLeaseResponse.LeaseID, *proposedLeaseIDs[0]) + + changeLeaseResp, err := dirLeaseClient.ChangeLease(ctx, *proposedLeaseIDs[1], nil) + _require.Nil(err) + _require.Equal(*changeLeaseResp.LeaseID, *proposedLeaseIDs[1]) + + _, err = dirLeaseClient.RenewLease(ctx, nil) + _require.Nil(err) + + _, err = dirLeaseClient.ReleaseLease(ctx, nil) + _require.Nil(err) +} diff --git a/sdk/storage/azdatalake/lease/models.go b/sdk/storage/azdatalake/lease/models.go index c09d30a21b40..ce552403c698 100644 --- a/sdk/storage/azdatalake/lease/models.go +++ b/sdk/storage/azdatalake/lease/models.go @@ -18,6 +18,9 @@ type FilesystemAcquireOptions struct { } func (o *FilesystemAcquireOptions) format() *lease.ContainerAcquireOptions { + if o == nil || o.ModifiedAccessConditions == nil { + return nil + } return &lease.ContainerAcquireOptions{ ModifiedAccessConditions: &blob.ModifiedAccessConditions{ IfModifiedSince: o.ModifiedAccessConditions.IfModifiedSince, @@ -35,6 +38,14 @@ type FilesystemBreakOptions struct { } func (o *FilesystemBreakOptions) format() *lease.ContainerBreakOptions { + opts := &lease.ContainerBreakOptions{} + if o == nil { + return opts + } + if o.ModifiedAccessConditions == nil { + opts.BreakPeriod = o.BreakPeriod + return opts + } return &lease.ContainerBreakOptions{ BreakPeriod: o.BreakPeriod, ModifiedAccessConditions: &blob.ModifiedAccessConditions{ @@ -52,6 +63,9 @@ type FilesystemChangeOptions struct { } func (o *FilesystemChangeOptions) format() *lease.ContainerChangeOptions { + if o == nil || o.ModifiedAccessConditions == nil { + return nil + } return &lease.ContainerChangeOptions{ ModifiedAccessConditions: &blob.ModifiedAccessConditions{ IfModifiedSince: o.ModifiedAccessConditions.IfModifiedSince, @@ -67,6 +81,9 @@ type FilesystemReleaseOptions struct { } func (o *FilesystemReleaseOptions) format() *lease.ContainerReleaseOptions { + if o == nil || o.ModifiedAccessConditions == nil { + return nil + } return &lease.ContainerReleaseOptions{ ModifiedAccessConditions: &blob.ModifiedAccessConditions{ IfModifiedSince: o.ModifiedAccessConditions.IfModifiedSince, @@ -82,6 +99,9 @@ type FilesystemRenewOptions struct { } func (o *FilesystemRenewOptions) format() *lease.ContainerRenewOptions { + if o == nil || o.ModifiedAccessConditions == nil { + return nil + } return &lease.ContainerRenewOptions{ ModifiedAccessConditions: &blob.ModifiedAccessConditions{ IfModifiedSince: o.ModifiedAccessConditions.IfModifiedSince, @@ -98,6 +118,9 @@ type PathAcquireOptions struct { } func (o *PathAcquireOptions) format() *lease.BlobAcquireOptions { + if o == nil || o.ModifiedAccessConditions == nil { + return nil + } return &lease.BlobAcquireOptions{ ModifiedAccessConditions: &blob.ModifiedAccessConditions{ IfModifiedSince: o.ModifiedAccessConditions.IfModifiedSince, @@ -115,6 +138,14 @@ type PathBreakOptions struct { } func (o *PathBreakOptions) format() *lease.BlobBreakOptions { + opts := &lease.BlobBreakOptions{} + if o == nil { + return opts + } + if o.ModifiedAccessConditions == nil { + opts.BreakPeriod = o.BreakPeriod + return opts + } return &lease.BlobBreakOptions{ BreakPeriod: o.BreakPeriod, ModifiedAccessConditions: &blob.ModifiedAccessConditions{ @@ -132,6 +163,9 @@ type PathChangeOptions struct { } func (o *PathChangeOptions) format() *lease.BlobChangeOptions { + if o == nil || o.ModifiedAccessConditions == nil { + return nil + } return &lease.BlobChangeOptions{ ModifiedAccessConditions: &blob.ModifiedAccessConditions{ IfModifiedSince: o.ModifiedAccessConditions.IfModifiedSince, @@ -147,6 +181,9 @@ type PathReleaseOptions struct { } func (o *PathReleaseOptions) format() *lease.BlobReleaseOptions { + if o == nil || o.ModifiedAccessConditions == nil { + return nil + } return &lease.BlobReleaseOptions{ ModifiedAccessConditions: &blob.ModifiedAccessConditions{ IfModifiedSince: o.ModifiedAccessConditions.IfModifiedSince, @@ -162,6 +199,9 @@ type PathRenewOptions struct { } func (o *PathRenewOptions) format() *lease.BlobRenewOptions { + if o == nil || o.ModifiedAccessConditions == nil { + return nil + } return &lease.BlobRenewOptions{ ModifiedAccessConditions: &blob.ModifiedAccessConditions{ IfModifiedSince: o.ModifiedAccessConditions.IfModifiedSince, diff --git a/sdk/storage/azdatalake/lease/path_client.go b/sdk/storage/azdatalake/lease/path_client.go index ec7aa846c47e..97e785571c05 100644 --- a/sdk/storage/azdatalake/lease/path_client.go +++ b/sdk/storage/azdatalake/lease/path_client.go @@ -8,9 +8,14 @@ package lease import ( "context" + "fmt" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/lease" "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/directory" "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/file" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/base" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/exported" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azdatalake/internal/generated" ) // PathClient provides lease functionality for the underlying path client. @@ -20,17 +25,29 @@ type PathClient struct { } // PathClientOptions contains the optional values when creating a PathClient. -type PathClientOptions struct { - // LeaseID contains a caller-provided lease ID. - LeaseID *string -} +type PathClientOptions = lease.BlobClientOptions // NewPathClient creates a path lease client for the provided path client. // - client - an instance of a path client // - options - client options; pass nil to accept the default values func NewPathClient[T directory.Client | file.Client](client *T, options *PathClientOptions) (*PathClient, error) { - // TODO: set up blob lease client - return nil, nil + var blobClient *blockblob.Client + switch t := any(client).(type) { + case *directory.Client: + _, _, blobClient = base.InnerClients((*base.CompositeClient[generated.PathClient, generated.PathClient, blockblob.Client])(t)) + case *file.Client: + _, _, blobClient = base.InnerClients((*base.CompositeClient[generated.PathClient, generated.PathClient, blockblob.Client])(t)) + default: + return nil, fmt.Errorf("unhandled client type %T", client) + } + blobLeaseClient, err := lease.NewBlobClient(blobClient, options) + if err != nil { + return nil, exported.ConvertToDFSError(err) + } + return &PathClient{ + blobClient: blobLeaseClient, + leaseID: blobLeaseClient.LeaseID(), + }, nil } // LeaseID returns leaseID of the client. @@ -43,32 +60,41 @@ func (c *PathClient) LeaseID() *string { // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. func (c *PathClient) AcquireLease(ctx context.Context, duration int32, o *PathAcquireOptions) (PathAcquireResponse, error) { opts := o.format() - return c.blobClient.AcquireLease(ctx, duration, opts) + resp, err := c.blobClient.AcquireLease(ctx, duration, opts) + return resp, exported.ConvertToDFSError(err) } // BreakLease breaks the path's previously-acquired lease. func (c *PathClient) BreakLease(ctx context.Context, o *PathBreakOptions) (PathBreakResponse, error) { opts := o.format() - return c.blobClient.BreakLease(ctx, opts) + resp, err := c.blobClient.BreakLease(ctx, opts) + return resp, exported.ConvertToDFSError(err) } // ChangeLease changes the path's lease ID. // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. func (c *PathClient) ChangeLease(ctx context.Context, proposedID string, o *PathChangeOptions) (PathChangeResponse, error) { opts := o.format() - return c.blobClient.ChangeLease(ctx, proposedID, opts) + resp, err := c.blobClient.ChangeLease(ctx, proposedID, opts) + if err != nil { + return resp, exported.ConvertToDFSError(err) + } + c.leaseID = &proposedID + return resp, nil } // RenewLease renews the path's previously-acquired lease. // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. func (c *PathClient) RenewLease(ctx context.Context, o *PathRenewOptions) (PathRenewResponse, error) { opts := o.format() - return c.blobClient.RenewLease(ctx, opts) + resp, err := c.blobClient.RenewLease(ctx, opts) + return resp, exported.ConvertToDFSError(err) } // ReleaseLease releases the path's previously-acquired lease. // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. func (c *PathClient) ReleaseLease(ctx context.Context, o *PathReleaseOptions) (PathReleaseResponse, error) { opts := o.format() - return c.blobClient.ReleaseLease(ctx, opts) + resp, err := c.blobClient.ReleaseLease(ctx, opts) + return resp, exported.ConvertToDFSError(err) } diff --git a/sdk/storage/azdatalake/service/client.go b/sdk/storage/azdatalake/service/client.go index 33e96821f3bd..9a31c3f6a8ab 100644 --- a/sdk/storage/azdatalake/service/client.go +++ b/sdk/storage/azdatalake/service/client.go @@ -147,7 +147,7 @@ func (s *Client) getClientOptions() *base.ClientOptions { // The new filesystem.Client uses the same request policy pipeline as the Client. func (s *Client) NewFilesystemClient(filesystemName string) *filesystem.Client { filesystemURL := runtime.JoinPaths(s.generatedServiceClientWithDFS().Endpoint(), filesystemName) - filesystemURL, containerURL := shared.GetURLs(filesystemURL) + containerURL, filesystemURL := shared.GetURLs(filesystemURL) return (*filesystem.Client)(base.NewFilesystemClient(filesystemURL, containerURL, s.serviceClient().NewContainerClient(filesystemName), s.generatedServiceClientWithDFS().InternalClient().WithClientName(shared.FilesystemClient), s.sharedKey(), s.identityCredential(), s.getClientOptions())) } @@ -162,7 +162,7 @@ func (s *Client) GetUserDelegationCredential(ctx context.Context, info KeyInfo, getUserDelegationKeyOptions := o.format() udk, err := s.generatedServiceClientWithBlob().GetUserDelegationKey(ctx, info, getUserDelegationKeyOptions) if err != nil { - return nil, err + return nil, exported.ConvertToDFSError(err) } return exported.NewUserDelegationCredential(strings.Split(url.Host, ".")[0], udk.UserDelegationKey), nil