This is an automated email from the ASF dual-hosted git repository.

Pearl1594 pushed a commit to branch 4.22.1-stgAccGrp
in repository https://gitbox.apache.org/repos/asf/cloudstack-go.git

commit d4383f00c49ebfd5ccddc6a2a45493b13fb7ae31
Author: Pearl Dsilva <[email protected]>
AuthorDate: Tue May 19 11:25:08 2026 -0400

    Add support for managing Storage access groups
---
 cloudstack/PoolService.go      | 393 +++++++++++++++++++++++++++++++++++++++++
 cloudstack/PoolService_mock.go |  79 +++++++++
 generate/layout.go             |   2 +
 test/PoolService_test.go       |  24 +++
 4 files changed, 498 insertions(+)

diff --git a/cloudstack/PoolService.go b/cloudstack/PoolService.go
index 9ea2f50..641c527 100644
--- a/cloudstack/PoolService.go
+++ b/cloudstack/PoolService.go
@@ -45,6 +45,11 @@ type PoolServiceIface interface {
        NewSyncStoragePoolParams(id string) *SyncStoragePoolParams
        UpdateStoragePool(p *UpdateStoragePoolParams) 
(*UpdateStoragePoolResponse, error)
        NewUpdateStoragePoolParams(id string) *UpdateStoragePoolParams
+       ConfigureStorageAccess(p *ConfigureStorageAccessParams) 
(*StorageAccessResponse, error)
+       NewConfigureStorageAccessParams() *ConfigureStorageAccessParams
+       ListStorageAccessGroups(p *ListStorageAccessGroupsParams) 
(*ListStorageAccessGroupsResponse, error)
+       NewListStorageAccessGroupsParams() *ListStorageAccessGroupsParams
+       GetStorageAccessGroupID(name string, opts ...OptionFunc) (string, int, 
error)
 }
 
 type CreateStoragePoolParams struct {
@@ -1806,3 +1811,391 @@ type UpdateStoragePoolResponse struct {
        Zoneid               string            `json:"zoneid"`
        Zonename             string            `json:"zonename"`
 }
+
+type ConfigureStorageAccessParams struct {
+       p map[string]interface{}
+}
+
+func (p *ConfigureStorageAccessParams) toURLValues() url.Values {
+       u := url.Values{}
+       if p.p == nil {
+               return u
+       }
+       if v, found := p.p["clusterid"]; found {
+               u.Set("clusterid", v.(string))
+       }
+       if v, found := p.p["hostid"]; found {
+               u.Set("hostid", v.(string))
+       }
+       if v, found := p.p["podid"]; found {
+               u.Set("podid", v.(string))
+       }
+       if v, found := p.p["storageaccessgroups"]; found {
+               vv := strings.Join(v.([]string), ",")
+               u.Set("storageaccessgroups", vv)
+       }
+       if v, found := p.p["storageid"]; found {
+               u.Set("storageid", v.(string))
+       }
+       if v, found := p.p["zoneid"]; found {
+               u.Set("zoneid", v.(string))
+       }
+       return u
+}
+
+func (p *ConfigureStorageAccessParams) SetClusterid(v string) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       p.p["clusterid"] = v
+}
+
+func (p *ConfigureStorageAccessParams) ResetClusterid() {
+       if p.p != nil && p.p["clusterid"] != nil {
+               delete(p.p, "clusterid")
+       }
+}
+
+func (p *ConfigureStorageAccessParams) GetClusterid() (string, bool) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       value, ok := p.p["clusterid"].(string)
+       return value, ok
+}
+
+func (p *ConfigureStorageAccessParams) SetHostid(v string) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       p.p["hostid"] = v
+}
+
+func (p *ConfigureStorageAccessParams) ResetHostid() {
+       if p.p != nil && p.p["hostid"] != nil {
+               delete(p.p, "hostid")
+       }
+}
+
+func (p *ConfigureStorageAccessParams) GetHostid() (string, bool) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       value, ok := p.p["hostid"].(string)
+       return value, ok
+}
+
+func (p *ConfigureStorageAccessParams) SetPodid(v string) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       p.p["podid"] = v
+}
+
+func (p *ConfigureStorageAccessParams) ResetPodid() {
+       if p.p != nil && p.p["podid"] != nil {
+               delete(p.p, "podid")
+       }
+}
+
+func (p *ConfigureStorageAccessParams) GetPodid() (string, bool) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       value, ok := p.p["podid"].(string)
+       return value, ok
+}
+
+func (p *ConfigureStorageAccessParams) SetStorageaccessgroups(v []string) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       p.p["storageaccessgroups"] = v
+}
+
+func (p *ConfigureStorageAccessParams) ResetStorageaccessgroups() {
+       if p.p != nil && p.p["storageaccessgroups"] != nil {
+               delete(p.p, "storageaccessgroups")
+       }
+}
+
+func (p *ConfigureStorageAccessParams) GetStorageaccessgroups() ([]string, 
bool) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       value, ok := p.p["storageaccessgroups"].([]string)
+       return value, ok
+}
+
+func (p *ConfigureStorageAccessParams) SetStorageid(v string) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       p.p["storageid"] = v
+}
+
+func (p *ConfigureStorageAccessParams) ResetStorageid() {
+       if p.p != nil && p.p["storageid"] != nil {
+               delete(p.p, "storageid")
+       }
+}
+
+func (p *ConfigureStorageAccessParams) GetStorageid() (string, bool) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       value, ok := p.p["storageid"].(string)
+       return value, ok
+}
+
+func (p *ConfigureStorageAccessParams) SetZoneid(v string) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       p.p["zoneid"] = v
+}
+
+func (p *ConfigureStorageAccessParams) ResetZoneid() {
+       if p.p != nil && p.p["zoneid"] != nil {
+               delete(p.p, "zoneid")
+       }
+}
+
+func (p *ConfigureStorageAccessParams) GetZoneid() (string, bool) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       value, ok := p.p["zoneid"].(string)
+       return value, ok
+}
+
+// You should always use this function to get a new 
ConfigureStorageAccessParams instance,
+// as then you are sure you have configured all required params
+func (s *PoolService) NewConfigureStorageAccessParams() 
*ConfigureStorageAccessParams {
+       p := &ConfigureStorageAccessParams{}
+       p.p = make(map[string]interface{})
+       return p
+}
+
+// Configure the storage access groups on zone/pod/cluster/host and storage, 
accordingly connections to the storage pools
+func (s *PoolService) ConfigureStorageAccess(p *ConfigureStorageAccessParams) 
(*StorageAccessResponse, error) {
+       resp, err := s.cs.newPostRequest("configureStorageAccess", 
p.toURLValues())
+       if err != nil {
+               return nil, err
+       }
+
+       var r StorageAccessResponse
+       if err := json.Unmarshal(resp, &r); err != nil {
+               return nil, err
+       }
+
+       // If we have a async client, we need to wait for the async result
+       if s.cs.async {
+               b, err := s.cs.GetAsyncJobResult(r.JobID, s.cs.timeout)
+               if err != nil {
+                       if err == AsyncTimeoutErr {
+                               return &r, err
+                       }
+                       return nil, err
+               }
+
+               if err := json.Unmarshal(b, &r); err != nil {
+                       return nil, err
+               }
+       }
+
+       return &r, nil
+}
+
+type StorageAccessResponse struct {
+       Displaytext string `json:"displaytext"`
+       JobID       string `json:"jobid"`
+       Jobstatus   int    `json:"jobstatus"`
+       Success     bool   `json:"success"`
+}
+
+type ListStorageAccessGroupsParams struct {
+       p map[string]interface{}
+}
+
+func (p *ListStorageAccessGroupsParams) toURLValues() url.Values {
+       u := url.Values{}
+       if p.p == nil {
+               return u
+       }
+       if v, found := p.p["keyword"]; found {
+               u.Set("keyword", v.(string))
+       }
+       if v, found := p.p["name"]; found {
+               u.Set("name", v.(string))
+       }
+       if v, found := p.p["page"]; found {
+               vv := strconv.Itoa(v.(int))
+               u.Set("page", vv)
+       }
+       if v, found := p.p["pagesize"]; found {
+               vv := strconv.Itoa(v.(int))
+               u.Set("pagesize", vv)
+       }
+       return u
+}
+
+func (p *ListStorageAccessGroupsParams) SetKeyword(v string) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       p.p["keyword"] = v
+}
+
+func (p *ListStorageAccessGroupsParams) ResetKeyword() {
+       if p.p != nil && p.p["keyword"] != nil {
+               delete(p.p, "keyword")
+       }
+}
+
+func (p *ListStorageAccessGroupsParams) GetKeyword() (string, bool) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       value, ok := p.p["keyword"].(string)
+       return value, ok
+}
+
+func (p *ListStorageAccessGroupsParams) SetName(v string) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       p.p["name"] = v
+}
+
+func (p *ListStorageAccessGroupsParams) ResetName() {
+       if p.p != nil && p.p["name"] != nil {
+               delete(p.p, "name")
+       }
+}
+
+func (p *ListStorageAccessGroupsParams) GetName() (string, bool) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       value, ok := p.p["name"].(string)
+       return value, ok
+}
+
+func (p *ListStorageAccessGroupsParams) SetPage(v int) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       p.p["page"] = v
+}
+
+func (p *ListStorageAccessGroupsParams) ResetPage() {
+       if p.p != nil && p.p["page"] != nil {
+               delete(p.p, "page")
+       }
+}
+
+func (p *ListStorageAccessGroupsParams) GetPage() (int, bool) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       value, ok := p.p["page"].(int)
+       return value, ok
+}
+
+func (p *ListStorageAccessGroupsParams) SetPagesize(v int) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       p.p["pagesize"] = v
+}
+
+func (p *ListStorageAccessGroupsParams) ResetPagesize() {
+       if p.p != nil && p.p["pagesize"] != nil {
+               delete(p.p, "pagesize")
+       }
+}
+
+func (p *ListStorageAccessGroupsParams) GetPagesize() (int, bool) {
+       if p.p == nil {
+               p.p = make(map[string]interface{})
+       }
+       value, ok := p.p["pagesize"].(int)
+       return value, ok
+}
+
+// You should always use this function to get a new 
ListStorageAccessGroupsParams instance,
+// as then you are sure you have configured all required params
+func (s *PoolService) NewListStorageAccessGroupsParams() 
*ListStorageAccessGroupsParams {
+       p := &ListStorageAccessGroupsParams{}
+       p.p = make(map[string]interface{})
+       return p
+}
+
+// This is a courtesy helper function, which in some cases may not work as 
expected!
+func (s *PoolService) GetStorageAccessGroupID(name string, opts ...OptionFunc) 
(string, int, error) {
+       p := &ListStorageAccessGroupsParams{}
+       p.p = make(map[string]interface{})
+
+       p.p["name"] = name
+
+       for _, fn := range append(s.cs.options, opts...) {
+               if err := fn(s.cs, p); err != nil {
+                       return "", -1, err
+               }
+       }
+
+       l, err := s.ListStorageAccessGroups(p)
+       if err != nil {
+               return "", -1, err
+       }
+
+       if l.Count == 0 {
+               return "", l.Count, fmt.Errorf("No match found for %s: %+v", 
name, l)
+       }
+
+       if l.Count == 1 {
+               return l.StorageAccessGroups[0].Id, l.Count, nil
+       }
+
+       if l.Count > 1 {
+               for _, v := range l.StorageAccessGroups {
+                       if v.Name == name {
+                               return v.Id, l.Count, nil
+                       }
+               }
+       }
+       return "", l.Count, fmt.Errorf("Could not find an exact match for %s: 
%+v", name, l)
+}
+
+// Lists storage access groups
+func (s *PoolService) ListStorageAccessGroups(p 
*ListStorageAccessGroupsParams) (*ListStorageAccessGroupsResponse, error) {
+       resp, err := s.cs.newRequest("listStorageAccessGroups", p.toURLValues())
+       if err != nil {
+               return nil, err
+       }
+
+       var r ListStorageAccessGroupsResponse
+       if err := json.Unmarshal(resp, &r); err != nil {
+               return nil, err
+       }
+
+       return &r, nil
+}
+
+type ListStorageAccessGroupsResponse struct {
+       Count               int                   `json:"count"`
+       StorageAccessGroups []*StorageAccessGroup `json:"storageaccessgroup"`
+}
+
+type StorageAccessGroup struct {
+       Clusters     string `json:"clusters"`
+       Hosts        string `json:"hosts"`
+       Id           string `json:"id"`
+       JobID        string `json:"jobid"`
+       Jobstatus    int    `json:"jobstatus"`
+       Name         string `json:"name"`
+       Pods         string `json:"pods"`
+       Storagepools string `json:"storagepools"`
+       Zones        string `json:"zones"`
+}
diff --git a/cloudstack/PoolService_mock.go b/cloudstack/PoolService_mock.go
index 261f24a..3cb5c66 100644
--- a/cloudstack/PoolService_mock.go
+++ b/cloudstack/PoolService_mock.go
@@ -58,6 +58,21 @@ func (m *MockPoolServiceIface) EXPECT() 
*MockPoolServiceIfaceMockRecorder {
        return m.recorder
 }
 
+// ConfigureStorageAccess mocks base method.
+func (m *MockPoolServiceIface) ConfigureStorageAccess(p 
*ConfigureStorageAccessParams) (*StorageAccessResponse, error) {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "ConfigureStorageAccess", p)
+       ret0, _ := ret[0].(*StorageAccessResponse)
+       ret1, _ := ret[1].(error)
+       return ret0, ret1
+}
+
+// ConfigureStorageAccess indicates an expected call of ConfigureStorageAccess.
+func (mr *MockPoolServiceIfaceMockRecorder) ConfigureStorageAccess(p any) 
*gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, 
"ConfigureStorageAccess", 
reflect.TypeOf((*MockPoolServiceIface)(nil).ConfigureStorageAccess), p)
+}
+
 // CreateStoragePool mocks base method.
 func (m *MockPoolServiceIface) CreateStoragePool(p *CreateStoragePoolParams) 
