From 3d11caa8a2f5bf945a1757ed7b7ee2670086349a Mon Sep 17 00:00:00 2001 From: Lee Spottiswood Date: Fri, 8 Sep 2023 14:57:55 +0100 Subject: [PATCH] add support for retrieving IOPS tiers (#168) --- cmd/ecloud/ecloud.go | 1 + cmd/ecloud/ecloud_availabilityzone.go | 3 + cmd/ecloud/ecloud_availabilityzone_iops.go | 64 ++++++++++ .../ecloud_availabilityzone_iops_test.go | 68 +++++++++++ cmd/ecloud/ecloud_iops.go | 87 ++++++++++++++ cmd/ecloud/ecloud_iops_test.go | 109 ++++++++++++++++++ cmd/ecloud/output.go | 4 + go.mod | 2 +- go.sum | 4 +- test/mocks/mock_ecloudservice.go | 75 ++++++++++++ 10 files changed, 414 insertions(+), 3 deletions(-) create mode 100644 cmd/ecloud/ecloud_availabilityzone_iops.go create mode 100644 cmd/ecloud/ecloud_availabilityzone_iops_test.go create mode 100644 cmd/ecloud/ecloud_iops.go create mode 100644 cmd/ecloud/ecloud_iops_test.go diff --git a/cmd/ecloud/ecloud.go b/cmd/ecloud/ecloud.go index 2d95285..fa330f0 100644 --- a/cmd/ecloud/ecloud.go +++ b/cmd/ecloud/ecloud.go @@ -47,6 +47,7 @@ func ECloudRootCmd(f factory.ClientFactory, fs afero.Fs) *cobra.Command { cmd.AddCommand(ecloudHostSpecRootCmd(f)) cmd.AddCommand(ecloudImageRootCmd(f)) cmd.AddCommand(ecloudInstanceRootCmd(f)) + cmd.AddCommand(ecloudIOPSRootCmd(f)) cmd.AddCommand(ecloudIPAddressRootCmd(f)) cmd.AddCommand(ecloudLoadBalancerRootCmd(f)) cmd.AddCommand(ecloudLoadBalancerSpecRootCmd(f)) diff --git a/cmd/ecloud/ecloud_availabilityzone.go b/cmd/ecloud/ecloud_availabilityzone.go index d72ac53..598ed39 100644 --- a/cmd/ecloud/ecloud_availabilityzone.go +++ b/cmd/ecloud/ecloud_availabilityzone.go @@ -24,6 +24,9 @@ func ecloudAvailabilityZoneRootCmd(f factory.ClientFactory) *cobra.Command { cmd.AddCommand(ecloudAvailabilityZoneListCmd(f)) cmd.AddCommand(ecloudAvailabilityZoneShowCmd(f)) + // Child root commands + cmd.AddCommand(ecloudAvailabilityZoneIOPSRootCmd(f)) + return cmd } diff --git a/cmd/ecloud/ecloud_availabilityzone_iops.go b/cmd/ecloud/ecloud_availabilityzone_iops.go new file mode 100644 index 0000000..b026e5a --- /dev/null +++ b/cmd/ecloud/ecloud_availabilityzone_iops.go @@ -0,0 +1,64 @@ +package ecloud + +import ( + "errors" + "fmt" + + "github.com/ans-group/cli/internal/pkg/factory" + "github.com/ans-group/cli/internal/pkg/helper" + "github.com/ans-group/cli/internal/pkg/output" + "github.com/ans-group/sdk-go/pkg/service/ecloud" + "github.com/spf13/cobra" +) + +func ecloudAvailabilityZoneIOPSRootCmd(f factory.ClientFactory) *cobra.Command { + cmd := &cobra.Command{ + Use: "iops", + Short: "sub-commands relating to availability zone IOPS tiers", + Aliases: []string{ + "az", + }, + } + + // Child commands + cmd.AddCommand(ecloudAvailabilityZoneIOPSTierListCmd(f)) + + return cmd +} + +func ecloudAvailabilityZoneIOPSTierListCmd(f factory.ClientFactory) *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "Lists availability zone IOPS tiers", + Long: "This command lists availability zone IOPS tiers", + Example: "ans ecloud availabilityzone iops list", + Args: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return errors.New("Missing availability zone") + } + + return nil + }, + RunE: ecloudCobraRunEFunc(f, ecloudAvailabilityZoneIOPSTierList), + } + + cmd.Flags().String("name", "", "IOPS name for filtering") + + return cmd +} + +func ecloudAvailabilityZoneIOPSTierList(service ecloud.ECloudService, cmd *cobra.Command, args []string) error { + params, err := helper.GetAPIRequestParametersFromFlags(cmd, + helper.NewStringFilterFlagOption("name", "name"), + ) + if err != nil { + return err + } + + zones, err := service.GetAvailabilityZoneIOPSTiers(args[0], params) + if err != nil { + return fmt.Errorf("Error retrieving availability zones: %s", err) + } + + return output.CommandOutput(cmd, OutputECloudIOPSTierProvider(zones)) +} diff --git a/cmd/ecloud/ecloud_availabilityzone_iops_test.go b/cmd/ecloud/ecloud_availabilityzone_iops_test.go new file mode 100644 index 0000000..b52ae34 --- /dev/null +++ b/cmd/ecloud/ecloud_availabilityzone_iops_test.go @@ -0,0 +1,68 @@ +package ecloud + +import ( + "errors" + "testing" + + "github.com/ans-group/cli/internal/pkg/clierrors" + "github.com/ans-group/cli/test/mocks" + "github.com/ans-group/sdk-go/pkg/service/ecloud" + gomock "github.com/golang/mock/gomock" + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" +) + +func Test_ecloudAvailabilityZoneIOPSTiersListCmd_Args(t *testing.T) { + t.Run("ValidArgs_NoError", func(t *testing.T) { + err := ecloudAvailabilityZoneIOPSTierListCmd(nil).Args(nil, []string{"fwp-abcdef12"}) + + assert.Nil(t, err) + }) + + t.Run("InvalidArgs_Error", func(t *testing.T) { + err := ecloudAvailabilityZoneIOPSTierListCmd(nil).Args(nil, []string{}) + + assert.NotNil(t, err) + assert.Equal(t, "Missing availability zone", err.Error()) + }) +} + +func Test_ecloudAvailabilityZoneIOPSTiersList(t *testing.T) { + t.Run("DefaultRetrieve", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + service := mocks.NewMockECloudService(mockCtrl) + + service.EXPECT().GetAvailabilityZoneIOPSTiers("fwp-abcdef12", gomock.Any()).Return([]ecloud.IOPSTier{}, nil).Times(1) + + ecloudAvailabilityZoneIOPSTierList(service, &cobra.Command{}, []string{"fwp-abcdef12"}) + }) + + t.Run("MalformedFlag_ReturnsError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + service := mocks.NewMockECloudService(mockCtrl) + cmd := &cobra.Command{} + cmd.Flags().StringArray("filter", []string{"invalidfilter"}, "") + + err := ecloudAvailabilityZoneIOPSTierList(service, cmd, []string{}) + + assert.IsType(t, &clierrors.ErrInvalidFlagValue{}, err) + }) + + t.Run("GetAvailabilityZonesError_ReturnsError", func(t *testing.T) { + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + service := mocks.NewMockECloudService(mockCtrl) + + service.EXPECT().GetAvailabilityZoneIOPSTiers("fwp-abcdef12", gomock.Any()).Return([]ecloud.IOPSTier{}, errors.New("test error")).Times(1) + + err := ecloudAvailabilityZoneIOPSTierList(service, &cobra.Command{}, []string{"fwp-abcdef12"}) + + assert.Equal(t, "Error retrieving availability zone ports: test error", err.Error()) + }) +} diff --git a/cmd/ecloud/ecloud_iops.go b/cmd/ecloud/ecloud_iops.go new file mode 100644 index 0000000..d2066cc --- /dev/null +++ b/cmd/ecloud/ecloud_iops.go @@ -0,0 +1,87 @@ +package ecloud + +import ( + "errors" + "fmt" + + "github.com/ans-group/cli/internal/pkg/factory" + "github.com/ans-group/cli/internal/pkg/helper" + "github.com/ans-group/cli/internal/pkg/output" + "github.com/ans-group/sdk-go/pkg/service/ecloud" + "github.com/spf13/cobra" +) + +func ecloudIOPSRootCmd(f factory.ClientFactory) *cobra.Command { + cmd := &cobra.Command{ + Use: "iops", + Short: "sub-commands relating to IOPS tiers", + } + + // Child commands + cmd.AddCommand(ecloudIOPSTierListCmd(f)) + cmd.AddCommand(ecloudIOPSTierShowCmd(f)) + + return cmd +} + +func ecloudIOPSTierListCmd(f factory.ClientFactory) *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "Lists IOPS tiers", + Long: "This command lists IOPS tiers", + Example: "ans ecloud iops list", + RunE: ecloudCobraRunEFunc(f, ecloudIOPSTierList), + } + + cmd.Flags().String("name", "", "IOPS name for filtering") + + return cmd +} + +func ecloudIOPSTierList(service ecloud.ECloudService, cmd *cobra.Command, args []string) error { + params, err := helper.GetAPIRequestParametersFromFlags(cmd, + helper.NewStringFilterFlagOption("name", "name"), + ) + if err != nil { + return err + } + + tiers, err := service.GetIOPSTiers(params) + if err != nil { + return fmt.Errorf("Error retrieving IOPS tiers: %s", err) + } + + return output.CommandOutput(cmd, OutputECloudIOPSTierProvider(tiers)) +} + +func ecloudIOPSTierShowCmd(f factory.ClientFactory) *cobra.Command { + return &cobra.Command{ + Use: "show ...", + Short: "Shows an IOPS tier", + Long: "This command shows one or more IOPS tiers", + Example: "ans ecloud IOPS show iops-abcdef12", + Args: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return errors.New("Missing IOPS tier") + } + + return nil + }, + RunE: ecloudCobraRunEFunc(f, ecloudIOPSTierShow), + } +} + +func ecloudIOPSTierShow(service ecloud.ECloudService, cmd *cobra.Command, args []string) error { + var tiersList []ecloud.IOPSTier + for _, arg := range args { + tiers, err := service.GetIOPSTier(arg) + if err != nil { + output.OutputWithErrorLevelf("Error retrieving IOPS tier [%s]: %s", arg, err) + continue + } + + tiersList = append(tiersList, tiers) + } + + return output.CommandOutput(cmd, OutputECloudIOPSTierProvider(tiersList)) +} diff --git a/cmd/ecloud/ecloud_iops_test.go b/cmd/ecloud/ecloud_iops_test.go new file mode 100644 index 0000000..72b79b6 --- /dev/null +++ b/cmd/ecloud/ecloud_iops_test.go @@ -0,0 +1,109 @@ +package ecloud + +import ( + "errors" + "testing" + + "github.com/ans-group/cli/internal/pkg/clierrors" + "github.com/ans-group/cli/test/mocks" + "github.com/ans-group/cli/test/test_output" + "github.com/ans-group/sdk-go/pkg/service/ecloud" + gomock "github.com/golang/mock/gomock" + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" +) + +func Test_ecloudIOPSTierList(t *testing.T) { + t.Run("DefaultRetrieve", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + service := mocks.NewMockECloudService(mockCtrl) + + service.EXPECT().GetIOPSTiers(gomock.Any()).Return([]ecloud.IOPSTier{}, nil).Times(1) + + ecloudIOPSTierList(service, &cobra.Command{}, []string{}) + }) + + t.Run("MalformedFlag_ReturnsError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + service := mocks.NewMockECloudService(mockCtrl) + cmd := &cobra.Command{} + cmd.Flags().StringArray("filter", []string{"invalidfilter"}, "") + + err := ecloudIOPSTierList(service, cmd, []string{}) + + assert.IsType(t, &clierrors.ErrInvalidFlagValue{}, err) + }) + + t.Run("GetIOPSTiersError_ReturnsError", func(t *testing.T) { + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + service := mocks.NewMockECloudService(mockCtrl) + + service.EXPECT().GetIOPSTiers(gomock.Any()).Return([]ecloud.IOPSTier{}, errors.New("test error")).Times(1) + + err := ecloudIOPSTierList(service, &cobra.Command{}, []string{}) + + assert.Equal(t, "Error retrieving IOPS tiers: test error", err.Error()) + }) +} + +func Test_ecloudIOPSTierShowCmd_Args(t *testing.T) { + t.Run("ValidArgs_NoError", func(t *testing.T) { + err := ecloudIOPSTierShowCmd(nil).Args(nil, []string{"iops-abcdef12"}) + + assert.Nil(t, err) + }) + + t.Run("InvalidArgs_Error", func(t *testing.T) { + err := ecloudIOPSTierShowCmd(nil).Args(nil, []string{}) + + assert.NotNil(t, err) + assert.Equal(t, "Missing IOPS", err.Error()) + }) +} + +func Test_ecloudIOPSTierShow(t *testing.T) { + t.Run("SingleIOPS", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + service := mocks.NewMockECloudService(mockCtrl) + + service.EXPECT().GetIOPSTier("iops-abcdef12").Return(ecloud.IOPSTier{}, nil).Times(1) + + ecloudIOPSTierShow(service, &cobra.Command{}, []string{"iops-abcdef12"}) + }) + + t.Run("MultipleIOPSs", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + service := mocks.NewMockECloudService(mockCtrl) + + gomock.InOrder( + service.EXPECT().GetIOPSTier("iops-abcdef12").Return(ecloud.IOPSTier{}, nil), + service.EXPECT().GetIOPSTier("iops-abcdef23").Return(ecloud.IOPSTier{}, nil), + ) + + ecloudIOPSTierShow(service, &cobra.Command{}, []string{"iops-abcdef12", "iops-abcdef23"}) + }) + + t.Run("GetIOPSError_OutputsError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + service := mocks.NewMockECloudService(mockCtrl) + + service.EXPECT().GetIOPSTier("iops-abcdef12").Return(ecloud.IOPSTier{}, errors.New("test error")) + + test_output.AssertErrorOutput(t, "Error retrieving IOPS tier [iops-abcdef12]: test error\n", func() { + ecloudIOPSTierShow(service, &cobra.Command{}, []string{"iops-abcdef12"}) + }) + }) +} diff --git a/cmd/ecloud/output.go b/cmd/ecloud/output.go index 57d8149..473528a 100644 --- a/cmd/ecloud/output.go +++ b/cmd/ecloud/output.go @@ -479,3 +479,7 @@ func OutputECloudResourceTiersProvider(tiers []ecloud.ResourceTier) output.Outpu func OutputECloudNATOverloadRulesProvider(rules []ecloud.NATOverloadRule) output.OutputHandlerDataProvider { return output.NewSerializedOutputHandlerDataProvider(rules).WithDefaultFields([]string{"id", "name", "network_id", "subnet", "floating_ip_id", "action"}) } + +func OutputECloudIOPSTierProvider(tiers []ecloud.IOPSTier) output.OutputHandlerDataProvider { + return output.NewSerializedOutputHandlerDataProvider(tiers).WithDefaultFields([]string{"id", "name", "level"}) +} diff --git a/go.mod b/go.mod index 82df619..0d2900e 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/ans-group/cli go 1.18 require ( - github.com/ans-group/sdk-go v1.16.5 + github.com/ans-group/sdk-go v1.16.6 github.com/blang/semver v3.5.1+incompatible github.com/golang/mock v1.6.0 github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 diff --git a/go.sum b/go.sum index 6cc7da5..3f3e679 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ans-group/go-durationstring v1.2.0 h1:UJIuQATkp0t1rBvZsHRwki33YHV9E+Ulro+3NbMB7MM= github.com/ans-group/go-durationstring v1.2.0/go.mod h1:QGF9Mdpq9058QXaut8r55QWu6lcHX6i/GvF1PZVkV6o= -github.com/ans-group/sdk-go v1.16.5 h1:FoBcdhM209iS2EfjVfq98GrDJNlJRu2mygZ0Xi8Mb3Q= -github.com/ans-group/sdk-go v1.16.5/go.mod h1:p1vrXBxHPvMOGlS4sFUSgeLeKAl9vIe/lJ6UaExe49A= +github.com/ans-group/sdk-go v1.16.6 h1:WPdKk8Ze8SDh2afStBWmaLdufPhLxYgGdEKThIboD24= +github.com/ans-group/sdk-go v1.16.6/go.mod h1:p1vrXBxHPvMOGlS4sFUSgeLeKAl9vIe/lJ6UaExe49A= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= diff --git a/test/mocks/mock_ecloudservice.go b/test/mocks/mock_ecloudservice.go index 66ac60d..1d94a9f 100644 --- a/test/mocks/mock_ecloudservice.go +++ b/test/mocks/mock_ecloudservice.go @@ -1325,6 +1325,36 @@ func (mr *MockECloudServiceMockRecorder) GetAvailabilityZone(arg0 interface{}) * return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAvailabilityZone", reflect.TypeOf((*MockECloudService)(nil).GetAvailabilityZone), arg0) } +// GetAvailabilityZoneIOPSTiers mocks base method. +func (m *MockECloudService) GetAvailabilityZoneIOPSTiers(arg0 string, arg1 connection.APIRequestParameters) ([]ecloud.IOPSTier, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAvailabilityZoneIOPSTiers", arg0, arg1) + ret0, _ := ret[0].([]ecloud.IOPSTier) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAvailabilityZoneIOPSTiers indicates an expected call of GetAvailabilityZoneIOPSTiers. +func (mr *MockECloudServiceMockRecorder) GetAvailabilityZoneIOPSTiers(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAvailabilityZoneIOPSTiers", reflect.TypeOf((*MockECloudService)(nil).GetAvailabilityZoneIOPSTiers), arg0, arg1) +} + +// GetAvailabilityZoneIOPSTiersPaginated mocks base method. +func (m *MockECloudService) GetAvailabilityZoneIOPSTiersPaginated(arg0 string, arg1 connection.APIRequestParameters) (*connection.Paginated[ecloud.IOPSTier], error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAvailabilityZoneIOPSTiersPaginated", arg0, arg1) + ret0, _ := ret[0].(*connection.Paginated[ecloud.IOPSTier]) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAvailabilityZoneIOPSTiersPaginated indicates an expected call of GetAvailabilityZoneIOPSTiersPaginated. +func (mr *MockECloudServiceMockRecorder) GetAvailabilityZoneIOPSTiersPaginated(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAvailabilityZoneIOPSTiersPaginated", reflect.TypeOf((*MockECloudService)(nil).GetAvailabilityZoneIOPSTiersPaginated), arg0, arg1) +} + // GetAvailabilityZones mocks base method. func (m *MockECloudService) GetAvailabilityZones(arg0 connection.APIRequestParameters) ([]ecloud.AvailabilityZone, error) { m.ctrl.T.Helper() @@ -2090,6 +2120,51 @@ func (mr *MockECloudServiceMockRecorder) GetHostsPaginated(arg0 interface{}) *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHostsPaginated", reflect.TypeOf((*MockECloudService)(nil).GetHostsPaginated), arg0) } +// GetIOPSTier mocks base method. +func (m *MockECloudService) GetIOPSTier(arg0 string) (ecloud.IOPSTier, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetIOPSTier", arg0) + ret0, _ := ret[0].(ecloud.IOPSTier) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetIOPSTier indicates an expected call of GetIOPSTier. +func (mr *MockECloudServiceMockRecorder) GetIOPSTier(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetIOPSTier", reflect.TypeOf((*MockECloudService)(nil).GetIOPSTier), arg0) +} + +// GetIOPSTiers mocks base method. +func (m *MockECloudService) GetIOPSTiers(arg0 connection.APIRequestParameters) ([]ecloud.IOPSTier, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetIOPSTiers", arg0) + ret0, _ := ret[0].([]ecloud.IOPSTier) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetIOPSTiers indicates an expected call of GetIOPSTiers. +func (mr *MockECloudServiceMockRecorder) GetIOPSTiers(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetIOPSTiers", reflect.TypeOf((*MockECloudService)(nil).GetIOPSTiers), arg0) +} + +// GetIOPSTiersPaginated mocks base method. +func (m *MockECloudService) GetIOPSTiersPaginated(arg0 connection.APIRequestParameters) (*connection.Paginated[ecloud.IOPSTier], error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetIOPSTiersPaginated", arg0) + ret0, _ := ret[0].(*connection.Paginated[ecloud.IOPSTier]) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetIOPSTiersPaginated indicates an expected call of GetIOPSTiersPaginated. +func (mr *MockECloudServiceMockRecorder) GetIOPSTiersPaginated(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetIOPSTiersPaginated", reflect.TypeOf((*MockECloudService)(nil).GetIOPSTiersPaginated), arg0) +} + // GetIPAddress mocks base method. func (m *MockECloudService) GetIPAddress(arg0 string) (ecloud.IPAddress, error) { m.ctrl.T.Helper()