diff --git a/fault_set.go b/fault_set.go new file mode 100644 index 0000000..aeba2a9 --- /dev/null +++ b/fault_set.go @@ -0,0 +1,85 @@ +// Copyright © 2023 Dell Inc. or its subsidiaries. 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 goscaleio + +import ( + "fmt" + types "github.com/dell/goscaleio/types/v1" + "net/http" +) + +// CreateFaultSet creates a fault set +func (pd *ProtectionDomain) CreateFaultSet(fs *types.FaultSetParam) (string, error) { + path := fmt.Sprintf("/api/types/FaultSet/instances") + fs.ProtectionDomainID = pd.ProtectionDomain.ID + fsResp := types.FaultSetResp{} + err := pd.client.getJSONWithRetry( + http.MethodPost, path, fs, &fsResp) + if err != nil { + return "", err + } + return fsResp.ID, nil +} + +// DeleteFaultSet will delete a fault set +func (pd *ProtectionDomain) DeleteFaultSet(id string) error { + path := fmt.Sprintf("/api/instances/FaultSet::%v/action/removeFaultSet", id) + fsParam := &types.EmptyPayload{} + err := pd.client.getJSONWithRetry( + http.MethodPost, path, fsParam, nil) + if err != nil { + return err + } + return nil +} + +// ModifyFaultSetName will modify the name of the fault set +func (pd *ProtectionDomain) ModifyFaultSetName(id, name string) error { + fs := &types.FaultSetRename{} + fs.NewName = name + path := fmt.Sprintf("/api/instances/FaultSet::%v/action/setFaultSetName", id) + + err := pd.client.getJSONWithRetry( + http.MethodPost, path, fs, nil) + if err != nil { + return err + } + return nil +} + +// ModifyFaultSetPerfProfile will modify the performance profile of the fault set +func (pd *ProtectionDomain) ModifyFaultSetPerfProfile(id, perfProfile string) error { + pp := &types.ChangeSdcPerfProfile{} + pp.PerfProfile = perfProfile + path := fmt.Sprintf("/api/instances/FaultSet::%v/action/setSdsPerformanceParameters", id) + + err := pd.client.getJSONWithRetry( + http.MethodPost, path, pp, nil) + if err != nil { + return err + } + return nil +} + +// GetFaultSetByID will read the fault set using the ID. +func (system *System) GetFaultSetByID(id string) (*types.FaultSet, error) { + fs := &types.FaultSet{} + path := fmt.Sprintf("/api/instances/FaultSet::%v", id) + + err := system.client.getJSONWithRetry( + http.MethodGet, path, nil, fs) + if err != nil { + return nil, err + } + return fs, nil +} diff --git a/fault_set_test.go b/fault_set_test.go new file mode 100644 index 0000000..69f172c --- /dev/null +++ b/fault_set_test.go @@ -0,0 +1,268 @@ +// Copyright © 2023 Dell Inc. or its subsidiaries. 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 goscaleio + +import ( + "errors" + "math" + "net/http" + "net/http/httptest" + "testing" + + types "github.com/dell/goscaleio/types/v1" +) + +var ( + ID string + errFs error +) + +func TestCreateFaultSet(t *testing.T) { + type testCase struct { + fs *types.FaultSetParam + expected error + } + cases := []testCase{ + { + fs: &types.FaultSetParam{ + Name: "testFaultSet", + ProtectionDomainID: "202a046600000000", + }, + expected: nil, + }, + { + fs: &types.FaultSetParam{ + Name: "testFaultSet", + ProtectionDomainID: "202a0466000000", + }, + expected: errors.New("Invalid Protection Domain. Please try again with the correct ID or name."), + }, + } + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + })) + defer svr.Close() + + for _, tc := range cases { + tc := tc + t.Run("", func(ts *testing.T) { + client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + p := NewProtectionDomain(client) + + ID, errFs = p.CreateFaultSet(tc.fs) + if errFs != nil { + if tc.expected == nil { + t.Errorf("Creating fault set did not work as expected, \n\tgot: %s \n\twant: %v", errFs, tc.expected) + } else { + if errFs.Error() != tc.expected.Error() { + t.Errorf("Creating fault set did not work as expected, \n\tgot: %s \n\twant: %s", errFs, tc.expected) + } + } + } + }) + } +} + +func TestGetFaultByID(t *testing.T) { + type testCase struct { + id string + expected error + } + cases := []testCase{ + { + id: ID, + expected: nil, + }, + { + id: "1234", + expected: errors.New("Invalid Fault Set. Please try again with the correct ID or name."), + }, + } + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + })) + defer svr.Close() + + for _, tc := range cases { + tc := tc + t.Run("", func(ts *testing.T) { + client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + s := System{ + client: client, + } + _, err2 := s.GetFaultSetByID(tc.id) + if err2 != nil { + if tc.expected == nil { + t.Errorf("Fetching fault set did not work as expected, \n\tgot: %s \n\twant: %v", err2, tc.expected) + } else { + if err2.Error() != tc.expected.Error() { + t.Errorf("Fetching fault set did not work as expected, \n\tgot: %s \n\twant: %s", err2, tc.expected) + } + } + } + }) + } +} + +func TestModifyFaultSetName(t *testing.T) { + type testCase struct { + name string + id string + expected error + } + cases := []testCase{ + { + + id: ID, + name: "renameFaultSet", + expected: nil, + }, + { + id: "1234", + name: "renameFaultSet", + expected: errors.New("Invalid Fault Set. Please try again with the correct ID or name."), + }, + } + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + })) + defer svr.Close() + + for _, tc := range cases { + tc := tc + t.Run("", func(ts *testing.T) { + client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + p := ProtectionDomain{ + client: client, + } + err2 := p.ModifyFaultSetName(tc.id, tc.name) + if err2 != nil { + if tc.expected == nil { + t.Errorf("Modifying fault set did not work as expected, \n\tgot: %s \n\twant: %v", err2, tc.expected) + } else { + if err2.Error() != tc.expected.Error() { + t.Errorf("Modifying fault set did not work as expected, \n\tgot: %s \n\twant: %s", err2, tc.expected) + } + } + } + }) + } +} + +func TestModifyFaultPerfProfile(t *testing.T) { + type testCase struct { + perfProfile string + id string + expected error + } + cases := []testCase{ + { + + id: ID, + perfProfile: "Compact", + expected: nil, + }, + { + + id: ID, + perfProfile: "HighPerformance", + expected: nil, + }, + { + + id: ID, + perfProfile: "Invalid", + expected: errors.New("perfProfile should get one of the following values: Compact, HighPerformance, but its value is Invalid."), + }, + } + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + })) + defer svr.Close() + + for _, tc := range cases { + tc := tc + t.Run("", func(ts *testing.T) { + client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + p := ProtectionDomain{ + client: client, + } + err2 := p.ModifyFaultSetPerfProfile(tc.id, tc.perfProfile) + if err2 != nil { + if tc.expected == nil { + t.Errorf("Modifying fault set did not work as expected, \n\tgot: %s \n\twant: %v", err2, tc.expected) + } else { + if err2.Error() != tc.expected.Error() { + t.Errorf("Modifying fault set did not work as expected, \n\tgot: %s \n\twant: %s", err2, tc.expected) + } + } + } + }) + } +} + +func TestDeleteFaultSet(t *testing.T) { + type testCase struct { + id string + expected error + } + cases := []testCase{ + { + id: ID, + expected: nil, + }, + { + id: "1234", + expected: errors.New("Invalid Fault Set. Please try again with the correct ID or name."), + }, + } + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + })) + defer svr.Close() + + for _, tc := range cases { + tc := tc + t.Run("", func(ts *testing.T) { + client, err := NewClientWithArgs(svr.URL, "", math.MaxInt64, true, false) + if err != nil { + t.Fatal(err) + } + + p := ProtectionDomain{ + client: client, + } + err2 := p.DeleteFaultSet(tc.id) + if err2 != nil { + if tc.expected == nil { + t.Errorf("Removing fault set did not work as expected, \n\tgot: %s \n\twant: %v", err2, tc.expected) + } else { + if err2.Error() != tc.expected.Error() { + t.Errorf("Removing fault set did not work as expected, \n\tgot: %s \n\twant: %s", err2, tc.expected) + } + } + } + }) + } +} diff --git a/inttests/fault_set_test.go b/inttests/fault_set_test.go new file mode 100644 index 0000000..52bcf32 --- /dev/null +++ b/inttests/fault_set_test.go @@ -0,0 +1,66 @@ +// Copyright © 2023 Dell Inc. or its subsidiaries. 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 inttests + +import ( + "fmt" + "testing" + "time" + + types "github.com/dell/goscaleio/types/v1" + "github.com/stretchr/testify/assert" +) + +func TestCreateModifyDeleteFaultSet(t *testing.T) { + domain := getProtectionDomain(t) + system := getSystem() + assert.NotNil(t, domain) + assert.NotNil(t, system) + fsName := fmt.Sprintf("%s-%s", testPrefix, "FaultSet") + + fs := &types.FaultSetParam{ + Name: fsName, + ProtectionDomainID: domain.ProtectionDomain.ID, + } + + // create the fault set + fsID, err := domain.CreateFaultSet(fs) + assert.Nil(t, err) + assert.NotNil(t, fsID) + + // create a fault set that exists + fsID2, err2 := domain.CreateFaultSet(fs) + assert.NotNil(t, err2) + assert.Equal(t, "", fsID2) + + // modify fault set name + err = domain.ModifyFaultSetName(fsID, "faultSetRenamed") + assert.Nil(t, err) + + // modify fault set performance profile + err = domain.ModifyFaultSetPerfProfile(fsID, "Compact") + assert.Nil(t, err) + time.Sleep(5 * time.Second) + + // read the fault set + fsr, err := system.GetFaultSetByID(fsID) + assert.Equal(t, "faultSetRenamed", fsr.Name) + + // delete the fault set + err = domain.DeleteFaultSet(fsID) + assert.Nil(t, err) + + // try to delete non-existent fault set + err3 := domain.DeleteFaultSet(invalidIdentifier) + assert.NotNil(t, err3) +} diff --git a/types/v1/types.go b/types/v1/types.go index 6ec8a3b..2461054 100644 --- a/types/v1/types.go +++ b/types/v1/types.go @@ -1,4 +1,4 @@ -// Copyright © 2019 - 2022 Dell Inc. or its subsidiaries. All Rights Reserved. +// Copyright © 2019 - 2023 Dell Inc. or its subsidiaries. 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. @@ -1753,3 +1753,26 @@ type QuerySystemLimitsResponse struct { type QuerySystemLimitsParam struct { } + +// FaultSetParam is the parameters required to create a fault set +type FaultSetParam struct { + ProtectionDomainID string `json:"protectionDomainId"` + Name string `json:"name"` +} + +// FaultSetResp defines struct for the response when fault set is created successfully +type FaultSetResp struct { + ID string `json:"id"` +} + +// FaultSet defines struct for reading the fault set +type FaultSet struct { + ID string `json:"id"` + Name string `json:"name"` + ProtectionDomainId string `json:"protectionDomainId"` +} + +// FaultSetRename defines struct for renaming the fault set +type FaultSetRename struct { + NewName string `json:"newName"` +}