(*CreateStoragePoolResponse, error) {
        m.ctrl.T.Helper()
@@ -103,6 +118,27 @@ func (mr *MockPoolServiceIfaceMockRecorder) 
FindStoragePoolsForMigration(p any)
        return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, 
"FindStoragePoolsForMigration", 
reflect.TypeOf((*MockPoolServiceIface)(nil).FindStoragePoolsForMigration), p)
 }
 
+// GetStorageAccessGroupID mocks base method.
+func (m *MockPoolServiceIface) GetStorageAccessGroupID(name string, opts 
...OptionFunc) (string, int, error) {
+       m.ctrl.T.Helper()
+       varargs := []any{name}
+       for _, a := range opts {
+               varargs = append(varargs, a)
+       }
+       ret := m.ctrl.Call(m, "GetStorageAccessGroupID", varargs...)
+       ret0, _ := ret[0].(string)
+       ret1, _ := ret[1].(int)
+       ret2, _ := ret[2].(error)
+       return ret0, ret1, ret2
+}
+
+// GetStorageAccessGroupID indicates an expected call of 
GetStorageAccessGroupID.
+func (mr *MockPoolServiceIfaceMockRecorder) GetStorageAccessGroupID(name any, 
opts ...any) *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       varargs := append([]any{name}, opts...)
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, 
"GetStorageAccessGroupID", 
reflect.TypeOf((*MockPoolServiceIface)(nil).GetStorageAccessGroupID), 
varargs...)
+}
+
 // GetStoragePoolByID mocks base method.
 func (m *MockPoolServiceIface) GetStoragePoolByID(id string, opts 
...OptionFunc) (*StoragePool, int, error) {
        m.ctrl.T.Helper()
@@ -181,6 +217,21 @@ func (mr *MockPoolServiceIfaceMockRecorder) 
ListElastistorPool(p any) *gomock.Ca
        return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, 
"ListElastistorPool", 
reflect.TypeOf((*MockPoolServiceIface)(nil).ListElastistorPool), p)
 }
 
