diff --git a/README.md b/README.md index 55430e5..30fcef5 100644 --- a/README.md +++ b/README.md @@ -26,4 +26,3 @@ Follow the steps to run integration tests: 4. To get the integration test coverage for each module, run `make go-coverage`. 5. To generate and analyze coverage statistics, run `go tool cover -html=gounity_coverprofile.out`. - diff --git a/api/apiconstants.go b/api/apiconstants.go index 09d36cd..57b28c5 100644 --- a/api/apiconstants.go +++ b/api/apiconstants.go @@ -96,6 +96,9 @@ const ( UnityListHostInitiatorsURI = unityAPITypes + "/hostInitiator/instances?fields=" UnityModifyHostInitiators = unityRootAPI + "/instances/hostInitiator/%s/action/modify" + // UnityListHostsURI gets Hosts URIs + UnityListHostsURI = unityAPITypes + "/host/instances?fields=" + // UnityInstancesFilter does Unity Instance Filter UnityInstancesFilter = UnityAPIInstanceTypeResources + "?filter=%s" diff --git a/api/restclient.go b/api/restclient.go index 763cbc3..2b1dc97 100644 --- a/api/restclient.go +++ b/api/restclient.go @@ -299,7 +299,7 @@ func (c *client) DoAndGetResponseBody(ctx context.Context, method, uri string, h // send the request req = req.WithContext(ctx) - if res, err = c.http.Do(req); err != nil { + if res, err = c.http.Do(req); err != nil { // #nosec G704 return nil, err } diff --git a/apitypes/response.go b/apitypes/response.go index 8b455dd..a432f02 100644 --- a/apitypes/response.go +++ b/apitypes/response.go @@ -161,6 +161,11 @@ type HostContent struct { Address string `json:"address,omitempty"` } +// ListHost struct to capture host list +type ListHost struct { + Hosts []Host `json:"entries"` +} + // Initiators struct to capture Initiator ID type Initiators struct { ID string `json:"id"` diff --git a/go.mod b/go.mod index 5b9cedf..13f2d7b 100644 --- a/go.mod +++ b/go.mod @@ -1,19 +1,19 @@ module github.com/dell/gounity -go 1.25 +go 1.26 require ( github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.11.1 - google.golang.org/grpc v1.77.0 + google.golang.org/grpc v1.80.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.3 // indirect - golang.org/x/sys v0.38.0 // indirect + golang.org/x/sys v0.40.0 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index d3c686c..c84b775 100644 --- a/go.sum +++ b/go.sum @@ -15,19 +15,19 @@ github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+Q github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= -golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= -google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/host.go b/host.go index b3ff911..927c5e3 100644 --- a/host.go +++ b/host.go @@ -97,6 +97,17 @@ func (c *UnityClientImpl) DeleteHost(ctx context.Context, hostName string) error return nil } +// ListHosts lists all hosts +func (c *UnityClientImpl) ListHosts(ctx context.Context) ([]types.Host, error) { + listHostResp := &types.ListHost{} + listHostURI := api.UnityListHostsURI + HostfieldsToQuery + err := c.executeWithRetryAuthenticate(ctx, http.MethodGet, listHostURI, nil, listHostResp) + if err != nil { + return nil, err + } + return listHostResp.Hosts, nil +} + // CreateHostIPPort - Create Host IP Port func (c *UnityClientImpl) CreateHostIPPort(ctx context.Context, hostID, ip string) (*types.HostIPPort, error) { if len(hostID) == 0 { diff --git a/host_test.go b/host_test.go index 61349a6..654bc33 100644 --- a/host_test.go +++ b/host_test.go @@ -442,3 +442,25 @@ func TestFindHostInitiatorByID(t *testing.T) { _, err = testConf.client.FindHostInitiatorByID(ctx, "") assert.Error(t, err) } + +func TestListHosts(t *testing.T) { + fmt.Println("Begin - List All Hosts Test") + ctx := context.Background() + testConf.client.(*UnityClientImpl).api.(*mocksapi.Client).ExpectedCalls = nil + + // Mock setup for listing all hosts + testConf.client.(*UnityClientImpl).api.(*mocksapi.Client).On("DoWithHeaders", mock.Anything, "GET", "/api/types/host/instances?fields=id,name,description,fcHostInitiators,iscsiHostInitiators,hostIPPorts?fields", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + + hosts, err := testConf.client.ListHosts(ctx) + fmt.Println("List All Hosts", hosts, err) + if err != nil { + t.Fatalf("List All Hosts failed: %v", err) + } + + testConf.client.(*UnityClientImpl).api.(*mocksapi.Client).On("DoWithHeaders", mock.Anything, "GET", "/api/types/host/instances?fields=id,name,description,fcHostInitiators,iscsiHostInitiators,hostIPPorts?fields", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("list all hosts failed")).Once() + + _, err = testConf.client.ListHosts(ctx) + assert.Error(t, err) + + fmt.Println("List All Hosts Test Successful") +} diff --git a/mocks/UnityClient.go b/mocks/UnityClient.go index 83274f6..62b312d 100644 --- a/mocks/UnityClient.go +++ b/mocks/UnityClient.go @@ -1425,6 +1425,36 @@ func (_m *UnityClient) ListHostInitiators(ctx context.Context) ([]types.HostInit return r0, r1 } +// ListHosts provides a mock function with given fields: ctx +func (_m *UnityClient) ListHosts(ctx context.Context) ([]types.Host, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for ListHosts") + } + + var r0 []types.Host + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([]types.Host, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) []types.Host); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]types.Host) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // ListIscsiIPInterfaces provides a mock function with given fields: ctx func (_m *UnityClient) ListIscsiIPInterfaces(ctx context.Context) ([]types.IPInterfaceEntries, error) { ret := _m.Called(ctx) diff --git a/unityclient.go b/unityclient.go index add671b..5f06974 100644 --- a/unityclient.go +++ b/unityclient.go @@ -73,6 +73,7 @@ type UnityClient interface { CreateHostIPPort(ctx context.Context, hostID, ip string) (*types.HostIPPort, error) FindHostIPPortByID(ctx context.Context, hostIPID string) (*types.HostIPPort, error) ListHostInitiators(ctx context.Context) ([]types.HostInitiator, error) + ListHosts(ctx context.Context) ([]types.Host, error) FindHostInitiatorByName(ctx context.Context, wwnOrIqn string) (*types.HostInitiator, error) FindHostInitiatorByID(ctx context.Context, wwnOrIqn string) (*types.HostInitiator, error) CreateHostInitiator(ctx context.Context, hostID, wwnOrIqn string, initiatorType types.InitiatorType) (*types.HostInitiator, error)