Skip to content

Commit

Permalink
Allowed clone and resize when backend's in suspended state
Browse files Browse the repository at this point in the history
  • Loading branch information
shashank-netapp authored Mar 25, 2024
1 parent f6abc86 commit 1bdfb9c
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 15 deletions.
3 changes: 0 additions & 3 deletions core/orchestrator_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -1264,9 +1264,6 @@ func (o *TridentOrchestrator) updateBackendByBackendUUID(
return nil, err
}

// Preserving user-state.
backend.SetUserState(originalBackend.UserState())

if err = o.validateBackendUpdate(originalBackend, backend); err != nil {
return nil, err
}
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ require (
github.com/spf13/afero v1.11.0
github.com/spf13/cobra v1.8.0
github.com/stretchr/testify v1.8.4
github.com/tidwall/gjson v1.17.1
github.com/vishvananda/netlink v1.1.0
github.com/zcalusic/sysinfo v1.0.2
go.uber.org/multierr v1.11.0 // github.com/uber-go/multierr
Expand Down Expand Up @@ -138,6 +139,8 @@ require (
github.com/rivo/uniseg v0.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect
go.mongodb.org/mongo-driver v1.13.1 // indirect
go.opentelemetry.io/otel v1.19.0 // indirect
Expand Down
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,13 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
Expand Down
10 changes: 0 additions & 10 deletions storage/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,11 +520,6 @@ func (b *StorageBackend) CloneVolume(
return nil, err
}

// Ensure provisioning is allowed
if !b.isProvisioningAllowed() {
return nil, fmt.Errorf("volume is not cloned because the backend %s is suspended", b.name)
}

// Ensure the internal names exist
if cloneVolConfig.InternalName == "" {
return nil, errors.New("internal name not set")
Expand Down Expand Up @@ -731,11 +726,6 @@ func (b *StorageBackend) ResizeVolume(ctx context.Context, volConfig *VolumeConf
return err
}

// Ensure provisioning is allowed
if !b.isProvisioningAllowed() {
return fmt.Errorf("volume is not resized because the backend %s is suspended", b.name)
}

// Determine volume size in bytes
requestedSize, err := utils.ConvertSizeToBytes(newSize)
if err != nil {
Expand Down
29 changes: 28 additions & 1 deletion storage/factory/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"

"github.com/ghodss/yaml"
"github.com/tidwall/gjson"

"github.com/netapp/trident/config"
. "github.com/netapp/trident/logging"
Expand Down Expand Up @@ -78,6 +79,14 @@ func NewStorageBackendForConfig(
}
}()

// Retrieving userBackendState that either has been set by the user via an update/creation of the tbc/backend.json
// or was previously stored in the config and the control flow is a part of the orchestrator bootstrap process.
var userBackendState storage.UserBackendState
if userBackendState, err = GetUserBackendState(ctx, configJSON); err != nil {
Logc(ctx).WithField("error", err).Error("Failed to get userBackendState from the config, setting it to default i.e. UserNormal")
}
Logc(ctx).WithField("userBackendState", userBackendState).Trace("Retrieved userBackendState from the config.")

driverProtocol, err := GetDriverProtocol(commonConfig.StorageDriverName, configJSON)
if err != nil {
Logc(ctx).WithField("error", err).Error("Failed to get driver protocol.")
Expand Down Expand Up @@ -111,7 +120,7 @@ func NewStorageBackendForConfig(

if err == nil {
sb.SetState(storage.Online)
sb.SetUserState(storage.UserNormal)
sb.SetUserState(userBackendState)
}
sb.SetBackendUUID(backendUUID)
sb.SetConfigRef(configRef)
Expand Down Expand Up @@ -193,3 +202,21 @@ func GetDriverProtocol(driverName, configJSON string) (string, error) {

return "", nil
}

// GetUserBackendState retrieves the userBackendState that was set by the user
// in the storage backend config file, either in tbc or backend.json.
func GetUserBackendState(ctx context.Context, configJSON string) (storage.UserBackendState, error) {
// gjon is a Go package that provides a fast and simple way to get values from a json document
value := gjson.Get(configJSON, "userBackendState")

// Converting the value to userBackendState and validating it.
// If validation failed i.e., any value other than suspended or normal is provided,
// by default userBackendState: UserNormal will be returned.
userBackendState := storage.UserBackendState(strings.ToLower(value.String()))
if err := userBackendState.Validate(); err != nil {
Logc(ctx).WithField("error", err).Error("Validation failed for user backend state.")
return storage.UserNormal, err
}

return userBackendState, nil
}
100 changes: 100 additions & 0 deletions storage/factory/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,3 +341,103 @@ func TestGetDriverProtocol(t *testing.T) {
_, err = GetDriverProtocol(config.OntapNASStorageDriverName, `{}`)
assert.NoError(t, err, "Failed to get protocol type.")
}

func TestGetUserBackendState(t *testing.T) {
empty := ""

// Function to create a FakeStorageDriverConfig.
configJSONFunc := func(userBackendState string) *drivers.FakeStorageDriverConfig {
return &drivers.FakeStorageDriverConfig{
CommonStorageDriverConfig: &drivers.CommonStorageDriverConfig{
Version: 1,
StoragePrefixRaw: json.RawMessage("{}"),
StoragePrefix: &empty,
Credentials: map[string]string{
"name": "secret1",
"type": "secret",
},
},
Username: "none",
Password: "none",
UserBackendState: userBackendState,
}
}

// Set of valid tests.
validTests := []struct {
name string
config *drivers.FakeStorageDriverConfig
output storage.UserBackendState
error bool
}{
{
name: "valid userBackendState userNormal",
config: configJSONFunc("normal"),
output: storage.UserNormal,
error: false,
},
{
name: "valid userBackendState userSuspended",
config: configJSONFunc("suspended"),
output: storage.UserSuspended,
error: false,
},
}

for _, tt := range validTests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
marshaledJSON, err := json.Marshal(tt.config)
if err != nil {
t.Fatal("Unable to marshal configJSON: ", err)
}
output, err := GetUserBackendState(context.Background(), string(marshaledJSON))
if tt.error {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
assert.Equal(t, tt.output, output)
})
}

// Set of invalid tests.
invalidTests := []struct {
name string
config *drivers.FakeStorageDriverConfig
output storage.UserBackendState
error bool
}{
{
name: "invalid userBackendState",
config: configJSONFunc("abcdef"),
output: storage.UserNormal,
error: true,
},
{
name: "missing userBackendState",
config: configJSONFunc(""),
output: storage.UserNormal,
error: true,
},
}

for _, tt := range invalidTests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
marshaledJSON, err := json.Marshal(tt.config)
if err != nil {
t.Fatal("Unable to marshal configJSON: ", err)
}
output, err := GetUserBackendState(context.Background(), string(marshaledJSON))
if tt.error {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
assert.Equal(t, tt.output, output)
})
}
}
3 changes: 2 additions & 1 deletion storage_drivers/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,8 @@ type FakeStorageDriverConfig struct {
Username string `json:"username"`
Password string `json:"password"`
// Dummy field for unit tests
VolumeAccess string `json:"volumeAccess"`
VolumeAccess string `json:"volumeAccess"`
UserBackendState string `json:"userBackendState"`
FakeStorageDriverPool
}

Expand Down

0 comments on commit 1bdfb9c

Please sign in to comment.