+// ListStorageAccessGroups mocks base method.
+func (m *MockPoolServiceIface) ListStorageAccessGroups(p 
*ListStorageAccessGroupsParams) (*ListStorageAccessGroupsResponse, error) {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "ListStorageAccessGroups", p)
+       ret0, _ := ret[0].(*ListStorageAccessGroupsResponse)
+       ret1, _ := ret[1].(error)
+       return ret0, ret1
+}
+
+// ListStorageAccessGroups indicates an expected call of 
ListStorageAccessGroups.
+func (mr *MockPoolServiceIfaceMockRecorder) ListStorageAccessGroups(p any) 
*gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, 
"ListStorageAccessGroups", 
reflect.TypeOf((*MockPoolServiceIface)(nil).ListStorageAccessGroups), p)
+}
+
 // ListStoragePools mocks base method.
 func (m *MockPoolServiceIface) ListStoragePools(p *ListStoragePoolsParams) 
(*ListStoragePoolsResponse, error) {
        m.ctrl.T.Helper()
@@ -196,6 +247,20 @@ func (mr *MockPoolServiceIfaceMockRecorder) 
ListStoragePools(p any) *gomock.Call
        return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, 
"ListStoragePools", 
reflect.TypeOf((*MockPoolServiceIface)(nil).ListStoragePools), p)
 }
 
