Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Implement method to return bucket type from server #1898

Merged
merged 50 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
7086b8a
adding bucketType method
Tulsishah May 9, 2024
baa3a49
lint and linux test fix
Tulsishah May 9, 2024
c178aac
changing const variable name
Tulsishah May 9, 2024
69e3ab0
remove extra parameter
Tulsishah May 10, 2024
3d3f7b2
creating enum for bucket
Tulsishah May 10, 2024
03ff4c9
review comments
Tulsishah May 17, 2024
1bd7703
adding method to returin bucket type
Tulsishah May 9, 2024
fdcb1ad
lint and linux tests
Tulsishah May 9, 2024
ef21019
unit test
Tulsishah May 9, 2024
5383772
rebasing
Tulsishah May 10, 2024
a41f791
rebasing
Tulsishah May 10, 2024
1ce5093
creating method
Tulsishah May 10, 2024
d0586a3
unit tests
Tulsishah May 10, 2024
f0e32cb
small fix
Tulsishah May 10, 2024
6138131
lint fix
Tulsishah May 10, 2024
ab761ee
using setup teardown for unit tests
Tulsishah May 11, 2024
e464b8c
lint fix
Tulsishah May 11, 2024
f6b3c7e
setting Unknown bucket type
Tulsishah May 15, 2024
bf91883
adding method in bucket interface
Tulsishah May 20, 2024
cbe3352
unit tests update
Tulsishah May 20, 2024
ac5e572
unit tests update
Tulsishah May 20, 2024
c0c008a
lint fix
Tulsishah May 20, 2024
98654e9
lint fix
Tulsishah May 20, 2024
c46e8f1
lint fix
Tulsishah May 20, 2024
f45cdee
review comments
Tulsishah May 21, 2024
5174583
lint fix
Tulsishah May 21, 2024
28a01f7
review comment
Tulsishah May 21, 2024
37d34a8
review comment
Tulsishah May 21, 2024
b23a0e6
remove unnecessary code
Tulsishah May 21, 2024
a44b1fc
small fixes
Tulsishah May 21, 2024
4e3639c
adding one more unit tests
Tulsishah May 21, 2024
8ceec70
adding one more unit tests
Tulsishah May 21, 2024
d61b4db
go mod fix
Tulsishah May 21, 2024
99b5b69
go mod fix
Tulsishah May 21, 2024
da427cb
testing on VM
Tulsishah May 21, 2024
238d2f5
fix for nil control client
Tulsishah May 21, 2024
d6364fd
fix for nil control client
Tulsishah May 21, 2024
59c4209
lint fix
Tulsishah May 21, 2024
9107d4c
review comment
Tulsishah May 22, 2024
1db5c42
test fix
Tulsishah May 22, 2024
efdc715
rebasing
Tulsishah May 22, 2024
4fa8b51
addibg method in bucketType only
Tulsishah May 22, 2024
a956ea1
remove unnecessary code
Tulsishah May 22, 2024
5a9aa49
bucket type
Tulsishah May 22, 2024
b19a818
adding comment
Tulsishah May 22, 2024
e4fc608
small fix
Tulsishah May 22, 2024
d3560e0
removing wrapper struct
Tulsishah May 22, 2024
032df61
removing comment
Tulsishah May 22, 2024
0c9c385
adding StorageControlClient interface in mock struct
Tulsishah May 22, 2024
986ec08
adding comment
Tulsishah May 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ require (
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.2 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 // indirect
go.opentelemetry.io/otel v1.26.0 // indirect
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
Expand Down
3 changes: 3 additions & 0 deletions internal/gcsx/bucket_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,9 @@ func (bm *bucketManager) SetUpBucket(
bm.config.TmpObjectPrefix,
b)

// Fetch bucket type from storage layout api and set bucket type.
b.BucketType()

// Check whether this bucket works, giving the user a warning early if there
// is some problem.
{
Expand Down
54 changes: 51 additions & 3 deletions internal/storage/bucket_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,59 @@ import (
"net/http"

"cloud.google.com/go/storage"
control "cloud.google.com/go/storage/control/apiv2"
"cloud.google.com/go/storage/control/apiv2/controlpb"
"github.com/googleapis/gax-go/v2"
"github.com/googlecloudplatform/gcsfuse/v2/internal/logger"
"github.com/googlecloudplatform/gcsfuse/v2/internal/storage/gcs"
"github.com/googlecloudplatform/gcsfuse/v2/internal/storage/storageutil"

"google.golang.org/api/googleapi"
"google.golang.org/api/iterator"
)

type bucketHandle struct {
gcs.Bucket
bucket *storage.BucketHandle
bucketName string
bucketType gcs.BucketType
bucket *storage.BucketHandle
bucketName string
bucketType gcs.BucketType
controlClient StorageControlClientInterface
}

func (bh *bucketHandle) Name() string {
return bh.bucketName
}

func (bh *bucketHandle) BucketType() gcs.BucketType {
Tulsishah marked this conversation as resolved.
Show resolved Hide resolved
var nilControlClient *control.StorageControlClient = nil
// Note: The first invocation of this method will be slower due to a required Google Cloud Storage (GCS) fetch.
// Subsequent calls will be significantly faster as the results are cached in memory.
// While this operation is thread-safe, parallel calls during the initial fetch can result in redundant GCS requests.
// To avoid this, it's advisable to call this initially while mounting.
if bh.bucketType == gcs.Nil {
if bh.controlClient == nilControlClient {
bh.bucketType = gcs.NonHierarchical
return bh.bucketType
}

storageLayout, err := bh.getStorageLayout()

// In case bucket does not exist, set type unknown instead of panic.
if err != nil {
bh.bucketType = gcs.Unknown
logger.Errorf("Error returned from GetStorageLayout: %v", err)
return bh.bucketType
}

hierarchicalNamespace := storageLayout.GetHierarchicalNamespace()
if hierarchicalNamespace != nil && hierarchicalNamespace.Enabled {
bh.bucketType = gcs.Hierarchical
return bh.bucketType
}

bh.bucketType = gcs.NonHierarchical
}

return bh.bucketType
}

Expand Down Expand Up @@ -430,6 +465,19 @@ func (b *bucketHandle) ComposeObjects(ctx context.Context, req *gcs.ComposeObjec
return
}

// TODO: Consider adding this method to the bucket interface if additional
// layout options are needed in the future.
func (b *bucketHandle) getStorageLayout() (*controlpb.StorageLayout, error) {
var callOptions []gax.CallOption
stoargeLayout, err := b.controlClient.GetStorageLayout(context.Background(), &controlpb.GetStorageLayoutRequest{
Name: "projects/_/buckets/" + b.bucketName + "/storageLayout",
Prefix: "",
RequestId: "",
}, callOptions...)

return stoargeLayout, err
}

func isStorageConditionsNotEmpty(conditions storage.Conditions) bool {
return conditions != (storage.Conditions{})
}
62 changes: 62 additions & 0 deletions internal/storage/bucket_handle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ import (
"time"

"cloud.google.com/go/storage"
control "cloud.google.com/go/storage/control/apiv2"
"cloud.google.com/go/storage/control/apiv2/controlpb"
"github.com/googlecloudplatform/gcsfuse/v2/internal/storage/gcs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
)

Expand Down Expand Up @@ -1187,3 +1190,62 @@ func (testSuite *BucketHandleTest) TestComposeObjectMethodWithOneSrcObjectIsDstO
assert.NotNil(testSuite.T(), composedObj)
assert.Equal(testSuite.T(), len(ContentInTestObject)+len(ContentInTestSubObject), int(composedObj.Size))
}

func (testSuite *BucketHandleTest) TestBucketTypeForHierarchicalNameSpaceTrue() {
mockClient := new(MockStorageControlClient)
mockClient.On("GetStorageLayout", mock.Anything, mock.Anything, mock.Anything).
Return(&controlpb.StorageLayout{
HierarchicalNamespace: &controlpb.StorageLayout_HierarchicalNamespace{Enabled: true},
}, nil)
testSuite.bucketHandle.controlClient = mockClient

testSuite.bucketHandle.BucketType()

assert.Equal(testSuite.T(), gcs.Hierarchical, testSuite.bucketHandle.bucketType, "Expected Hierarchical bucket type")
}

func (testSuite *BucketHandleTest) TestBucketTypeForHierarchicalNameSpaceFalse() {
mockClient := new(MockStorageControlClient)
mockClient.On("GetStorageLayout", mock.Anything, mock.Anything, mock.Anything).
Return(&controlpb.StorageLayout{
HierarchicalNamespace: &controlpb.StorageLayout_HierarchicalNamespace{Enabled: false},
}, nil)
testSuite.bucketHandle.controlClient = mockClient

testSuite.bucketHandle.BucketType()

assert.Equal(testSuite.T(), gcs.NonHierarchical, testSuite.bucketHandle.bucketType, "Expected NonHierarchical bucket type")
}

func (testSuite *BucketHandleTest) TestBucketTypeWithError() {
var x *controlpb.StorageLayout
mockClient := new(MockStorageControlClient)
// Test when the client returns an error.
mockClient.On("GetStorageLayout", mock.Anything, mock.Anything, mock.Anything).
Return(x, errors.New("mocked error"))
testSuite.bucketHandle.controlClient = mockClient

testSuite.bucketHandle.BucketType()

assert.Equal(testSuite.T(), gcs.Unknown, testSuite.bucketHandle.bucketType, "Expected Unknown when there's an error")
}

func (testSuite *BucketHandleTest) TestBucketTypeWithHierarchicalNamespaceIsNil() {
mockClient := new(MockStorageControlClient)
mockClient.On("GetStorageLayout", mock.Anything, mock.Anything, mock.Anything).
Return(&controlpb.StorageLayout{}, nil)
testSuite.bucketHandle.controlClient = mockClient

testSuite.bucketHandle.BucketType()

assert.Equal(testSuite.T(), gcs.NonHierarchical, testSuite.bucketHandle.bucketType, "Expected NonHierarchical bucket type")
}

func (testSuite *BucketHandleTest) TestDefaultBucketTypeWithControlClientNil() {
var nilControlClient *control.StorageControlClient = nil
testSuite.bucketHandle.controlClient = nilControlClient

testSuite.bucketHandle.BucketType()

assert.Equal(testSuite.T(), gcs.NonHierarchical, testSuite.bucketHandle.bucketType, "Expected Hierarchical bucket type")
}
Tulsishah marked this conversation as resolved.
Show resolved Hide resolved
38 changes: 38 additions & 0 deletions internal/storage/control_client_wrapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2024 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package storage

import (
"context"

control "cloud.google.com/go/storage/control/apiv2"
"cloud.google.com/go/storage/control/apiv2/controlpb"
"github.com/googleapis/gax-go/v2"
)

// Define the interface
Tulsishah marked this conversation as resolved.
Show resolved Hide resolved
type StorageControlClientInterface interface {
GetStorageLayout(ctx context.Context,
req *controlpb.GetStorageLayoutRequest,
opts ...gax.CallOption) (*controlpb.StorageLayout, error)
}

type StorageControlClientWrapper struct {
Tulsishah marked this conversation as resolved.
Show resolved Hide resolved
*control.StorageControlClient
}

func (w *StorageControlClientWrapper) GetStorageLayout(ctx context.Context, req *controlpb.GetStorageLayoutRequest, opts ...gax.CallOption) (*controlpb.StorageLayout, error) {
return w.StorageControlClient.GetStorageLayout(ctx, req, opts...)
}
4 changes: 4 additions & 0 deletions internal/storage/fake/bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,10 @@ func (b *bucket) BucketType() gcs.BucketType {
return b.bucketType
}

func (b *bucket) FetchAndSetBucketType() {
Tulsishah marked this conversation as resolved.
Show resolved Hide resolved
b.bucketType = gcs.Unknown
}

// LOCKS_EXCLUDED(b.mu)
func (b *bucket) ListObjects(
ctx context.Context,
Expand Down
4 changes: 3 additions & 1 deletion internal/storage/gcs/bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ type BucketType int

// BucketType enum values.
const (
NonHierarchical BucketType = iota
Nil BucketType = iota
Tulsishah marked this conversation as resolved.
Show resolved Hide resolved
NonHierarchical
Hierarchical
Unknown
)

// Bucket represents a GCS bucket, pre-bound with a bucket name and necessary
Expand Down
36 changes: 36 additions & 0 deletions internal/storage/mock_control_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2024 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package storage

import (
"context"

"cloud.google.com/go/storage/control/apiv2/controlpb"
"github.com/googleapis/gax-go/v2"
"github.com/stretchr/testify/mock"
)

// MockStorageControlClient creates a mock version of the StorageControlClient.
type MockStorageControlClient struct {
Tulsishah marked this conversation as resolved.
Show resolved Hide resolved
mock.Mock
}

// Implement the GetStorageLayout method for the mock.
func (m *MockStorageControlClient) GetStorageLayout(ctx context.Context,
req *controlpb.GetStorageLayoutRequest,
opts ...gax.CallOption) (*controlpb.StorageLayout, error) {
args := m.Called(ctx, req, opts)
return args.Get(0).(*controlpb.StorageLayout), args.Error(1)
}
11 changes: 5 additions & 6 deletions internal/storage/storage_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"github.com/googleapis/gax-go/v2"
"github.com/googlecloudplatform/gcsfuse/v2/internal/logger"
mountpkg "github.com/googlecloudplatform/gcsfuse/v2/internal/mount"
"github.com/googlecloudplatform/gcsfuse/v2/internal/storage/gcs"
"github.com/googlecloudplatform/gcsfuse/v2/internal/storage/storageutil"
"golang.org/x/net/context"
option "google.golang.org/api/option"
Expand Down Expand Up @@ -206,10 +205,10 @@ func (sh *storageClient) BucketHandle(bucketName string, billingProject string)
storageBucketHandle = storageBucketHandle.UserProject(billingProject)
}

// TODO: Implement a method that determines and returns the appropriate bucket type
// when the enableHNS flag is set to true.
bucketType := gcs.NonHierarchical

bh = &bucketHandle{bucket: storageBucketHandle, bucketType: bucketType, bucketName: bucketName}
bh = &bucketHandle{
bucket: storageBucketHandle,
bucketName: bucketName,
controlClient: sh.storageControlClient,
}
return
}
4 changes: 2 additions & 2 deletions internal/storage/storage_handle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func (testSuite *StorageHandleTest) TestBucketHandleWhenBucketExistsWithEmptyBil

assert.NotNil(testSuite.T(), bucketHandle)
assert.Equal(testSuite.T(), TestBucketName, bucketHandle.bucketName)
assert.Equal(testSuite.T(), gcs.NonHierarchical, bucketHandle.bucketType)
assert.Equal(testSuite.T(), gcs.Nil, bucketHandle.bucketType)
}

func (testSuite *StorageHandleTest) TestBucketHandleWhenBucketDoesNotExistWithEmptyBillingProject() {
Expand All @@ -71,7 +71,7 @@ func (testSuite *StorageHandleTest) TestBucketHandleWhenBucketExistsWithNonEmpty

assert.NotNil(testSuite.T(), bucketHandle)
assert.Equal(testSuite.T(), TestBucketName, bucketHandle.bucketName)
assert.Equal(testSuite.T(), gcs.NonHierarchical, bucketHandle.bucketType)
assert.Equal(testSuite.T(), gcs.Nil, bucketHandle.bucketType)
}

func (testSuite *StorageHandleTest) TestBucketHandleWhenBucketDoesNotExistWithNonEmptyBillingProject() {
Expand Down
Loading