+// NewConfigureStorageAccessParams mocks base method.
+func (m *MockPoolServiceIface) NewConfigureStorageAccessParams() 
*ConfigureStorageAccessParams {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "NewConfigureStorageAccessParams")
+       ret0, _ := ret[0].(*ConfigureStorageAccessParams)
+       return ret0
+}
+
+// NewConfigureStorageAccessParams indicates an expected call of 
NewConfigureStorageAccessParams.
+func (mr *MockPoolServiceIfaceMockRecorder) NewConfigureStorageAccessParams() 
*gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, 
"NewConfigureStorageAccessParams", 
reflect.TypeOf((*MockPoolServiceIface)(nil).NewConfigureStorageAccessParams))
+}
+
 // NewCreateStoragePoolParams mocks base method.
 func (m *MockPoolServiceIface) NewCreateStoragePoolParams(name, url, zoneid 
string) *CreateStoragePoolParams {
        m.ctrl.T.Helper()
@@ -252,6 +317,20 @@ func (mr *MockPoolServiceIfaceMockRecorder) 
NewListElastistorPoolParams() *gomoc
        return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, 
"NewListElastistorPoolParams", 
reflect.TypeOf((*MockPoolServiceIface)(nil).NewListElastistorPoolParams))
 }
 
+// NewListStorageAccessGroupsParams mocks base method.
+func (m *MockPoolServiceIface) NewListStorageAccessGroupsParams() 
*ListStorageAccessGroupsParams {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "NewListStorageAccessGroupsParams")
+       ret0, _ := ret[0].(*ListStorageAccessGroupsParams)
+       return ret0
+}
+
+// NewListStorageAccessGroupsParams indicates an expected call of 
NewListStorageAccessGroupsParams.
+func (mr *MockPoolServiceIfaceMockRecorder) NewListStorageAccessGroupsParams() 
*gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, 
"NewListStorageAccessGroupsParams", 
reflect.TypeOf((*MockPoolServiceIface)(nil).NewListStorageAccessGroupsParams))
+}
+
 // NewListStoragePoolsParams mocks base method.
 func (m *MockPoolServiceIface) NewListStoragePoolsParams() 
*ListStoragePoolsParams {
        m.ctrl.T.Helper()
diff --git a/generate/layout.go b/generate/layout.go
index 0a20b96..bf9c07d 100644
--- a/generate/layout.go
+++ b/generate/layout.go
@@ -504,6 +504,8 @@ var layout = apiInfo{
                "listStoragePools",
                "syncStoragePool",
                "updateStoragePool",
+               "configureStorageAccess",
+               "listStorageAccessGroups",
        },
        "NetworkACLService": {
                "createNetworkACL",
diff --git a/test/PoolService_test.go b/test/PoolService_test.go
index 365f79a..13616c1 100644
--- a/test/PoolService_test.go
+++ b/test/PoolService_test.go
@@ -131,4 +131,28 @@ func TestPoolService(t *testing.T) {
        }
        t.Run("UpdateStoragePool", testupdateStoragePool)
 
+       testconfigureStorageAccess := func(t *testing.T) {
+               if _, ok := response["configureStorageAccess"]; !ok {
+                       t.Skipf("Skipping as no json response is provided in 
testdata")
+               }
+               p := client.Pool.NewConfigureStorageAccessParams()
+               _, err := client.Pool.ConfigureStorageAccess(p)
+               if err != nil {
+                       t.Errorf(err.Error())
+               }
+       }
+       t.Run("ConfigureStorageAccess", testconfigureStorageAccess)
+
+       testlistStorageAccessGroups := func(t *testing.T) {
+               if _, ok := response["listStorageAccessGroups"]; !ok {
+                       t.Skipf("Skipping as no json response is provided in 
testdata")
+               }
+               p := client.Pool.NewListStorageAccessGroupsParams()
+               _, err := client.Pool.ListStorageAccessGroups(p)
+               if err != nil {
+                       t.Errorf(err.Error())
+               }
+       }
+       t.Run("ListStorageAccessGroups", testlistStorageAccessGroups)
+
 }

Reply via email to