You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by da...@apache.org on 2024/12/30 15:18:48 UTC

(cloudstack-go) 24/25: add +30 more apis

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

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

commit cd1296025ae9e00b694e337b78ac129601aa6b75
Author: Ahmed Awlaqi <ah...@sue.nl>
AuthorDate: Fri Jun 14 14:26:53 2024 +0200

    add +30 more apis
---
 cloudstack/CertificateService.go                   |  206 ++
 cloudstack/CertificateService_mock.go              |   58 +
 cloudstack/ConfigurationService.go                 |   94 +
 cloudstack/ConfigurationService_mock.go            |   29 +
 cloudstack/DiagnosticsService.go                   |  142 +
 cloudstack/DiagnosticsService_mock.go              |   82 +
 cloudstack/GuestOSService.go                       |  145 +
 cloudstack/GuestOSService_mock.go                  |   29 +
 cloudstack/HostService.go                          | 1218 +++++++++
 cloudstack/HostService_mock.go                     |  282 ++
 cloudstack/ImageStoreService.go                    |  445 +++
 cloudstack/ImageStoreService_mock.go               |  108 +
 cloudstack/ManagementService.go                    |  298 ++
 cloudstack/ManagementService_mock.go               |  145 +
 cloudstack/MetricsService.go                       |   88 +
 cloudstack/MetricsService_mock.go                  |   82 +
 cloudstack/NetworkService.go                       |    6 +-
 cloudstack/OauthService.go                         |  589 ++++
 cloudstack/OauthService_mock.go                    |  203 ++
 cloudstack/ObjectStoreService.go                   | 1130 ++++++++
 cloudstack/ObjectStoreService_mock.go              |  232 ++
 cloudstack/PodService.go                           |  182 ++
 cloudstack/PodService_mock.go                      |   29 +
 cloudstack/ProjectService.go                       |  393 +++
 cloudstack/ProjectService_mock.go                  |   87 +
 cloudstack/RegistrationService.go                  |  269 ++
 cloudstack/RegistrationService_mock.go             |   82 +
 cloudstack/RoleService.go                          |  237 ++
 cloudstack/RoleService_mock.go                     |   50 +
 cloudstack/ShutdownService.go                      |  101 +
 cloudstack/ShutdownService_mock.go                 |   82 +
 cloudstack/StoragePoolService.go                   | 1382 ++++++++++
 cloudstack/StoragePoolService_mock.go              |  321 +++
 cloudstack/TemplateService.go                      |  220 ++
 cloudstack/TemplateService_mock.go                 |   29 +
 cloudstack/UserService.go                          | 1054 ++++++++
 cloudstack/UserService_mock.go                     |  208 ++
 cloudstack/VirtualMachineService.go                | 2836 +++++++++++++++++++-
 cloudstack/VirtualMachineService_mock.go           |  253 ++
 cloudstack/VolumeService.go                        |  515 ++++
 cloudstack/VolumeService_mock.go                   |  121 +
 cloudstack/ZoneService.go                          |  920 +++++++
 cloudstack/ZoneService_mock.go                     |  166 ++
 cloudstack/cloudstack.go                           |   77 +
 generate/generate.go                               |   99 +-
 generate/layout.go                                 |   74 +
 test/CertificateService_test.go                    |   24 +
 test/ConfigurationService_test.go                  |   15 +
 ...eService_test.go => DiagnosticsService_test.go} |   14 +-
 test/GuestOSService_test.go                        |   12 +
 test/HostService_test.go                           |  123 +
 test/ImageStoreService_test.go                     |   42 +
 ...teService_test.go => ManagementService_test.go} |   14 +-
 ...icateService_test.go => MetricsService_test.go} |   14 +-
 ...agePoolService_test.go => OauthService_test.go} |   37 +-
 ...lService_test.go => ObjectStoreService_test.go} |   47 +-
 test/PodService_test.go                            |   12 +
 test/ProjectService_test.go                        |   42 +
 ...Service_test.go => RegistrationService_test.go} |   14 +-
 test/RoleService_test.go                           |   12 +
 ...cateService_test.go => ShutdownService_test.go} |   14 +-
 test/StoragePoolService_test.go                    |   78 +
 test/TemplateService_test.go                       |   15 +
 test/UserService_test.go                           |   63 +
 test/VirtualMachineService_test.go                 |  108 +
 test/VolumeService_test.go                         |   27 +
 test/ZoneService_test.go                           |   66 +
 67 files changed, 16102 insertions(+), 89 deletions(-)

diff --git a/cloudstack/CertificateService.go b/cloudstack/CertificateService.go
index 8b8c12f..e0a3dd7 100644
--- a/cloudstack/CertificateService.go
+++ b/cloudstack/CertificateService.go
@@ -28,6 +28,10 @@ import (
 type CertificateServiceIface interface {
 	UploadCustomCertificate(p *UploadCustomCertificateParams) (*UploadCustomCertificateResponse, error)
 	NewUploadCustomCertificateParams(certificate string, domainsuffix string) *UploadCustomCertificateParams
+	ListCAProviders(p *ListCAProvidersParams) (*ListCAProvidersResponse, error)
+	NewListCAProvidersParams() *ListCAProvidersParams
+	ProvisionCertificate(p *ProvisionCertificateParams) (*ProvisionCertificateResponse, error)
+	NewProvisionCertificateParams(hostid string) *ProvisionCertificateParams
 }
 
 type UploadCustomCertificateParams struct {
@@ -213,3 +217,205 @@ type UploadCustomCertificateResponse struct {
 	Jobstatus int    `json:"jobstatus"`
 	Message   string `json:"message"`
 }
+
+type ListCAProvidersParams struct {
+	p map[string]interface{}
+}
+
+func (p *ListCAProvidersParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["name"]; found {
+		u.Set("name", v.(string))
+	}
+	return u
+}
+
+func (p *ListCAProvidersParams) SetName(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["name"] = v
+}
+
+func (p *ListCAProvidersParams) ResetName() {
+	if p.p != nil && p.p["name"] != nil {
+		delete(p.p, "name")
+	}
+}
+
+func (p *ListCAProvidersParams) GetName() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["name"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new ListCAProvidersParams instance,
+// as then you are sure you have configured all required params
+func (s *CertificateService) NewListCAProvidersParams() *ListCAProvidersParams {
+	p := &ListCAProvidersParams{}
+	p.p = make(map[string]interface{})
+	return p
+}
+
+// Lists available certificate authority providers in CloudStack
+func (s *CertificateService) ListCAProviders(p *ListCAProvidersParams) (*ListCAProvidersResponse, error) {
+	resp, err := s.cs.newRequest("listCAProviders", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r ListCAProvidersResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type ListCAProvidersResponse struct {
+	Count       int           `json:"count"`
+	CAProviders []*CAProvider `json:"caprovider"`
+}
+
+type CAProvider struct {
+	Description string `json:"description"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Name        string `json:"name"`
+}
+
+type ProvisionCertificateParams struct {
+	p map[string]interface{}
+}
+
+func (p *ProvisionCertificateParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["hostid"]; found {
+		u.Set("hostid", v.(string))
+	}
+	if v, found := p.p["provider"]; found {
+		u.Set("provider", v.(string))
+	}
+	if v, found := p.p["reconnect"]; found {
+		vv := strconv.FormatBool(v.(bool))
+		u.Set("reconnect", vv)
+	}
+	return u
+}
+
+func (p *ProvisionCertificateParams) SetHostid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["hostid"] = v
+}
+
+func (p *ProvisionCertificateParams) ResetHostid() {
+	if p.p != nil && p.p["hostid"] != nil {
+		delete(p.p, "hostid")
+	}
+}
+
+func (p *ProvisionCertificateParams) GetHostid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["hostid"].(string)
+	return value, ok
+}
+
+func (p *ProvisionCertificateParams) SetProvider(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["provider"] = v
+}
+
+func (p *ProvisionCertificateParams) ResetProvider() {
+	if p.p != nil && p.p["provider"] != nil {
+		delete(p.p, "provider")
+	}
+}
+
+func (p *ProvisionCertificateParams) GetProvider() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["provider"].(string)
+	return value, ok
+}
+
+func (p *ProvisionCertificateParams) SetReconnect(v bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["reconnect"] = v
+}
+
+func (p *ProvisionCertificateParams) ResetReconnect() {
+	if p.p != nil && p.p["reconnect"] != nil {
+		delete(p.p, "reconnect")
+	}
+}
+
+func (p *ProvisionCertificateParams) GetReconnect() (bool, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["reconnect"].(bool)
+	return value, ok
+}
+
+// You should always use this function to get a new ProvisionCertificateParams instance,
+// as then you are sure you have configured all required params
+func (s *CertificateService) NewProvisionCertificateParams(hostid string) *ProvisionCertificateParams {
+	p := &ProvisionCertificateParams{}
+	p.p = make(map[string]interface{})
+	p.p["hostid"] = hostid
+	return p
+}
+
+// Issues and propagates client certificate on a connected host/agent using configured CA plugin
+func (s *CertificateService) ProvisionCertificate(p *ProvisionCertificateParams) (*ProvisionCertificateResponse, error) {
+	resp, err := s.cs.newRequest("provisionCertificate", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r ProvisionCertificateResponse
+	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 ProvisionCertificateResponse struct {
+	Displaytext string `json:"displaytext"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Success     bool   `json:"success"`
+}
diff --git a/cloudstack/CertificateService_mock.go b/cloudstack/CertificateService_mock.go
index c0733a9..dfd5159 100644
--- a/cloudstack/CertificateService_mock.go
+++ b/cloudstack/CertificateService_mock.go
@@ -52,6 +52,49 @@ func (m *MockCertificateServiceIface) EXPECT() *MockCertificateServiceIfaceMockR
 	return m.recorder
 }
 
+// ListCAProviders mocks base method.
+func (m *MockCertificateServiceIface) ListCAProviders(p *ListCAProvidersParams) (*ListCAProvidersResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ListCAProviders", p)
+	ret0, _ := ret[0].(*ListCAProvidersResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListCAProviders indicates an expected call of ListCAProviders.
+func (mr *MockCertificateServiceIfaceMockRecorder) ListCAProviders(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListCAProviders", reflect.TypeOf((*MockCertificateServiceIface)(nil).ListCAProviders), p)
+}
+
+// NewListCAProvidersParams mocks base method.
+func (m *MockCertificateServiceIface) NewListCAProvidersParams() *ListCAProvidersParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewListCAProvidersParams")
+	ret0, _ := ret[0].(*ListCAProvidersParams)
+	return ret0
+}
+
+// NewListCAProvidersParams indicates an expected call of NewListCAProvidersParams.
+func (mr *MockCertificateServiceIfaceMockRecorder) NewListCAProvidersParams() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListCAProvidersParams", reflect.TypeOf((*MockCertificateServiceIface)(nil).NewListCAProvidersParams))
+}
+
+// NewProvisionCertificateParams mocks base method.
+func (m *MockCertificateServiceIface) NewProvisionCertificateParams(hostid string) *ProvisionCertificateParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewProvisionCertificateParams", hostid)
+	ret0, _ := ret[0].(*ProvisionCertificateParams)
+	return ret0
+}
+
+// NewProvisionCertificateParams indicates an expected call of NewProvisionCertificateParams.
+func (mr *MockCertificateServiceIfaceMockRecorder) NewProvisionCertificateParams(hostid interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewProvisionCertificateParams", reflect.TypeOf((*MockCertificateServiceIface)(nil).NewProvisionCertificateParams), hostid)
+}
+
 // NewUploadCustomCertificateParams mocks base method.
 func (m *MockCertificateServiceIface) NewUploadCustomCertificateParams(certificate, domainsuffix string) *UploadCustomCertificateParams {
 	m.ctrl.T.Helper()
@@ -66,6 +109,21 @@ func (mr *MockCertificateServiceIfaceMockRecorder) NewUploadCustomCertificatePar
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewUploadCustomCertificateParams", reflect.TypeOf((*MockCertificateServiceIface)(nil).NewUploadCustomCertificateParams), certificate, domainsuffix)
 }
 
+// ProvisionCertificate mocks base method.
+func (m *MockCertificateServiceIface) ProvisionCertificate(p *ProvisionCertificateParams) (*ProvisionCertificateResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ProvisionCertificate", p)
+	ret0, _ := ret[0].(*ProvisionCertificateResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ProvisionCertificate indicates an expected call of ProvisionCertificate.
+func (mr *MockCertificateServiceIfaceMockRecorder) ProvisionCertificate(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvisionCertificate", reflect.TypeOf((*MockCertificateServiceIface)(nil).ProvisionCertificate), p)
+}
+
 // UploadCustomCertificate mocks base method.
 func (m *MockCertificateServiceIface) UploadCustomCertificate(p *UploadCustomCertificateParams) (*UploadCustomCertificateResponse, error) {
 	m.ctrl.T.Helper()
diff --git a/cloudstack/ConfigurationService.go b/cloudstack/ConfigurationService.go
index 0a1e39b..ba16bee 100644
--- a/cloudstack/ConfigurationService.go
+++ b/cloudstack/ConfigurationService.go
@@ -36,6 +36,8 @@ type ConfigurationServiceIface interface {
 	NewUpdateConfigurationParams(name string) *UpdateConfigurationParams
 	ResetConfiguration(p *ResetConfigurationParams) (*ResetConfigurationResponse, error)
 	NewResetConfigurationParams(name string) *ResetConfigurationParams
+	UpdateStorageCapabilities(p *UpdateStorageCapabilitiesParams) (*UpdateStorageCapabilitiesResponse, error)
+	NewUpdateStorageCapabilitiesParams(id string) *UpdateStorageCapabilitiesParams
 }
 
 type ListCapabilitiesParams struct {
@@ -1100,3 +1102,95 @@ type ResetConfigurationResponse struct {
 	Type         string `json:"type"`
 	Value        string `json:"value"`
 }
+
+type UpdateStorageCapabilitiesParams struct {
+	p map[string]interface{}
+}
+
+func (p *UpdateStorageCapabilitiesParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	return u
+}
+
+func (p *UpdateStorageCapabilitiesParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *UpdateStorageCapabilitiesParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *UpdateStorageCapabilitiesParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new UpdateStorageCapabilitiesParams instance,
+// as then you are sure you have configured all required params
+func (s *ConfigurationService) NewUpdateStorageCapabilitiesParams(id string) *UpdateStorageCapabilitiesParams {
+	p := &UpdateStorageCapabilitiesParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	return p
+}
+
+// Syncs capabilities of storage pools
+func (s *ConfigurationService) UpdateStorageCapabilities(p *UpdateStorageCapabilitiesParams) (*UpdateStorageCapabilitiesResponse, error) {
+	resp, err := s.cs.newRequest("updateStorageCapabilities", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r UpdateStorageCapabilitiesResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type UpdateStorageCapabilitiesResponse struct {
+	Allocatediops        int64             `json:"allocatediops"`
+	Capacityiops         int64             `json:"capacityiops"`
+	Clusterid            string            `json:"clusterid"`
+	Clustername          string            `json:"clustername"`
+	Created              string            `json:"created"`
+	Disksizeallocated    int64             `json:"disksizeallocated"`
+	Disksizetotal        int64             `json:"disksizetotal"`
+	Disksizeused         int64             `json:"disksizeused"`
+	Hasannotations       bool              `json:"hasannotations"`
+	Hypervisor           string            `json:"hypervisor"`
+	Id                   string            `json:"id"`
+	Ipaddress            string            `json:"ipaddress"`
+	Istagarule           bool              `json:"istagarule"`
+	JobID                string            `json:"jobid"`
+	Jobstatus            int               `json:"jobstatus"`
+	Name                 string            `json:"name"`
+	Overprovisionfactor  string            `json:"overprovisionfactor"`
+	Path                 string            `json:"path"`
+	Podid                string            `json:"podid"`
+	Podname              string            `json:"podname"`
+	Provider             string            `json:"provider"`
+	Scope                string            `json:"scope"`
+	State                string            `json:"state"`
+	Storagecapabilities  map[string]string `json:"storagecapabilities"`
+	Suitableformigration bool              `json:"suitableformigration"`
+	Tags                 string            `json:"tags"`
+	Type                 string            `json:"type"`
+	Zoneid               string            `json:"zoneid"`
+	Zonename             string            `json:"zonename"`
+}
diff --git a/cloudstack/ConfigurationService_mock.go b/cloudstack/ConfigurationService_mock.go
index ac31e8e..891178b 100644
--- a/cloudstack/ConfigurationService_mock.go
+++ b/cloudstack/ConfigurationService_mock.go
@@ -167,6 +167,20 @@ func (mr *MockConfigurationServiceIfaceMockRecorder) NewUpdateConfigurationParam
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewUpdateConfigurationParams", reflect.TypeOf((*MockConfigurationServiceIface)(nil).NewUpdateConfigurationParams), name)
 }
 
+// NewUpdateStorageCapabilitiesParams mocks base method.
+func (m *MockConfigurationServiceIface) NewUpdateStorageCapabilitiesParams(id string) *UpdateStorageCapabilitiesParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewUpdateStorageCapabilitiesParams", id)
+	ret0, _ := ret[0].(*UpdateStorageCapabilitiesParams)
+	return ret0
+}
+
+// NewUpdateStorageCapabilitiesParams indicates an expected call of NewUpdateStorageCapabilitiesParams.
+func (mr *MockConfigurationServiceIfaceMockRecorder) NewUpdateStorageCapabilitiesParams(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewUpdateStorageCapabilitiesParams", reflect.TypeOf((*MockConfigurationServiceIface)(nil).NewUpdateStorageCapabilitiesParams), id)
+}
+
 // ResetConfiguration mocks base method.
 func (m *MockConfigurationServiceIface) ResetConfiguration(p *ResetConfigurationParams) (*ResetConfigurationResponse, error) {
 	m.ctrl.T.Helper()
@@ -196,3 +210,18 @@ func (mr *MockConfigurationServiceIfaceMockRecorder) UpdateConfiguration(p inter
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateConfiguration", reflect.TypeOf((*MockConfigurationServiceIface)(nil).UpdateConfiguration), p)
 }
+
+// UpdateStorageCapabilities mocks base method.
+func (m *MockConfigurationServiceIface) UpdateStorageCapabilities(p *UpdateStorageCapabilitiesParams) (*UpdateStorageCapabilitiesResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "UpdateStorageCapabilities", p)
+	ret0, _ := ret[0].(*UpdateStorageCapabilitiesResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// UpdateStorageCapabilities indicates an expected call of UpdateStorageCapabilities.
+func (mr *MockConfigurationServiceIfaceMockRecorder) UpdateStorageCapabilities(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateStorageCapabilities", reflect.TypeOf((*MockConfigurationServiceIface)(nil).UpdateStorageCapabilities), p)
+}
diff --git a/cloudstack/DiagnosticsService.go b/cloudstack/DiagnosticsService.go
new file mode 100644
index 0000000..f45f82d
--- /dev/null
+++ b/cloudstack/DiagnosticsService.go
@@ -0,0 +1,142 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 cloudstack
+
+import (
+	"encoding/json"
+	"net/url"
+	"strings"
+)
+
+type DiagnosticsServiceIface interface {
+	GetDiagnosticsData(p *GetDiagnosticsDataParams) (*GetDiagnosticsDataResponse, error)
+	NewGetDiagnosticsDataParams(targetid string) *GetDiagnosticsDataParams
+}
+
+type GetDiagnosticsDataParams struct {
+	p map[string]interface{}
+}
+
+func (p *GetDiagnosticsDataParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["files"]; found {
+		vv := strings.Join(v.([]string), ",")
+		u.Set("files", vv)
+	}
+	if v, found := p.p["targetid"]; found {
+		u.Set("targetid", v.(string))
+	}
+	return u
+}
+
+func (p *GetDiagnosticsDataParams) SetFiles(v []string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["files"] = v
+}
+
+func (p *GetDiagnosticsDataParams) ResetFiles() {
+	if p.p != nil && p.p["files"] != nil {
+		delete(p.p, "files")
+	}
+}
+
+func (p *GetDiagnosticsDataParams) GetFiles() ([]string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["files"].([]string)
+	return value, ok
+}
+
+func (p *GetDiagnosticsDataParams) SetTargetid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["targetid"] = v
+}
+
+func (p *GetDiagnosticsDataParams) ResetTargetid() {
+	if p.p != nil && p.p["targetid"] != nil {
+		delete(p.p, "targetid")
+	}
+}
+
+func (p *GetDiagnosticsDataParams) GetTargetid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["targetid"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new GetDiagnosticsDataParams instance,
+// as then you are sure you have configured all required params
+func (s *DiagnosticsService) NewGetDiagnosticsDataParams(targetid string) *GetDiagnosticsDataParams {
+	p := &GetDiagnosticsDataParams{}
+	p.p = make(map[string]interface{})
+	p.p["targetid"] = targetid
+	return p
+}
+
+// Get diagnostics and files from system VMs
+func (s *DiagnosticsService) GetDiagnosticsData(p *GetDiagnosticsDataParams) (*GetDiagnosticsDataResponse, error) {
+	resp, err := s.cs.newRequest("getDiagnosticsData", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r GetDiagnosticsDataResponse
+	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
+		}
+
+		b, err = getRawValue(b)
+		if err != nil {
+			return nil, err
+		}
+
+		if err := json.Unmarshal(b, &r); err != nil {
+			return nil, err
+		}
+	}
+
+	return &r, nil
+}
+
+type GetDiagnosticsDataResponse struct {
+	JobID     string `json:"jobid"`
+	Jobstatus int    `json:"jobstatus"`
+	Url       string `json:"url"`
+}
diff --git a/cloudstack/DiagnosticsService_mock.go b/cloudstack/DiagnosticsService_mock.go
new file mode 100644
index 0000000..678e39f
--- /dev/null
+++ b/cloudstack/DiagnosticsService_mock.go
@@ -0,0 +1,82 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: ./cloudstack/DiagnosticsService.go
+
+// Package cloudstack is a generated GoMock package.
+package cloudstack
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockDiagnosticsServiceIface is a mock of DiagnosticsServiceIface interface.
+type MockDiagnosticsServiceIface struct {
+	ctrl     *gomock.Controller
+	recorder *MockDiagnosticsServiceIfaceMockRecorder
+}
+
+// MockDiagnosticsServiceIfaceMockRecorder is the mock recorder for MockDiagnosticsServiceIface.
+type MockDiagnosticsServiceIfaceMockRecorder struct {
+	mock *MockDiagnosticsServiceIface
+}
+
+// NewMockDiagnosticsServiceIface creates a new mock instance.
+func NewMockDiagnosticsServiceIface(ctrl *gomock.Controller) *MockDiagnosticsServiceIface {
+	mock := &MockDiagnosticsServiceIface{ctrl: ctrl}
+	mock.recorder = &MockDiagnosticsServiceIfaceMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockDiagnosticsServiceIface) EXPECT() *MockDiagnosticsServiceIfaceMockRecorder {
+	return m.recorder
+}
+
+// GetDiagnosticsData mocks base method.
+func (m *MockDiagnosticsServiceIface) GetDiagnosticsData(p *GetDiagnosticsDataParams) (*GetDiagnosticsDataResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetDiagnosticsData", p)
+	ret0, _ := ret[0].(*GetDiagnosticsDataResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetDiagnosticsData indicates an expected call of GetDiagnosticsData.
+func (mr *MockDiagnosticsServiceIfaceMockRecorder) GetDiagnosticsData(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDiagnosticsData", reflect.TypeOf((*MockDiagnosticsServiceIface)(nil).GetDiagnosticsData), p)
+}
+
+// NewGetDiagnosticsDataParams mocks base method.
+func (m *MockDiagnosticsServiceIface) NewGetDiagnosticsDataParams(targetid string) *GetDiagnosticsDataParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewGetDiagnosticsDataParams", targetid)
+	ret0, _ := ret[0].(*GetDiagnosticsDataParams)
+	return ret0
+}
+
+// NewGetDiagnosticsDataParams indicates an expected call of NewGetDiagnosticsDataParams.
+func (mr *MockDiagnosticsServiceIfaceMockRecorder) NewGetDiagnosticsDataParams(targetid interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewGetDiagnosticsDataParams", reflect.TypeOf((*MockDiagnosticsServiceIface)(nil).NewGetDiagnosticsDataParams), targetid)
+}
diff --git a/cloudstack/GuestOSService.go b/cloudstack/GuestOSService.go
index fd3bc67..0bde913 100644
--- a/cloudstack/GuestOSService.go
+++ b/cloudstack/GuestOSService.go
@@ -53,6 +53,8 @@ type GuestOSServiceIface interface {
 	NewUpdateGuestOsParams(id string, osdisplayname string) *UpdateGuestOsParams
 	UpdateGuestOsMapping(p *UpdateGuestOsMappingParams) (*UpdateGuestOsMappingResponse, error)
 	NewUpdateGuestOsMappingParams(id string, osnameforhypervisor string) *UpdateGuestOsMappingParams
+	GetHypervisorGuestOsNames(p *GetHypervisorGuestOsNamesParams) (*GetHypervisorGuestOsNamesResponse, error)
+	NewGetHypervisorGuestOsNamesParams(hypervisor string, hypervisorversion string) *GetHypervisorGuestOsNamesParams
 }
 
 type AddGuestOsParams struct {
@@ -1906,3 +1908,146 @@ func (r *UpdateGuestOsMappingResponse) UnmarshalJSON(b []byte) error {
 	type alias UpdateGuestOsMappingResponse
 	return json.Unmarshal(b, (*alias)(r))
 }
+
+type GetHypervisorGuestOsNamesParams struct {
+	p map[string]interface{}
+}
+
+func (p *GetHypervisorGuestOsNamesParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["hypervisor"]; found {
+		u.Set("hypervisor", v.(string))
+	}
+	if v, found := p.p["hypervisorversion"]; found {
+		u.Set("hypervisorversion", v.(string))
+	}
+	if v, found := p.p["keyword"]; found {
+		u.Set("keyword", v.(string))
+	}
+	return u
+}
+
+func (p *GetHypervisorGuestOsNamesParams) SetHypervisor(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["hypervisor"] = v
+}
+
+func (p *GetHypervisorGuestOsNamesParams) ResetHypervisor() {
+	if p.p != nil && p.p["hypervisor"] != nil {
+		delete(p.p, "hypervisor")
+	}
+}
+
+func (p *GetHypervisorGuestOsNamesParams) GetHypervisor() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["hypervisor"].(string)
+	return value, ok
+}
+
+func (p *GetHypervisorGuestOsNamesParams) SetHypervisorversion(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["hypervisorversion"] = v
+}
+
+func (p *GetHypervisorGuestOsNamesParams) ResetHypervisorversion() {
+	if p.p != nil && p.p["hypervisorversion"] != nil {
+		delete(p.p, "hypervisorversion")
+	}
+}
+
+func (p *GetHypervisorGuestOsNamesParams) GetHypervisorversion() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["hypervisorversion"].(string)
+	return value, ok
+}
+
+func (p *GetHypervisorGuestOsNamesParams) SetKeyword(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["keyword"] = v
+}
+
+func (p *GetHypervisorGuestOsNamesParams) ResetKeyword() {
+	if p.p != nil && p.p["keyword"] != nil {
+		delete(p.p, "keyword")
+	}
+}
+
+func (p *GetHypervisorGuestOsNamesParams) GetKeyword() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["keyword"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new GetHypervisorGuestOsNamesParams instance,
+// as then you are sure you have configured all required params
+func (s *GuestOSService) NewGetHypervisorGuestOsNamesParams(hypervisor string, hypervisorversion string) *GetHypervisorGuestOsNamesParams {
+	p := &GetHypervisorGuestOsNamesParams{}
+	p.p = make(map[string]interface{})
+	p.p["hypervisor"] = hypervisor
+	p.p["hypervisorversion"] = hypervisorversion
+	return p
+}
+
+// Gets the guest OS names in the hypervisor
+func (s *GuestOSService) GetHypervisorGuestOsNames(p *GetHypervisorGuestOsNamesParams) (*GetHypervisorGuestOsNamesResponse, error) {
+	resp, err := s.cs.newRequest("getHypervisorGuestOsNames", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r GetHypervisorGuestOsNamesResponse
+	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
+		}
+
+		b, err = getRawValue(b)
+		if err != nil {
+			return nil, err
+		}
+
+		if err := json.Unmarshal(b, &r); err != nil {
+			return nil, err
+		}
+	}
+
+	return &r, nil
+}
+
+type GetHypervisorGuestOsNamesResponse struct {
+	Guestoscount      int                                            `json:"guestoscount"`
+	Guestoslist       []GetHypervisorGuestOsNamesResponseGuestoslist `json:"guestoslist"`
+	Hypervisor        string                                         `json:"hypervisor"`
+	Hypervisorversion string                                         `json:"hypervisorversion"`
+	JobID             string                                         `json:"jobid"`
+	Jobstatus         int                                            `json:"jobstatus"`
+}
+
+type GetHypervisorGuestOsNamesResponseGuestoslist struct {
+	Osdisplayname       string `json:"osdisplayname"`
+	Osnameforhypervisor string `json:"osnameforhypervisor"`
+}
diff --git a/cloudstack/GuestOSService_mock.go b/cloudstack/GuestOSService_mock.go
index 382fd60..04775d2 100644
--- a/cloudstack/GuestOSService_mock.go
+++ b/cloudstack/GuestOSService_mock.go
@@ -103,6 +103,21 @@ func (mr *MockGuestOSServiceIfaceMockRecorder) GetGuestOsMappingByID(id interfac
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGuestOsMappingByID", reflect.TypeOf((*MockGuestOSServiceIface)(nil).GetGuestOsMappingByID), varargs...)
 }
 
+// GetHypervisorGuestOsNames mocks base method.
+func (m *MockGuestOSServiceIface) GetHypervisorGuestOsNames(p *GetHypervisorGuestOsNamesParams) (*GetHypervisorGuestOsNamesResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetHypervisorGuestOsNames", p)
+	ret0, _ := ret[0].(*GetHypervisorGuestOsNamesResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetHypervisorGuestOsNames indicates an expected call of GetHypervisorGuestOsNames.
+func (mr *MockGuestOSServiceIfaceMockRecorder) GetHypervisorGuestOsNames(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHypervisorGuestOsNames", reflect.TypeOf((*MockGuestOSServiceIface)(nil).GetHypervisorGuestOsNames), p)
+}
+
 // GetOsCategoryByID mocks base method.
 func (m *MockGuestOSServiceIface) GetOsCategoryByID(id string, opts ...OptionFunc) (*OsCategory, int, error) {
 	m.ctrl.T.Helper()
@@ -302,6 +317,20 @@ func (mr *MockGuestOSServiceIfaceMockRecorder) NewAddGuestOsParams(oscategoryid,
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewAddGuestOsParams", reflect.TypeOf((*MockGuestOSServiceIface)(nil).NewAddGuestOsParams), oscategoryid, osdisplayname)
 }
 
+// NewGetHypervisorGuestOsNamesParams mocks base method.
+func (m *MockGuestOSServiceIface) NewGetHypervisorGuestOsNamesParams(hypervisor, hypervisorversion string) *GetHypervisorGuestOsNamesParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewGetHypervisorGuestOsNamesParams", hypervisor, hypervisorversion)
+	ret0, _ := ret[0].(*GetHypervisorGuestOsNamesParams)
+	return ret0
+}
+
+// NewGetHypervisorGuestOsNamesParams indicates an expected call of NewGetHypervisorGuestOsNamesParams.
+func (mr *MockGuestOSServiceIfaceMockRecorder) NewGetHypervisorGuestOsNamesParams(hypervisor, hypervisorversion interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewGetHypervisorGuestOsNamesParams", reflect.TypeOf((*MockGuestOSServiceIface)(nil).NewGetHypervisorGuestOsNamesParams), hypervisor, hypervisorversion)
+}
+
 // NewListGuestOsMappingParams mocks base method.
 func (m *MockGuestOSServiceIface) NewListGuestOsMappingParams() *ListGuestOsMappingParams {
 	m.ctrl.T.Helper()
diff --git a/cloudstack/HostService.go b/cloudstack/HostService.go
index 3980564..3ea546f 100644
--- a/cloudstack/HostService.go
+++ b/cloudstack/HostService.go
@@ -79,6 +79,25 @@ type HostServiceIface interface {
 	NewUpdateHostParams(id string) *UpdateHostParams
 	UpdateHostPassword(p *UpdateHostPasswordParams) (*UpdateHostPasswordResponse, error)
 	NewUpdateHostPasswordParams(password string, username string) *UpdateHostPasswordParams
+	MigrateSecondaryStorageData(p *MigrateSecondaryStorageDataParams) (*MigrateSecondaryStorageDataResponse, error)
+	NewMigrateSecondaryStorageDataParams(destpools []string, srcpool string) *MigrateSecondaryStorageDataParams
+	CancelHostAsDegraded(p *CancelHostAsDegradedParams) (*CancelHostAsDegradedResponse, error)
+	NewCancelHostAsDegradedParams(id string) *CancelHostAsDegradedParams
+	ListHostHAProviders(p *ListHostHAProvidersParams) (*ListHostHAProvidersResponse, error)
+	NewListHostHAProvidersParams(hypervisor string) *ListHostHAProvidersParams
+	ListSecondaryStorageSelectors(p *ListSecondaryStorageSelectorsParams) (*ListSecondaryStorageSelectorsResponse, error)
+	NewListSecondaryStorageSelectorsParams(zoneid string) *ListSecondaryStorageSelectorsParams
+	GetSecondaryStorageSelectorID(keyword string, zoneid string, opts ...OptionFunc) (string, int, error)
+	CreateSecondaryStorageSelector(p *CreateSecondaryStorageSelectorParams) (*CreateSecondaryStorageSelectorResponse, error)
+	NewCreateSecondaryStorageSelectorParams(description string, heuristicrule string, name string, hostType string, zoneid string) *CreateSecondaryStorageSelectorParams
+	RemoveSecondaryStorageSelector(p *RemoveSecondaryStorageSelectorParams) (*RemoveSecondaryStorageSelectorResponse, error)
+	NewRemoveSecondaryStorageSelectorParams(id string) *RemoveSecondaryStorageSelectorParams
+	ListHostHAResources(p *ListHostHAResourcesParams) (*ListHostHAResourcesResponse, error)
+	NewListHostHAResourcesParams() *ListHostHAResourcesParams
+	DeclareHostAsDegraded(p *DeclareHostAsDegradedParams) (*DeclareHostAsDegradedResponse, error)
+	NewDeclareHostAsDegradedParams(id string) *DeclareHostAsDegradedParams
+	UpdateSecondaryStorageSelector(p *UpdateSecondaryStorageSelectorParams) (*UpdateSecondaryStorageSelectorResponse, error)
+	NewUpdateSecondaryStorageSelectorParams(heuristicrule string, id string) *UpdateSecondaryStorageSelectorParams
 }
 
 type AddBaremetalHostParams struct {
@@ -4753,3 +4772,1202 @@ func (r *UpdateHostPasswordResponse) UnmarshalJSON(b []byte) error {
 	type alias UpdateHostPasswordResponse
 	return json.Unmarshal(b, (*alias)(r))
 }
+
+type MigrateSecondaryStorageDataParams struct {
+	p map[string]interface{}
+}
+
+func (p *MigrateSecondaryStorageDataParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["destpools"]; found {
+		vv := strings.Join(v.([]string), ",")
+		u.Set("destpools", vv)
+	}
+	if v, found := p.p["migrationtype"]; found {
+		u.Set("migrationtype", v.(string))
+	}
+	if v, found := p.p["srcpool"]; found {
+		u.Set("srcpool", v.(string))
+	}
+	return u
+}
+
+func (p *MigrateSecondaryStorageDataParams) SetDestpools(v []string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["destpools"] = v
+}
+
+func (p *MigrateSecondaryStorageDataParams) ResetDestpools() {
+	if p.p != nil && p.p["destpools"] != nil {
+		delete(p.p, "destpools")
+	}
+}
+
+func (p *MigrateSecondaryStorageDataParams) GetDestpools() ([]string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["destpools"].([]string)
+	return value, ok
+}
+
+func (p *MigrateSecondaryStorageDataParams) SetMigrationtype(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["migrationtype"] = v
+}
+
+func (p *MigrateSecondaryStorageDataParams) ResetMigrationtype() {
+	if p.p != nil && p.p["migrationtype"] != nil {
+		delete(p.p, "migrationtype")
+	}
+}
+
+func (p *MigrateSecondaryStorageDataParams) GetMigrationtype() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["migrationtype"].(string)
+	return value, ok
+}
+
+func (p *MigrateSecondaryStorageDataParams) SetSrcpool(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["srcpool"] = v
+}
+
+func (p *MigrateSecondaryStorageDataParams) ResetSrcpool() {
+	if p.p != nil && p.p["srcpool"] != nil {
+		delete(p.p, "srcpool")
+	}
+}
+
+func (p *MigrateSecondaryStorageDataParams) GetSrcpool() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["srcpool"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new MigrateSecondaryStorageDataParams instance,
+// as then you are sure you have configured all required params
+func (s *HostService) NewMigrateSecondaryStorageDataParams(destpools []string, srcpool string) *MigrateSecondaryStorageDataParams {
+	p := &MigrateSecondaryStorageDataParams{}
+	p.p = make(map[string]interface{})
+	p.p["destpools"] = destpools
+	p.p["srcpool"] = srcpool
+	return p
+}
+
+// migrates data objects from one secondary storage to destination image store(s)
+func (s *HostService) MigrateSecondaryStorageData(p *MigrateSecondaryStorageDataParams) (*MigrateSecondaryStorageDataResponse, error) {
+	resp, err := s.cs.newRequest("migrateSecondaryStorageData", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r MigrateSecondaryStorageDataResponse
+	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
+		}
+
+		b, err = getRawValue(b)
+		if err != nil {
+			return nil, err
+		}
+
+		if err := json.Unmarshal(b, &r); err != nil {
+			return nil, err
+		}
+	}
+
+	return &r, nil
+}
+
+type MigrateSecondaryStorageDataResponse struct {
+	JobID         string `json:"jobid"`
+	Jobstatus     int    `json:"jobstatus"`
+	Message       string `json:"message"`
+	Migrationtype string `json:"migrationtype"`
+	Success       bool   `json:"success"`
+}
+
+type CancelHostAsDegradedParams struct {
+	p map[string]interface{}
+}
+
+func (p *CancelHostAsDegradedParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	return u
+}
+
+func (p *CancelHostAsDegradedParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *CancelHostAsDegradedParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *CancelHostAsDegradedParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new CancelHostAsDegradedParams instance,
+// as then you are sure you have configured all required params
+func (s *HostService) NewCancelHostAsDegradedParams(id string) *CancelHostAsDegradedParams {
+	p := &CancelHostAsDegradedParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	return p
+}
+
+// Cancel host status from 'Degraded'. Host will transit back to status 'Enabled'.
+func (s *HostService) CancelHostAsDegraded(p *CancelHostAsDegradedParams) (*CancelHostAsDegradedResponse, error) {
+	resp, err := s.cs.newRequest("cancelHostAsDegraded", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r CancelHostAsDegradedResponse
+	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
+		}
+
+		b, err = getRawValue(b)
+		if err != nil {
+			return nil, err
+		}
+
+		if err := json.Unmarshal(b, &r); err != nil {
+			return nil, err
+		}
+	}
+
+	return &r, nil
+}
+
+type CancelHostAsDegradedResponse struct {
+	Annotation                       string                                 `json:"annotation"`
+	Capabilities                     string                                 `json:"capabilities"`
+	Clusterid                        string                                 `json:"clusterid"`
+	Clustername                      string                                 `json:"clustername"`
+	Clustertype                      string                                 `json:"clustertype"`
+	Cpuallocated                     string                                 `json:"cpuallocated"`
+	Cpuallocatedpercentage           string                                 `json:"cpuallocatedpercentage"`
+	Cpuallocatedvalue                int64                                  `json:"cpuallocatedvalue"`
+	Cpuallocatedwithoverprovisioning string                                 `json:"cpuallocatedwithoverprovisioning"`
+	Cpuloadaverage                   float64                                `json:"cpuloadaverage"`
+	Cpunumber                        int                                    `json:"cpunumber"`
+	Cpusockets                       int                                    `json:"cpusockets"`
+	Cpuspeed                         int64                                  `json:"cpuspeed"`
+	Cpuused                          string                                 `json:"cpuused"`
+	Cpuwithoverprovisioning          string                                 `json:"cpuwithoverprovisioning"`
+	Created                          string                                 `json:"created"`
+	Details                          map[string]string                      `json:"details"`
+	Disconnected                     string                                 `json:"disconnected"`
+	Disksizeallocated                int64                                  `json:"disksizeallocated"`
+	Disksizetotal                    int64                                  `json:"disksizetotal"`
+	Encryptionsupported              bool                                   `json:"encryptionsupported"`
+	Events                           string                                 `json:"events"`
+	Gpugroup                         []CancelHostAsDegradedResponseGpugroup `json:"gpugroup"`
+	Hahost                           bool                                   `json:"hahost"`
+	Hasannotations                   bool                                   `json:"hasannotations"`
+	Hasenoughcapacity                bool                                   `json:"hasenoughcapacity"`
+	Hostha                           HAForHostResponse                      `json:"hostha"`
+	Hosttags                         string                                 `json:"hosttags"`
+	Hypervisor                       string                                 `json:"hypervisor"`
+	Hypervisorversion                string                                 `json:"hypervisorversion"`
+	Id                               string                                 `json:"id"`
+	Ipaddress                        string                                 `json:"ipaddress"`
+	Islocalstorageactive             bool                                   `json:"islocalstorageactive"`
+	Istagarule                       bool                                   `json:"istagarule"`
+	JobID                            string                                 `json:"jobid"`
+	Jobstatus                        int                                    `json:"jobstatus"`
+	Lastannotated                    string                                 `json:"lastannotated"`
+	Lastpinged                       string                                 `json:"lastpinged"`
+	Managementserverid               UUID                                   `json:"managementserverid"`
+	Memoryallocated                  int64                                  `json:"memoryallocated"`
+	Memoryallocatedbytes             int64                                  `json:"memoryallocatedbytes"`
+	Memoryallocatedpercentage        string                                 `json:"memoryallocatedpercentage"`
+	Memorytotal                      int64                                  `json:"memorytotal"`
+	Memoryused                       int64                                  `json:"memoryused"`
+	Memorywithoverprovisioning       string                                 `json:"memorywithoverprovisioning"`
+	Name                             string                                 `json:"name"`
+	Networkkbsread                   int64                                  `json:"networkkbsread"`
+	Networkkbswrite                  int64                                  `json:"networkkbswrite"`
+	Oscategoryid                     string                                 `json:"oscategoryid"`
+	Oscategoryname                   string                                 `json:"oscategoryname"`
+	Outofbandmanagement              OutOfBandManagementResponse            `json:"outofbandmanagement"`
+	Podid                            string                                 `json:"podid"`
+	Podname                          string                                 `json:"podname"`
+	Removed                          string                                 `json:"removed"`
+	Resourcestate                    string                                 `json:"resourcestate"`
+	State                            string                                 `json:"state"`
+	Suitableformigration             bool                                   `json:"suitableformigration"`
+	Type                             string                                 `json:"type"`
+	Ueficapability                   bool                                   `json:"ueficapability"`
+	Username                         string                                 `json:"username"`
+	Version                          string                                 `json:"version"`
+	Zoneid                           string                                 `json:"zoneid"`
+	Zonename                         string                                 `json:"zonename"`
+}
+
+type CancelHostAsDegradedResponseGpugroup struct {
+	Gpugroupname string                                     `json:"gpugroupname"`
+	Vgpu         []CancelHostAsDegradedResponseGpugroupVgpu `json:"vgpu"`
+}
+
+type CancelHostAsDegradedResponseGpugroupVgpu struct {
+	Maxcapacity       int64  `json:"maxcapacity"`
+	Maxheads          int64  `json:"maxheads"`
+	Maxresolutionx    int64  `json:"maxresolutionx"`
+	Maxresolutiony    int64  `json:"maxresolutiony"`
+	Maxvgpuperpgpu    int64  `json:"maxvgpuperpgpu"`
+	Remainingcapacity int64  `json:"remainingcapacity"`
+	Vgputype          string `json:"vgputype"`
+	Videoram          int64  `json:"videoram"`
+}
+
+type ListHostHAProvidersParams struct {
+	p map[string]interface{}
+}
+
+func (p *ListHostHAProvidersParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["hypervisor"]; found {
+		u.Set("hypervisor", v.(string))
+	}
+	return u
+}
+
+func (p *ListHostHAProvidersParams) SetHypervisor(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["hypervisor"] = v
+}
+
+func (p *ListHostHAProvidersParams) ResetHypervisor() {
+	if p.p != nil && p.p["hypervisor"] != nil {
+		delete(p.p, "hypervisor")
+	}
+}
+
+func (p *ListHostHAProvidersParams) GetHypervisor() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["hypervisor"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new ListHostHAProvidersParams instance,
+// as then you are sure you have configured all required params
+func (s *HostService) NewListHostHAProvidersParams(hypervisor string) *ListHostHAProvidersParams {
+	p := &ListHostHAProvidersParams{}
+	p.p = make(map[string]interface{})
+	p.p["hypervisor"] = hypervisor
+	return p
+}
+
+// Lists HA providers
+func (s *HostService) ListHostHAProviders(p *ListHostHAProvidersParams) (*ListHostHAProvidersResponse, error) {
+	resp, err := s.cs.newRequest("listHostHAProviders", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r ListHostHAProvidersResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type ListHostHAProvidersResponse struct {
+	Count           int               `json:"count"`
+	HostHAProviders []*HostHAProvider `json:"haprovider"`
+}
+
+type HostHAProvider struct {
+	Haenable   bool   `json:"haenable"`
+	Haprovider string `json:"haprovider"`
+	Hastate    string `json:"hastate"`
+	Hostid     string `json:"hostid"`
+	JobID      string `json:"jobid"`
+	Jobstatus  int    `json:"jobstatus"`
+	Status     bool   `json:"status"`
+}
+
+type ListSecondaryStorageSelectorsParams struct {
+	p map[string]interface{}
+}
+
+func (p *ListSecondaryStorageSelectorsParams) 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["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)
+	}
+	if v, found := p.p["showremoved"]; found {
+		vv := strconv.FormatBool(v.(bool))
+		u.Set("showremoved", vv)
+	}
+	if v, found := p.p["type"]; found {
+		u.Set("type", v.(string))
+	}
+	if v, found := p.p["zoneid"]; found {
+		u.Set("zoneid", v.(string))
+	}
+	return u
+}
+
+func (p *ListSecondaryStorageSelectorsParams) SetKeyword(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["keyword"] = v
+}
+
+func (p *ListSecondaryStorageSelectorsParams) ResetKeyword() {
+	if p.p != nil && p.p["keyword"] != nil {
+		delete(p.p, "keyword")
+	}
+}
+
+func (p *ListSecondaryStorageSelectorsParams) GetKeyword() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["keyword"].(string)
+	return value, ok
+}
+
+func (p *ListSecondaryStorageSelectorsParams) SetPage(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["page"] = v
+}
+
+func (p *ListSecondaryStorageSelectorsParams) ResetPage() {
+	if p.p != nil && p.p["page"] != nil {
+		delete(p.p, "page")
+	}
+}
+
+func (p *ListSecondaryStorageSelectorsParams) GetPage() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["page"].(int)
+	return value, ok
+}
+
+func (p *ListSecondaryStorageSelectorsParams) SetPagesize(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["pagesize"] = v
+}
+
+func (p *ListSecondaryStorageSelectorsParams) ResetPagesize() {
+	if p.p != nil && p.p["pagesize"] != nil {
+		delete(p.p, "pagesize")
+	}
+}
+
+func (p *ListSecondaryStorageSelectorsParams) GetPagesize() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["pagesize"].(int)
+	return value, ok
+}
+
+func (p *ListSecondaryStorageSelectorsParams) SetShowremoved(v bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["showremoved"] = v
+}
+
+func (p *ListSecondaryStorageSelectorsParams) ResetShowremoved() {
+	if p.p != nil && p.p["showremoved"] != nil {
+		delete(p.p, "showremoved")
+	}
+}
+
+func (p *ListSecondaryStorageSelectorsParams) GetShowremoved() (bool, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["showremoved"].(bool)
+	return value, ok
+}
+
+func (p *ListSecondaryStorageSelectorsParams) SetType(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["type"] = v
+}
+
+func (p *ListSecondaryStorageSelectorsParams) ResetType() {
+	if p.p != nil && p.p["type"] != nil {
+		delete(p.p, "type")
+	}
+}
+
+func (p *ListSecondaryStorageSelectorsParams) GetType() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["type"].(string)
+	return value, ok
+}
+
+func (p *ListSecondaryStorageSelectorsParams) SetZoneid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["zoneid"] = v
+}
+
+func (p *ListSecondaryStorageSelectorsParams) ResetZoneid() {
+	if p.p != nil && p.p["zoneid"] != nil {
+		delete(p.p, "zoneid")
+	}
+}
+
+func (p *ListSecondaryStorageSelectorsParams) 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 ListSecondaryStorageSelectorsParams instance,
+// as then you are sure you have configured all required params
+func (s *HostService) NewListSecondaryStorageSelectorsParams(zoneid string) *ListSecondaryStorageSelectorsParams {
+	p := &ListSecondaryStorageSelectorsParams{}
+	p.p = make(map[string]interface{})
+	p.p["zoneid"] = zoneid
+	return p
+}
+
+// This is a courtesy helper function, which in some cases may not work as expected!
+func (s *HostService) GetSecondaryStorageSelectorID(keyword string, zoneid string, opts ...OptionFunc) (string, int, error) {
+	p := &ListSecondaryStorageSelectorsParams{}
+	p.p = make(map[string]interface{})
+
+	p.p["keyword"] = keyword
+	p.p["zoneid"] = zoneid
+
+	for _, fn := range append(s.cs.options, opts...) {
+		if err := fn(s.cs, p); err != nil {
+			return "", -1, err
+		}
+	}
+
+	l, err := s.ListSecondaryStorageSelectors(p)
+	if err != nil {
+		return "", -1, err
+	}
+
+	if l.Count == 0 {
+		return "", l.Count, fmt.Errorf("No match found for %s: %+v", keyword, l)
+	}
+
+	if l.Count == 1 {
+		return l.SecondaryStorageSelectors[0].Id, l.Count, nil
+	}
+
+	if l.Count > 1 {
+		for _, v := range l.SecondaryStorageSelectors {
+			if v.Name == keyword {
+				return v.Id, l.Count, nil
+			}
+		}
+	}
+	return "", l.Count, fmt.Errorf("Could not find an exact match for %s: %+v", keyword, l)
+}
+
+// Lists the secondary storage selectors and their rules.
+func (s *HostService) ListSecondaryStorageSelectors(p *ListSecondaryStorageSelectorsParams) (*ListSecondaryStorageSelectorsResponse, error) {
+	resp, err := s.cs.newRequest("listSecondaryStorageSelectors", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r ListSecondaryStorageSelectorsResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type ListSecondaryStorageSelectorsResponse struct {
+	Count                     int                         `json:"count"`
+	SecondaryStorageSelectors []*SecondaryStorageSelector `json:"heuristics"`
+}
+
+type SecondaryStorageSelector struct {
+	Created       string `json:"created"`
+	Description   string `json:"description"`
+	Heuristicrule string `json:"heuristicrule"`
+	Id            string `json:"id"`
+	JobID         string `json:"jobid"`
+	Jobstatus     int    `json:"jobstatus"`
+	Name          string `json:"name"`
+	Removed       string `json:"removed"`
+	Type          string `json:"type"`
+	Zoneid        string `json:"zoneid"`
+}
+
+type CreateSecondaryStorageSelectorParams struct {
+	p map[string]interface{}
+}
+
+func (p *CreateSecondaryStorageSelectorParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["description"]; found {
+		u.Set("description", v.(string))
+	}
+	if v, found := p.p["heuristicrule"]; found {
+		u.Set("heuristicrule", v.(string))
+	}
+	if v, found := p.p["name"]; found {
+		u.Set("name", v.(string))
+	}
+	if v, found := p.p["type"]; found {
+		u.Set("type", v.(string))
+	}
+	if v, found := p.p["zoneid"]; found {
+		u.Set("zoneid", v.(string))
+	}
+	return u
+}
+
+func (p *CreateSecondaryStorageSelectorParams) SetDescription(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["description"] = v
+}
+
+func (p *CreateSecondaryStorageSelectorParams) ResetDescription() {
+	if p.p != nil && p.p["description"] != nil {
+		delete(p.p, "description")
+	}
+}
+
+func (p *CreateSecondaryStorageSelectorParams) GetDescription() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["description"].(string)
+	return value, ok
+}
+
+func (p *CreateSecondaryStorageSelectorParams) SetHeuristicrule(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["heuristicrule"] = v
+}
+
+func (p *CreateSecondaryStorageSelectorParams) ResetHeuristicrule() {
+	if p.p != nil && p.p["heuristicrule"] != nil {
+		delete(p.p, "heuristicrule")
+	}
+}
+
+func (p *CreateSecondaryStorageSelectorParams) GetHeuristicrule() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["heuristicrule"].(string)
+	return value, ok
+}
+
+func (p *CreateSecondaryStorageSelectorParams) SetName(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["name"] = v
+}
+
+func (p *CreateSecondaryStorageSelectorParams) ResetName() {
+	if p.p != nil && p.p["name"] != nil {
+		delete(p.p, "name")
+	}
+}
+
+func (p *CreateSecondaryStorageSelectorParams) GetName() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["name"].(string)
+	return value, ok
+}
+
+func (p *CreateSecondaryStorageSelectorParams) SetType(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["type"] = v
+}
+
+func (p *CreateSecondaryStorageSelectorParams) ResetType() {
+	if p.p != nil && p.p["type"] != nil {
+		delete(p.p, "type")
+	}
+}
+
+func (p *CreateSecondaryStorageSelectorParams) GetType() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["type"].(string)
+	return value, ok
+}
+
+func (p *CreateSecondaryStorageSelectorParams) SetZoneid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["zoneid"] = v
+}
+
+func (p *CreateSecondaryStorageSelectorParams) ResetZoneid() {
+	if p.p != nil && p.p["zoneid"] != nil {
+		delete(p.p, "zoneid")
+	}
+}
+
+func (p *CreateSecondaryStorageSelectorParams) 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 CreateSecondaryStorageSelectorParams instance,
+// as then you are sure you have configured all required params
+func (s *HostService) NewCreateSecondaryStorageSelectorParams(description string, heuristicrule string, name string, hostType string, zoneid string) *CreateSecondaryStorageSelectorParams {
+	p := &CreateSecondaryStorageSelectorParams{}
+	p.p = make(map[string]interface{})
+	p.p["description"] = description
+	p.p["heuristicrule"] = heuristicrule
+	p.p["name"] = name
+	p.p["type"] = hostType
+	p.p["zoneid"] = zoneid
+	return p
+}
+
+// Creates a secondary storage selector, described by the heuristic rule.
+func (s *HostService) CreateSecondaryStorageSelector(p *CreateSecondaryStorageSelectorParams) (*CreateSecondaryStorageSelectorResponse, error) {
+	resp, err := s.cs.newRequest("createSecondaryStorageSelector", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var nested struct {
+		Response CreateSecondaryStorageSelectorResponse `json:"heuristics"`
+	}
+	if err := json.Unmarshal(resp, &nested); err != nil {
+		return nil, err
+	}
+	r := nested.Response
+
+	return &r, nil
+}
+
+type CreateSecondaryStorageSelectorResponse struct {
+	Created       string `json:"created"`
+	Description   string `json:"description"`
+	Heuristicrule string `json:"heuristicrule"`
+	Id            string `json:"id"`
+	JobID         string `json:"jobid"`
+	Jobstatus     int    `json:"jobstatus"`
+	Name          string `json:"name"`
+	Removed       string `json:"removed"`
+	Type          string `json:"type"`
+	Zoneid        string `json:"zoneid"`
+}
+
+type RemoveSecondaryStorageSelectorParams struct {
+	p map[string]interface{}
+}
+
+func (p *RemoveSecondaryStorageSelectorParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	return u
+}
+
+func (p *RemoveSecondaryStorageSelectorParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *RemoveSecondaryStorageSelectorParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *RemoveSecondaryStorageSelectorParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new RemoveSecondaryStorageSelectorParams instance,
+// as then you are sure you have configured all required params
+func (s *HostService) NewRemoveSecondaryStorageSelectorParams(id string) *RemoveSecondaryStorageSelectorParams {
+	p := &RemoveSecondaryStorageSelectorParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	return p
+}
+
+// Removes an existing secondary storage selector.
+func (s *HostService) RemoveSecondaryStorageSelector(p *RemoveSecondaryStorageSelectorParams) (*RemoveSecondaryStorageSelectorResponse, error) {
+	resp, err := s.cs.newRequest("removeSecondaryStorageSelector", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r RemoveSecondaryStorageSelectorResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type RemoveSecondaryStorageSelectorResponse struct {
+	Created       string `json:"created"`
+	Description   string `json:"description"`
+	Heuristicrule string `json:"heuristicrule"`
+	Id            string `json:"id"`
+	JobID         string `json:"jobid"`
+	Jobstatus     int    `json:"jobstatus"`
+	Name          string `json:"name"`
+	Removed       string `json:"removed"`
+	Type          string `json:"type"`
+	Zoneid        string `json:"zoneid"`
+}
+
+type ListHostHAResourcesParams struct {
+	p map[string]interface{}
+}
+
+func (p *ListHostHAResourcesParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["hostid"]; found {
+		u.Set("hostid", v.(string))
+	}
+	return u
+}
+
+func (p *ListHostHAResourcesParams) SetHostid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["hostid"] = v
+}
+
+func (p *ListHostHAResourcesParams) ResetHostid() {
+	if p.p != nil && p.p["hostid"] != nil {
+		delete(p.p, "hostid")
+	}
+}
+
+func (p *ListHostHAResourcesParams) GetHostid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["hostid"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new ListHostHAResourcesParams instance,
+// as then you are sure you have configured all required params
+func (s *HostService) NewListHostHAResourcesParams() *ListHostHAResourcesParams {
+	p := &ListHostHAResourcesParams{}
+	p.p = make(map[string]interface{})
+	return p
+}
+
+// Lists host HA resources
+func (s *HostService) ListHostHAResources(p *ListHostHAResourcesParams) (*ListHostHAResourcesResponse, error) {
+	resp, err := s.cs.newRequest("listHostHAResources", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r ListHostHAResourcesResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type ListHostHAResourcesResponse struct {
+	Count           int               `json:"count"`
+	HostHAResources []*HostHAResource `json:"hostha"`
+}
+
+type HostHAResource struct {
+	Haenable   bool   `json:"haenable"`
+	Haprovider string `json:"haprovider"`
+	Hastate    string `json:"hastate"`
+	Hostid     string `json:"hostid"`
+	JobID      string `json:"jobid"`
+	Jobstatus  int    `json:"jobstatus"`
+	Status     bool   `json:"status"`
+}
+
+type DeclareHostAsDegradedParams struct {
+	p map[string]interface{}
+}
+
+func (p *DeclareHostAsDegradedParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	return u
+}
+
+func (p *DeclareHostAsDegradedParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *DeclareHostAsDegradedParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *DeclareHostAsDegradedParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new DeclareHostAsDegradedParams instance,
+// as then you are sure you have configured all required params
+func (s *HostService) NewDeclareHostAsDegradedParams(id string) *DeclareHostAsDegradedParams {
+	p := &DeclareHostAsDegradedParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	return p
+}
+
+// Declare host as 'Degraded'. Host must be on 'Disconnected' or 'Alert' state. The ADMIN must be sure that there are no VMs running on the respective host otherwise this command might corrupted VMs that were running on the 'Degraded' host.
+func (s *HostService) DeclareHostAsDegraded(p *DeclareHostAsDegradedParams) (*DeclareHostAsDegradedResponse, error) {
+	resp, err := s.cs.newRequest("declareHostAsDegraded", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r DeclareHostAsDegradedResponse
+	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
+		}
+
+		b, err = getRawValue(b)
+		if err != nil {
+			return nil, err
+		}
+
+		if err := json.Unmarshal(b, &r); err != nil {
+			return nil, err
+		}
+	}
+
+	return &r, nil
+}
+
+type DeclareHostAsDegradedResponse struct {
+	Annotation                       string                                  `json:"annotation"`
+	Capabilities                     string                                  `json:"capabilities"`
+	Clusterid                        string                                  `json:"clusterid"`
+	Clustername                      string                                  `json:"clustername"`
+	Clustertype                      string                                  `json:"clustertype"`
+	Cpuallocated                     string                                  `json:"cpuallocated"`
+	Cpuallocatedpercentage           string                                  `json:"cpuallocatedpercentage"`
+	Cpuallocatedvalue                int64                                   `json:"cpuallocatedvalue"`
+	Cpuallocatedwithoverprovisioning string                                  `json:"cpuallocatedwithoverprovisioning"`
+	Cpuloadaverage                   float64                                 `json:"cpuloadaverage"`
+	Cpunumber                        int                                     `json:"cpunumber"`
+	Cpusockets                       int                                     `json:"cpusockets"`
+	Cpuspeed                         int64                                   `json:"cpuspeed"`
+	Cpuused                          string                                  `json:"cpuused"`
+	Cpuwithoverprovisioning          string                                  `json:"cpuwithoverprovisioning"`
+	Created                          string                                  `json:"created"`
+	Details                          map[string]string                       `json:"details"`
+	Disconnected                     string                                  `json:"disconnected"`
+	Disksizeallocated                int64                                   `json:"disksizeallocated"`
+	Disksizetotal                    int64                                   `json:"disksizetotal"`
+	Encryptionsupported              bool                                    `json:"encryptionsupported"`
+	Events                           string                                  `json:"events"`
+	Gpugroup                         []DeclareHostAsDegradedResponseGpugroup `json:"gpugroup"`
+	Hahost                           bool                                    `json:"hahost"`
+	Hasannotations                   bool                                    `json:"hasannotations"`
+	Hasenoughcapacity                bool                                    `json:"hasenoughcapacity"`
+	Hostha                           HAForHostResponse                       `json:"hostha"`
+	Hosttags                         string                                  `json:"hosttags"`
+	Hypervisor                       string                                  `json:"hypervisor"`
+	Hypervisorversion                string                                  `json:"hypervisorversion"`
+	Id                               string                                  `json:"id"`
+	Ipaddress                        string                                  `json:"ipaddress"`
+	Islocalstorageactive             bool                                    `json:"islocalstorageactive"`
+	Istagarule                       bool                                    `json:"istagarule"`
+	JobID                            string                                  `json:"jobid"`
+	Jobstatus                        int                                     `json:"jobstatus"`
+	Lastannotated                    string                                  `json:"lastannotated"`
+	Lastpinged                       string                                  `json:"lastpinged"`
+	Managementserverid               UUID                                    `json:"managementserverid"`
+	Memoryallocated                  int64                                   `json:"memoryallocated"`
+	Memoryallocatedbytes             int64                                   `json:"memoryallocatedbytes"`
+	Memoryallocatedpercentage        string                                  `json:"memoryallocatedpercentage"`
+	Memorytotal                      int64                                   `json:"memorytotal"`
+	Memoryused                       int64                                   `json:"memoryused"`
+	Memorywithoverprovisioning       string                                  `json:"memorywithoverprovisioning"`
+	Name                             string                                  `json:"name"`
+	Networkkbsread                   int64                                   `json:"networkkbsread"`
+	Networkkbswrite                  int64                                   `json:"networkkbswrite"`
+	Oscategoryid                     string                                  `json:"oscategoryid"`
+	Oscategoryname                   string                                  `json:"oscategoryname"`
+	Outofbandmanagement              OutOfBandManagementResponse             `json:"outofbandmanagement"`
+	Podid                            string                                  `json:"podid"`
+	Podname                          string                                  `json:"podname"`
+	Removed                          string                                  `json:"removed"`
+	Resourcestate                    string                                  `json:"resourcestate"`
+	State                            string                                  `json:"state"`
+	Suitableformigration             bool                                    `json:"suitableformigration"`
+	Type                             string                                  `json:"type"`
+	Ueficapability                   bool                                    `json:"ueficapability"`
+	Username                         string                                  `json:"username"`
+	Version                          string                                  `json:"version"`
+	Zoneid                           string                                  `json:"zoneid"`
+	Zonename                         string                                  `json:"zonename"`
+}
+
+type DeclareHostAsDegradedResponseGpugroup struct {
+	Gpugroupname string                                      `json:"gpugroupname"`
+	Vgpu         []DeclareHostAsDegradedResponseGpugroupVgpu `json:"vgpu"`
+}
+
+type DeclareHostAsDegradedResponseGpugroupVgpu struct {
+	Maxcapacity       int64  `json:"maxcapacity"`
+	Maxheads          int64  `json:"maxheads"`
+	Maxresolutionx    int64  `json:"maxresolutionx"`
+	Maxresolutiony    int64  `json:"maxresolutiony"`
+	Maxvgpuperpgpu    int64  `json:"maxvgpuperpgpu"`
+	Remainingcapacity int64  `json:"remainingcapacity"`
+	Vgputype          string `json:"vgputype"`
+	Videoram          int64  `json:"videoram"`
+}
+
+type UpdateSecondaryStorageSelectorParams struct {
+	p map[string]interface{}
+}
+
+func (p *UpdateSecondaryStorageSelectorParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["heuristicrule"]; found {
+		u.Set("heuristicrule", v.(string))
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	return u
+}
+
+func (p *UpdateSecondaryStorageSelectorParams) SetHeuristicrule(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["heuristicrule"] = v
+}
+
+func (p *UpdateSecondaryStorageSelectorParams) ResetHeuristicrule() {
+	if p.p != nil && p.p["heuristicrule"] != nil {
+		delete(p.p, "heuristicrule")
+	}
+}
+
+func (p *UpdateSecondaryStorageSelectorParams) GetHeuristicrule() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["heuristicrule"].(string)
+	return value, ok
+}
+
+func (p *UpdateSecondaryStorageSelectorParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *UpdateSecondaryStorageSelectorParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *UpdateSecondaryStorageSelectorParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new UpdateSecondaryStorageSelectorParams instance,
+// as then you are sure you have configured all required params
+func (s *HostService) NewUpdateSecondaryStorageSelectorParams(heuristicrule string, id string) *UpdateSecondaryStorageSelectorParams {
+	p := &UpdateSecondaryStorageSelectorParams{}
+	p.p = make(map[string]interface{})
+	p.p["heuristicrule"] = heuristicrule
+	p.p["id"] = id
+	return p
+}
+
+// Updates an existing secondary storage selector.
+func (s *HostService) UpdateSecondaryStorageSelector(p *UpdateSecondaryStorageSelectorParams) (*UpdateSecondaryStorageSelectorResponse, error) {
+	resp, err := s.cs.newRequest("updateSecondaryStorageSelector", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var nested struct {
+		Response UpdateSecondaryStorageSelectorResponse `json:"heuristics"`
+	}
+	if err := json.Unmarshal(resp, &nested); err != nil {
+		return nil, err
+	}
+	r := nested.Response
+
+	return &r, nil
+}
+
+type UpdateSecondaryStorageSelectorResponse struct {
+	Created       string `json:"created"`
+	Description   string `json:"description"`
+	Heuristicrule string `json:"heuristicrule"`
+	Id            string `json:"id"`
+	JobID         string `json:"jobid"`
+	Jobstatus     int    `json:"jobstatus"`
+	Name          string `json:"name"`
+	Removed       string `json:"removed"`
+	Type          string `json:"type"`
+	Zoneid        string `json:"zoneid"`
+}
diff --git a/cloudstack/HostService_mock.go b/cloudstack/HostService_mock.go
index afa82fe..badb90e 100644
--- a/cloudstack/HostService_mock.go
+++ b/cloudstack/HostService_mock.go
@@ -112,6 +112,21 @@ func (mr *MockHostServiceIfaceMockRecorder) AddSecondaryStorage(p interface{}) *
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSecondaryStorage", reflect.TypeOf((*MockHostServiceIface)(nil).AddSecondaryStorage), p)
 }
 
+// CancelHostAsDegraded mocks base method.
+func (m *MockHostServiceIface) CancelHostAsDegraded(p *CancelHostAsDegradedParams) (*CancelHostAsDegradedResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CancelHostAsDegraded", p)
+	ret0, _ := ret[0].(*CancelHostAsDegradedResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CancelHostAsDegraded indicates an expected call of CancelHostAsDegraded.
+func (mr *MockHostServiceIfaceMockRecorder) CancelHostAsDegraded(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CancelHostAsDegraded", reflect.TypeOf((*MockHostServiceIface)(nil).CancelHostAsDegraded), p)
+}
+
 // CancelHostMaintenance mocks base method.
 func (m *MockHostServiceIface) CancelHostMaintenance(p *CancelHostMaintenanceParams) (*CancelHostMaintenanceResponse, error) {
 	m.ctrl.T.Helper()
@@ -142,6 +157,36 @@ func (mr *MockHostServiceIfaceMockRecorder) ConfigureHAForHost(p interface{}) *g
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigureHAForHost", reflect.TypeOf((*MockHostServiceIface)(nil).ConfigureHAForHost), p)
 }
 
+// CreateSecondaryStorageSelector mocks base method.
+func (m *MockHostServiceIface) CreateSecondaryStorageSelector(p *CreateSecondaryStorageSelectorParams) (*CreateSecondaryStorageSelectorResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateSecondaryStorageSelector", p)
+	ret0, _ := ret[0].(*CreateSecondaryStorageSelectorResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateSecondaryStorageSelector indicates an expected call of CreateSecondaryStorageSelector.
+func (mr *MockHostServiceIfaceMockRecorder) CreateSecondaryStorageSelector(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSecondaryStorageSelector", reflect.TypeOf((*MockHostServiceIface)(nil).CreateSecondaryStorageSelector), p)
+}
+
+// DeclareHostAsDegraded mocks base method.
+func (m *MockHostServiceIface) DeclareHostAsDegraded(p *DeclareHostAsDegradedParams) (*DeclareHostAsDegradedResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DeclareHostAsDegraded", p)
+	ret0, _ := ret[0].(*DeclareHostAsDegradedResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// DeclareHostAsDegraded indicates an expected call of DeclareHostAsDegraded.
+func (mr *MockHostServiceIfaceMockRecorder) DeclareHostAsDegraded(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeclareHostAsDegraded", reflect.TypeOf((*MockHostServiceIface)(nil).DeclareHostAsDegraded), p)
+}
+
 // DedicateHost mocks base method.
 func (m *MockHostServiceIface) DedicateHost(p *DedicateHostParams) (*DedicateHostResponse, error) {
 	m.ctrl.T.Helper()
@@ -379,6 +424,27 @@ func (mr *MockHostServiceIfaceMockRecorder) GetHostsMetricID(name interface{}, o
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetHostsMetricID", reflect.TypeOf((*MockHostServiceIface)(nil).GetHostsMetricID), varargs...)
 }
 
+// GetSecondaryStorageSelectorID mocks base method.
+func (m *MockHostServiceIface) GetSecondaryStorageSelectorID(keyword, zoneid string, opts ...OptionFunc) (string, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{keyword, zoneid}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetSecondaryStorageSelectorID", varargs...)
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetSecondaryStorageSelectorID indicates an expected call of GetSecondaryStorageSelectorID.
+func (mr *MockHostServiceIfaceMockRecorder) GetSecondaryStorageSelectorID(keyword, zoneid interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{keyword, zoneid}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSecondaryStorageSelectorID", reflect.TypeOf((*MockHostServiceIface)(nil).GetSecondaryStorageSelectorID), varargs...)
+}
+
 // ListDedicatedHosts mocks base method.
 func (m *MockHostServiceIface) ListDedicatedHosts(p *ListDedicatedHostsParams) (*ListDedicatedHostsResponse, error) {
 	m.ctrl.T.Helper()
@@ -394,6 +460,36 @@ func (mr *MockHostServiceIfaceMockRecorder) ListDedicatedHosts(p interface{}) *g
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDedicatedHosts", reflect.TypeOf((*MockHostServiceIface)(nil).ListDedicatedHosts), p)
 }
 
+// ListHostHAProviders mocks base method.
+func (m *MockHostServiceIface) ListHostHAProviders(p *ListHostHAProvidersParams) (*ListHostHAProvidersResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ListHostHAProviders", p)
+	ret0, _ := ret[0].(*ListHostHAProvidersResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListHostHAProviders indicates an expected call of ListHostHAProviders.
+func (mr *MockHostServiceIfaceMockRecorder) ListHostHAProviders(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListHostHAProviders", reflect.TypeOf((*MockHostServiceIface)(nil).ListHostHAProviders), p)
+}
+
+// ListHostHAResources mocks base method.
+func (m *MockHostServiceIface) ListHostHAResources(p *ListHostHAResourcesParams) (*ListHostHAResourcesResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ListHostHAResources", p)
+	ret0, _ := ret[0].(*ListHostHAResourcesResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListHostHAResources indicates an expected call of ListHostHAResources.
+func (mr *MockHostServiceIfaceMockRecorder) ListHostHAResources(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListHostHAResources", reflect.TypeOf((*MockHostServiceIface)(nil).ListHostHAResources), p)
+}
+
 // ListHostTags mocks base method.
 func (m *MockHostServiceIface) ListHostTags(p *ListHostTagsParams) (*ListHostTagsResponse, error) {
 	m.ctrl.T.Helper()
@@ -439,6 +535,36 @@ func (mr *MockHostServiceIfaceMockRecorder) ListHostsMetrics(p interface{}) *gom
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListHostsMetrics", reflect.TypeOf((*MockHostServiceIface)(nil).ListHostsMetrics), p)
 }
 
+// ListSecondaryStorageSelectors mocks base method.
+func (m *MockHostServiceIface) ListSecondaryStorageSelectors(p *ListSecondaryStorageSelectorsParams) (*ListSecondaryStorageSelectorsResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ListSecondaryStorageSelectors", p)
+	ret0, _ := ret[0].(*ListSecondaryStorageSelectorsResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListSecondaryStorageSelectors indicates an expected call of ListSecondaryStorageSelectors.
+func (mr *MockHostServiceIfaceMockRecorder) ListSecondaryStorageSelectors(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSecondaryStorageSelectors", reflect.TypeOf((*MockHostServiceIface)(nil).ListSecondaryStorageSelectors), p)
+}
+
+// MigrateSecondaryStorageData mocks base method.
+func (m *MockHostServiceIface) MigrateSecondaryStorageData(p *MigrateSecondaryStorageDataParams) (*MigrateSecondaryStorageDataResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "MigrateSecondaryStorageData", p)
+	ret0, _ := ret[0].(*MigrateSecondaryStorageDataResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// MigrateSecondaryStorageData indicates an expected call of MigrateSecondaryStorageData.
+func (mr *MockHostServiceIfaceMockRecorder) MigrateSecondaryStorageData(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MigrateSecondaryStorageData", reflect.TypeOf((*MockHostServiceIface)(nil).MigrateSecondaryStorageData), p)
+}
+
 // NewAddBaremetalHostParams mocks base method.
 func (m *MockHostServiceIface) NewAddBaremetalHostParams(hypervisor, podid, url, zoneid string) *AddBaremetalHostParams {
 	m.ctrl.T.Helper()
@@ -495,6 +621,20 @@ func (mr *MockHostServiceIfaceMockRecorder) NewAddSecondaryStorageParams(url int
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewAddSecondaryStorageParams", reflect.TypeOf((*MockHostServiceIface)(nil).NewAddSecondaryStorageParams), url)
 }
 
+// NewCancelHostAsDegradedParams mocks base method.
+func (m *MockHostServiceIface) NewCancelHostAsDegradedParams(id string) *CancelHostAsDegradedParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewCancelHostAsDegradedParams", id)
+	ret0, _ := ret[0].(*CancelHostAsDegradedParams)
+	return ret0
+}
+
+// NewCancelHostAsDegradedParams indicates an expected call of NewCancelHostAsDegradedParams.
+func (mr *MockHostServiceIfaceMockRecorder) NewCancelHostAsDegradedParams(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewCancelHostAsDegradedParams", reflect.TypeOf((*MockHostServiceIface)(nil).NewCancelHostAsDegradedParams), id)
+}
+
 // NewCancelHostMaintenanceParams mocks base method.
 func (m *MockHostServiceIface) NewCancelHostMaintenanceParams(id string) *CancelHostMaintenanceParams {
 	m.ctrl.T.Helper()
@@ -523,6 +663,34 @@ func (mr *MockHostServiceIfaceMockRecorder) NewConfigureHAForHostParams(hostid,
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewConfigureHAForHostParams", reflect.TypeOf((*MockHostServiceIface)(nil).NewConfigureHAForHostParams), hostid, provider)
 }
 
+// NewCreateSecondaryStorageSelectorParams mocks base method.
+func (m *MockHostServiceIface) NewCreateSecondaryStorageSelectorParams(description, heuristicrule, name, hostType, zoneid string) *CreateSecondaryStorageSelectorParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewCreateSecondaryStorageSelectorParams", description, heuristicrule, name, hostType, zoneid)
+	ret0, _ := ret[0].(*CreateSecondaryStorageSelectorParams)
+	return ret0
+}
+
+// NewCreateSecondaryStorageSelectorParams indicates an expected call of NewCreateSecondaryStorageSelectorParams.
+func (mr *MockHostServiceIfaceMockRecorder) NewCreateSecondaryStorageSelectorParams(description, heuristicrule, name, hostType, zoneid interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewCreateSecondaryStorageSelectorParams", reflect.TypeOf((*MockHostServiceIface)(nil).NewCreateSecondaryStorageSelectorParams), description, heuristicrule, name, hostType, zoneid)
+}
+
+// NewDeclareHostAsDegradedParams mocks base method.
+func (m *MockHostServiceIface) NewDeclareHostAsDegradedParams(id string) *DeclareHostAsDegradedParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewDeclareHostAsDegradedParams", id)
+	ret0, _ := ret[0].(*DeclareHostAsDegradedParams)
+	return ret0
+}
+
+// NewDeclareHostAsDegradedParams indicates an expected call of NewDeclareHostAsDegradedParams.
+func (mr *MockHostServiceIfaceMockRecorder) NewDeclareHostAsDegradedParams(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewDeclareHostAsDegradedParams", reflect.TypeOf((*MockHostServiceIface)(nil).NewDeclareHostAsDegradedParams), id)
+}
+
 // NewDedicateHostParams mocks base method.
 func (m *MockHostServiceIface) NewDedicateHostParams(domainid, hostid string) *DedicateHostParams {
 	m.ctrl.T.Helper()
@@ -621,6 +789,34 @@ func (mr *MockHostServiceIfaceMockRecorder) NewListDedicatedHostsParams() *gomoc
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListDedicatedHostsParams", reflect.TypeOf((*MockHostServiceIface)(nil).NewListDedicatedHostsParams))
 }
 
+// NewListHostHAProvidersParams mocks base method.
+func (m *MockHostServiceIface) NewListHostHAProvidersParams(hypervisor string) *ListHostHAProvidersParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewListHostHAProvidersParams", hypervisor)
+	ret0, _ := ret[0].(*ListHostHAProvidersParams)
+	return ret0
+}
+
+// NewListHostHAProvidersParams indicates an expected call of NewListHostHAProvidersParams.
+func (mr *MockHostServiceIfaceMockRecorder) NewListHostHAProvidersParams(hypervisor interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListHostHAProvidersParams", reflect.TypeOf((*MockHostServiceIface)(nil).NewListHostHAProvidersParams), hypervisor)
+}
+
+// NewListHostHAResourcesParams mocks base method.
+func (m *MockHostServiceIface) NewListHostHAResourcesParams() *ListHostHAResourcesParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewListHostHAResourcesParams")
+	ret0, _ := ret[0].(*ListHostHAResourcesParams)
+	return ret0
+}
+
+// NewListHostHAResourcesParams indicates an expected call of NewListHostHAResourcesParams.
+func (mr *MockHostServiceIfaceMockRecorder) NewListHostHAResourcesParams() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListHostHAResourcesParams", reflect.TypeOf((*MockHostServiceIface)(nil).NewListHostHAResourcesParams))
+}
+
 // NewListHostTagsParams mocks base method.
 func (m *MockHostServiceIface) NewListHostTagsParams() *ListHostTagsParams {
 	m.ctrl.T.Helper()
@@ -663,6 +859,34 @@ func (mr *MockHostServiceIfaceMockRecorder) NewListHostsParams() *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListHostsParams", reflect.TypeOf((*MockHostServiceIface)(nil).NewListHostsParams))
 }
 
+// NewListSecondaryStorageSelectorsParams mocks base method.
+func (m *MockHostServiceIface) NewListSecondaryStorageSelectorsParams(zoneid string) *ListSecondaryStorageSelectorsParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewListSecondaryStorageSelectorsParams", zoneid)
+	ret0, _ := ret[0].(*ListSecondaryStorageSelectorsParams)
+	return ret0
+}
+
+// NewListSecondaryStorageSelectorsParams indicates an expected call of NewListSecondaryStorageSelectorsParams.
+func (mr *MockHostServiceIfaceMockRecorder) NewListSecondaryStorageSelectorsParams(zoneid interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListSecondaryStorageSelectorsParams", reflect.TypeOf((*MockHostServiceIface)(nil).NewListSecondaryStorageSelectorsParams), zoneid)
+}
+
+// NewMigrateSecondaryStorageDataParams mocks base method.
+func (m *MockHostServiceIface) NewMigrateSecondaryStorageDataParams(destpools []string, srcpool string) *MigrateSecondaryStorageDataParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewMigrateSecondaryStorageDataParams", destpools, srcpool)
+	ret0, _ := ret[0].(*MigrateSecondaryStorageDataParams)
+	return ret0
+}
+
+// NewMigrateSecondaryStorageDataParams indicates an expected call of NewMigrateSecondaryStorageDataParams.
+func (mr *MockHostServiceIfaceMockRecorder) NewMigrateSecondaryStorageDataParams(destpools, srcpool interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewMigrateSecondaryStorageDataParams", reflect.TypeOf((*MockHostServiceIface)(nil).NewMigrateSecondaryStorageDataParams), destpools, srcpool)
+}
+
 // NewPrepareHostForMaintenanceParams mocks base method.
 func (m *MockHostServiceIface) NewPrepareHostForMaintenanceParams(id string) *PrepareHostForMaintenanceParams {
 	m.ctrl.T.Helper()
@@ -719,6 +943,20 @@ func (mr *MockHostServiceIfaceMockRecorder) NewReleaseHostReservationParams(id i
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewReleaseHostReservationParams", reflect.TypeOf((*MockHostServiceIface)(nil).NewReleaseHostReservationParams), id)
 }
 
+// NewRemoveSecondaryStorageSelectorParams mocks base method.
+func (m *MockHostServiceIface) NewRemoveSecondaryStorageSelectorParams(id string) *RemoveSecondaryStorageSelectorParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewRemoveSecondaryStorageSelectorParams", id)
+	ret0, _ := ret[0].(*RemoveSecondaryStorageSelectorParams)
+	return ret0
+}
+
+// NewRemoveSecondaryStorageSelectorParams indicates an expected call of NewRemoveSecondaryStorageSelectorParams.
+func (mr *MockHostServiceIfaceMockRecorder) NewRemoveSecondaryStorageSelectorParams(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewRemoveSecondaryStorageSelectorParams", reflect.TypeOf((*MockHostServiceIface)(nil).NewRemoveSecondaryStorageSelectorParams), id)
+}
+
 // NewUpdateHostParams mocks base method.
 func (m *MockHostServiceIface) NewUpdateHostParams(id string) *UpdateHostParams {
 	m.ctrl.T.Helper()
@@ -747,6 +985,20 @@ func (mr *MockHostServiceIfaceMockRecorder) NewUpdateHostPasswordParams(password
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewUpdateHostPasswordParams", reflect.TypeOf((*MockHostServiceIface)(nil).NewUpdateHostPasswordParams), password, username)
 }
 
+// NewUpdateSecondaryStorageSelectorParams mocks base method.
+func (m *MockHostServiceIface) NewUpdateSecondaryStorageSelectorParams(heuristicrule, id string) *UpdateSecondaryStorageSelectorParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewUpdateSecondaryStorageSelectorParams", heuristicrule, id)
+	ret0, _ := ret[0].(*UpdateSecondaryStorageSelectorParams)
+	return ret0
+}
+
+// NewUpdateSecondaryStorageSelectorParams indicates an expected call of NewUpdateSecondaryStorageSelectorParams.
+func (mr *MockHostServiceIfaceMockRecorder) NewUpdateSecondaryStorageSelectorParams(heuristicrule, id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewUpdateSecondaryStorageSelectorParams", reflect.TypeOf((*MockHostServiceIface)(nil).NewUpdateSecondaryStorageSelectorParams), heuristicrule, id)
+}
+
 // PrepareHostForMaintenance mocks base method.
 func (m *MockHostServiceIface) PrepareHostForMaintenance(p *PrepareHostForMaintenanceParams) (*PrepareHostForMaintenanceResponse, error) {
 	m.ctrl.T.Helper()
@@ -807,6 +1059,21 @@ func (mr *MockHostServiceIfaceMockRecorder) ReleaseHostReservation(p interface{}
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseHostReservation", reflect.TypeOf((*MockHostServiceIface)(nil).ReleaseHostReservation), p)
 }
 
+// RemoveSecondaryStorageSelector mocks base method.
+func (m *MockHostServiceIface) RemoveSecondaryStorageSelector(p *RemoveSecondaryStorageSelectorParams) (*RemoveSecondaryStorageSelectorResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "RemoveSecondaryStorageSelector", p)
+	ret0, _ := ret[0].(*RemoveSecondaryStorageSelectorResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// RemoveSecondaryStorageSelector indicates an expected call of RemoveSecondaryStorageSelector.
+func (mr *MockHostServiceIfaceMockRecorder) RemoveSecondaryStorageSelector(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveSecondaryStorageSelector", reflect.TypeOf((*MockHostServiceIface)(nil).RemoveSecondaryStorageSelector), p)
+}
+
 // UpdateHost mocks base method.
 func (m *MockHostServiceIface) UpdateHost(p *UpdateHostParams) (*UpdateHostResponse, error) {
 	m.ctrl.T.Helper()
@@ -836,3 +1103,18 @@ func (mr *MockHostServiceIfaceMockRecorder) UpdateHostPassword(p interface{}) *g
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateHostPassword", reflect.TypeOf((*MockHostServiceIface)(nil).UpdateHostPassword), p)
 }
+
+// UpdateSecondaryStorageSelector mocks base method.
+func (m *MockHostServiceIface) UpdateSecondaryStorageSelector(p *UpdateSecondaryStorageSelectorParams) (*UpdateSecondaryStorageSelectorResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "UpdateSecondaryStorageSelector", p)
+	ret0, _ := ret[0].(*UpdateSecondaryStorageSelectorResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// UpdateSecondaryStorageSelector indicates an expected call of UpdateSecondaryStorageSelector.
+func (mr *MockHostServiceIfaceMockRecorder) UpdateSecondaryStorageSelector(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateSecondaryStorageSelector", reflect.TypeOf((*MockHostServiceIface)(nil).UpdateSecondaryStorageSelector), p)
+}
diff --git a/cloudstack/ImageStoreService.go b/cloudstack/ImageStoreService.go
index 04b2cff..cacdedb 100644
--- a/cloudstack/ImageStoreService.go
+++ b/cloudstack/ImageStoreService.go
@@ -50,6 +50,13 @@ type ImageStoreServiceIface interface {
 	GetSecondaryStagingStoreByID(id string, opts ...OptionFunc) (*SecondaryStagingStore, int, error)
 	UpdateCloudToUseObjectStore(p *UpdateCloudToUseObjectStoreParams) (*UpdateCloudToUseObjectStoreResponse, error)
 	NewUpdateCloudToUseObjectStoreParams(provider string) *UpdateCloudToUseObjectStoreParams
+	ListImageStoreObjects(p *ListImageStoreObjectsParams) (*ListImageStoreObjectsResponse, error)
+	NewListImageStoreObjectsParams(id string) *ListImageStoreObjectsParams
+	GetImageStoreObjectByID(id string, opts ...OptionFunc) (*ImageStoreObject, int, error)
+	UpdateImageStore(p *UpdateImageStoreParams) (*UpdateImageStoreResponse, error)
+	NewUpdateImageStoreParams(id string, readonly bool) *UpdateImageStoreParams
+	DownloadImageStoreObject(p *DownloadImageStoreObjectParams) (*DownloadImageStoreObjectResponse, error)
+	NewDownloadImageStoreObjectParams(id string) *DownloadImageStoreObjectParams
 }
 
 type AddImageStoreParams struct {
@@ -1769,3 +1776,441 @@ type UpdateCloudToUseObjectStoreResponse struct {
 	Zoneid         string `json:"zoneid"`
 	Zonename       string `json:"zonename"`
 }
+
+type ListImageStoreObjectsParams struct {
+	p map[string]interface{}
+}
+
+func (p *ListImageStoreObjectsParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	if v, found := p.p["keyword"]; found {
+		u.Set("keyword", 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)
+	}
+	if v, found := p.p["path"]; found {
+		u.Set("path", v.(string))
+	}
+	return u
+}
+
+func (p *ListImageStoreObjectsParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *ListImageStoreObjectsParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *ListImageStoreObjectsParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+func (p *ListImageStoreObjectsParams) SetKeyword(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["keyword"] = v
+}
+
+func (p *ListImageStoreObjectsParams) ResetKeyword() {
+	if p.p != nil && p.p["keyword"] != nil {
+		delete(p.p, "keyword")
+	}
+}
+
+func (p *ListImageStoreObjectsParams) GetKeyword() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["keyword"].(string)
+	return value, ok
+}
+
+func (p *ListImageStoreObjectsParams) SetPage(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["page"] = v
+}
+
+func (p *ListImageStoreObjectsParams) ResetPage() {
+	if p.p != nil && p.p["page"] != nil {
+		delete(p.p, "page")
+	}
+}
+
+func (p *ListImageStoreObjectsParams) GetPage() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["page"].(int)
+	return value, ok
+}
+
+func (p *ListImageStoreObjectsParams) SetPagesize(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["pagesize"] = v
+}
+
+func (p *ListImageStoreObjectsParams) ResetPagesize() {
+	if p.p != nil && p.p["pagesize"] != nil {
+		delete(p.p, "pagesize")
+	}
+}
+
+func (p *ListImageStoreObjectsParams) GetPagesize() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["pagesize"].(int)
+	return value, ok
+}
+
+func (p *ListImageStoreObjectsParams) SetPath(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["path"] = v
+}
+
+func (p *ListImageStoreObjectsParams) ResetPath() {
+	if p.p != nil && p.p["path"] != nil {
+		delete(p.p, "path")
+	}
+}
+
+func (p *ListImageStoreObjectsParams) GetPath() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["path"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new ListImageStoreObjectsParams instance,
+// as then you are sure you have configured all required params
+func (s *ImageStoreService) NewListImageStoreObjectsParams(id string) *ListImageStoreObjectsParams {
+	p := &ListImageStoreObjectsParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	return p
+}
+
+// This is a courtesy helper function, which in some cases may not work as expected!
+func (s *ImageStoreService) GetImageStoreObjectByID(id string, opts ...OptionFunc) (*ImageStoreObject, int, error) {
+	p := &ListImageStoreObjectsParams{}
+	p.p = make(map[string]interface{})
+
+	p.p["id"] = id
+
+	for _, fn := range append(s.cs.options, opts...) {
+		if err := fn(s.cs, p); err != nil {
+			return nil, -1, err
+		}
+	}
+
+	l, err := s.ListImageStoreObjects(p)
+	if err != nil {
+		if strings.Contains(err.Error(), fmt.Sprintf(
+			"Invalid parameter id value=%s due to incorrect long value format, "+
+				"or entity does not exist", id)) {
+			return nil, 0, fmt.Errorf("No match found for %s: %+v", id, l)
+		}
+		return nil, -1, err
+	}
+
+	if l.Count == 0 {
+		return nil, l.Count, fmt.Errorf("No match found for %s: %+v", id, l)
+	}
+
+	if l.Count == 1 {
+		return l.ImageStoreObjects[0], l.Count, nil
+	}
+	return nil, l.Count, fmt.Errorf("There is more then one result for ImageStoreObject UUID: %s!", id)
+}
+
+// Lists objects at specified path on an image store.
+func (s *ImageStoreService) ListImageStoreObjects(p *ListImageStoreObjectsParams) (*ListImageStoreObjectsResponse, error) {
+	resp, err := s.cs.newRequest("listImageStoreObjects", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r ListImageStoreObjectsResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type ListImageStoreObjectsResponse struct {
+	Count             int                 `json:"count"`
+	ImageStoreObjects []*ImageStoreObject `json:"datastoreobject"`
+}
+
+type ImageStoreObject struct {
+	Format      string `json:"format"`
+	Isdirectory bool   `json:"isdirectory"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Lastupdated string `json:"lastupdated"`
+	Name        string `json:"name"`
+	Size        int64  `json:"size"`
+	Snapshotid  string `json:"snapshotid"`
+	Templateid  string `json:"templateid"`
+	Volumeid    string `json:"volumeid"`
+}
+
+type UpdateImageStoreParams struct {
+	p map[string]interface{}
+}
+
+func (p *UpdateImageStoreParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	if v, found := p.p["readonly"]; found {
+		vv := strconv.FormatBool(v.(bool))
+		u.Set("readonly", vv)
+	}
+	return u
+}
+
+func (p *UpdateImageStoreParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *UpdateImageStoreParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *UpdateImageStoreParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+func (p *UpdateImageStoreParams) SetReadonly(v bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["readonly"] = v
+}
+
+func (p *UpdateImageStoreParams) ResetReadonly() {
+	if p.p != nil && p.p["readonly"] != nil {
+		delete(p.p, "readonly")
+	}
+}
+
+func (p *UpdateImageStoreParams) GetReadonly() (bool, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["readonly"].(bool)
+	return value, ok
+}
+
+// You should always use this function to get a new UpdateImageStoreParams instance,
+// as then you are sure you have configured all required params
+func (s *ImageStoreService) NewUpdateImageStoreParams(id string, readonly bool) *UpdateImageStoreParams {
+	p := &UpdateImageStoreParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	p.p["readonly"] = readonly
+	return p
+}
+
+// Updates image store read-only status
+func (s *ImageStoreService) UpdateImageStore(p *UpdateImageStoreParams) (*UpdateImageStoreResponse, error) {
+	resp, err := s.cs.newRequest("updateImageStore", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var nested struct {
+		Response UpdateImageStoreResponse `json:"imagestore"`
+	}
+	if err := json.Unmarshal(resp, &nested); err != nil {
+		return nil, err
+	}
+	r := nested.Response
+
+	return &r, nil
+}
+
+type UpdateImageStoreResponse struct {
+	Disksizetotal  int64  `json:"disksizetotal"`
+	Disksizeused   int64  `json:"disksizeused"`
+	Hasannotations bool   `json:"hasannotations"`
+	Id             string `json:"id"`
+	JobID          string `json:"jobid"`
+	Jobstatus      int    `json:"jobstatus"`
+	Name           string `json:"name"`
+	Protocol       string `json:"protocol"`
+	Providername   string `json:"providername"`
+	Readonly       bool   `json:"readonly"`
+	Scope          string `json:"scope"`
+	Url            string `json:"url"`
+	Zoneid         string `json:"zoneid"`
+	Zonename       string `json:"zonename"`
+}
+
+type DownloadImageStoreObjectParams struct {
+	p map[string]interface{}
+}
+
+func (p *DownloadImageStoreObjectParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	if v, found := p.p["path"]; found {
+		u.Set("path", v.(string))
+	}
+	return u
+}
+
+func (p *DownloadImageStoreObjectParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *DownloadImageStoreObjectParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *DownloadImageStoreObjectParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+func (p *DownloadImageStoreObjectParams) SetPath(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["path"] = v
+}
+
+func (p *DownloadImageStoreObjectParams) ResetPath() {
+	if p.p != nil && p.p["path"] != nil {
+		delete(p.p, "path")
+	}
+}
+
+func (p *DownloadImageStoreObjectParams) GetPath() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["path"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new DownloadImageStoreObjectParams instance,
+// as then you are sure you have configured all required params
+func (s *ImageStoreService) NewDownloadImageStoreObjectParams(id string) *DownloadImageStoreObjectParams {
+	p := &DownloadImageStoreObjectParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	return p
+}
+
+// Download object at a specified path on an image store.
+func (s *ImageStoreService) DownloadImageStoreObject(p *DownloadImageStoreObjectParams) (*DownloadImageStoreObjectResponse, error) {
+	resp, err := s.cs.newRequest("downloadImageStoreObject", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r DownloadImageStoreObjectResponse
+	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
+		}
+
+		b, err = getRawValue(b)
+		if err != nil {
+			return nil, err
+		}
+
+		if err := json.Unmarshal(b, &r); err != nil {
+			return nil, err
+		}
+	}
+
+	return &r, nil
+}
+
+type DownloadImageStoreObjectResponse struct {
+	Accountid        string `json:"accountid"`
+	Created          string `json:"created"`
+	ExtractId        string `json:"extractId"`
+	ExtractMode      string `json:"extractMode"`
+	Id               string `json:"id"`
+	JobID            string `json:"jobid"`
+	Jobstatus        int    `json:"jobstatus"`
+	Name             string `json:"name"`
+	Resultstring     string `json:"resultstring"`
+	State            string `json:"state"`
+	Status           string `json:"status"`
+	Storagetype      string `json:"storagetype"`
+	Uploadpercentage int    `json:"uploadpercentage"`
+	Url              string `json:"url"`
+	Zoneid           string `json:"zoneid"`
+	Zonename         string `json:"zonename"`
+}
diff --git a/cloudstack/ImageStoreService_mock.go b/cloudstack/ImageStoreService_mock.go
index 4c14bed..29dc1b4 100644
--- a/cloudstack/ImageStoreService_mock.go
+++ b/cloudstack/ImageStoreService_mock.go
@@ -127,6 +127,21 @@ func (mr *MockImageStoreServiceIfaceMockRecorder) DeleteSecondaryStagingStore(p
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSecondaryStagingStore", reflect.TypeOf((*MockImageStoreServiceIface)(nil).DeleteSecondaryStagingStore), p)
 }
 
+// DownloadImageStoreObject mocks base method.
+func (m *MockImageStoreServiceIface) DownloadImageStoreObject(p *DownloadImageStoreObjectParams) (*DownloadImageStoreObjectResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DownloadImageStoreObject", p)
+	ret0, _ := ret[0].(*DownloadImageStoreObjectResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// DownloadImageStoreObject indicates an expected call of DownloadImageStoreObject.
+func (mr *MockImageStoreServiceIfaceMockRecorder) DownloadImageStoreObject(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DownloadImageStoreObject", reflect.TypeOf((*MockImageStoreServiceIface)(nil).DownloadImageStoreObject), p)
+}
+
 // GetImageStoreByID mocks base method.
 func (m *MockImageStoreServiceIface) GetImageStoreByID(id string, opts ...OptionFunc) (*ImageStore, int, error) {
 	m.ctrl.T.Helper()
@@ -190,6 +205,27 @@ func (mr *MockImageStoreServiceIfaceMockRecorder) GetImageStoreID(name interface
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetImageStoreID", reflect.TypeOf((*MockImageStoreServiceIface)(nil).GetImageStoreID), varargs...)
 }
 
+// GetImageStoreObjectByID mocks base method.
+func (m *MockImageStoreServiceIface) GetImageStoreObjectByID(id string, opts ...OptionFunc) (*ImageStoreObject, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{id}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetImageStoreObjectByID", varargs...)
+	ret0, _ := ret[0].(*ImageStoreObject)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetImageStoreObjectByID indicates an expected call of GetImageStoreObjectByID.
+func (mr *MockImageStoreServiceIfaceMockRecorder) GetImageStoreObjectByID(id interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{id}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetImageStoreObjectByID", reflect.TypeOf((*MockImageStoreServiceIface)(nil).GetImageStoreObjectByID), varargs...)
+}
+
 // GetSecondaryStagingStoreByID mocks base method.
 func (m *MockImageStoreServiceIface) GetSecondaryStagingStoreByID(id string, opts ...OptionFunc) (*SecondaryStagingStore, int, error) {
 	m.ctrl.T.Helper()
@@ -253,6 +289,21 @@ func (mr *MockImageStoreServiceIfaceMockRecorder) GetSecondaryStagingStoreID(nam
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSecondaryStagingStoreID", reflect.TypeOf((*MockImageStoreServiceIface)(nil).GetSecondaryStagingStoreID), varargs...)
 }
 
+// ListImageStoreObjects mocks base method.
+func (m *MockImageStoreServiceIface) ListImageStoreObjects(p *ListImageStoreObjectsParams) (*ListImageStoreObjectsResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ListImageStoreObjects", p)
+	ret0, _ := ret[0].(*ListImageStoreObjectsResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListImageStoreObjects indicates an expected call of ListImageStoreObjects.
+func (mr *MockImageStoreServiceIfaceMockRecorder) ListImageStoreObjects(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListImageStoreObjects", reflect.TypeOf((*MockImageStoreServiceIface)(nil).ListImageStoreObjects), p)
+}
+
 // ListImageStores mocks base method.
 func (m *MockImageStoreServiceIface) ListImageStores(p *ListImageStoresParams) (*ListImageStoresResponse, error) {
 	m.ctrl.T.Helper()
@@ -353,6 +404,34 @@ func (mr *MockImageStoreServiceIfaceMockRecorder) NewDeleteSecondaryStagingStore
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewDeleteSecondaryStagingStoreParams", reflect.TypeOf((*MockImageStoreServiceIface)(nil).NewDeleteSecondaryStagingStoreParams), id)
 }
 
+// NewDownloadImageStoreObjectParams mocks base method.
+func (m *MockImageStoreServiceIface) NewDownloadImageStoreObjectParams(id string) *DownloadImageStoreObjectParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewDownloadImageStoreObjectParams", id)
+	ret0, _ := ret[0].(*DownloadImageStoreObjectParams)
+	return ret0
+}
+
+// NewDownloadImageStoreObjectParams indicates an expected call of NewDownloadImageStoreObjectParams.
+func (mr *MockImageStoreServiceIfaceMockRecorder) NewDownloadImageStoreObjectParams(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewDownloadImageStoreObjectParams", reflect.TypeOf((*MockImageStoreServiceIface)(nil).NewDownloadImageStoreObjectParams), id)
+}
+
+// NewListImageStoreObjectsParams mocks base method.
+func (m *MockImageStoreServiceIface) NewListImageStoreObjectsParams(id string) *ListImageStoreObjectsParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewListImageStoreObjectsParams", id)
+	ret0, _ := ret[0].(*ListImageStoreObjectsParams)
+	return ret0
+}
+
+// NewListImageStoreObjectsParams indicates an expected call of NewListImageStoreObjectsParams.
+func (mr *MockImageStoreServiceIfaceMockRecorder) NewListImageStoreObjectsParams(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListImageStoreObjectsParams", reflect.TypeOf((*MockImageStoreServiceIface)(nil).NewListImageStoreObjectsParams), id)
+}
+
 // NewListImageStoresParams mocks base method.
 func (m *MockImageStoreServiceIface) NewListImageStoresParams() *ListImageStoresParams {
 	m.ctrl.T.Helper()
@@ -395,6 +474,20 @@ func (mr *MockImageStoreServiceIfaceMockRecorder) NewUpdateCloudToUseObjectStore
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewUpdateCloudToUseObjectStoreParams", reflect.TypeOf((*MockImageStoreServiceIface)(nil).NewUpdateCloudToUseObjectStoreParams), provider)
 }
 
+// NewUpdateImageStoreParams mocks base method.
+func (m *MockImageStoreServiceIface) NewUpdateImageStoreParams(id string, readonly bool) *UpdateImageStoreParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewUpdateImageStoreParams", id, readonly)
+	ret0, _ := ret[0].(*UpdateImageStoreParams)
+	return ret0
+}
+
+// NewUpdateImageStoreParams indicates an expected call of NewUpdateImageStoreParams.
+func (mr *MockImageStoreServiceIfaceMockRecorder) NewUpdateImageStoreParams(id, readonly interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewUpdateImageStoreParams", reflect.TypeOf((*MockImageStoreServiceIface)(nil).NewUpdateImageStoreParams), id, readonly)
+}
+
 // UpdateCloudToUseObjectStore mocks base method.
 func (m *MockImageStoreServiceIface) UpdateCloudToUseObjectStore(p *UpdateCloudToUseObjectStoreParams) (*UpdateCloudToUseObjectStoreResponse, error) {
 	m.ctrl.T.Helper()
@@ -409,3 +502,18 @@ func (mr *MockImageStoreServiceIfaceMockRecorder) UpdateCloudToUseObjectStore(p
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateCloudToUseObjectStore", reflect.TypeOf((*MockImageStoreServiceIface)(nil).UpdateCloudToUseObjectStore), p)
 }
+
+// UpdateImageStore mocks base method.
+func (m *MockImageStoreServiceIface) UpdateImageStore(p *UpdateImageStoreParams) (*UpdateImageStoreResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "UpdateImageStore", p)
+	ret0, _ := ret[0].(*UpdateImageStoreResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// UpdateImageStore indicates an expected call of UpdateImageStore.
+func (mr *MockImageStoreServiceIfaceMockRecorder) UpdateImageStore(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateImageStore", reflect.TypeOf((*MockImageStoreServiceIface)(nil).UpdateImageStore), p)
+}
diff --git a/cloudstack/ManagementService.go b/cloudstack/ManagementService.go
new file mode 100644
index 0000000..8398c8d
--- /dev/null
+++ b/cloudstack/ManagementService.go
@@ -0,0 +1,298 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 cloudstack
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"strconv"
+	"strings"
+)
+
+type ManagementServiceIface interface {
+	ListManagementServers(p *ListManagementServersParams) (*ListManagementServersResponse, error)
+	NewListManagementServersParams() *ListManagementServersParams
+	GetManagementServerID(name string, opts ...OptionFunc) (string, int, error)
+	GetManagementServerByName(name string, opts ...OptionFunc) (*ManagementServer, int, error)
+	GetManagementServerByID(id string, opts ...OptionFunc) (*ManagementServer, int, error)
+}
+
+type ListManagementServersParams struct {
+	p map[string]interface{}
+}
+
+func (p *ListManagementServersParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	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 *ListManagementServersParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *ListManagementServersParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *ListManagementServersParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+func (p *ListManagementServersParams) SetKeyword(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["keyword"] = v
+}
+
+func (p *ListManagementServersParams) ResetKeyword() {
+	if p.p != nil && p.p["keyword"] != nil {
+		delete(p.p, "keyword")
+	}
+}
+
+func (p *ListManagementServersParams) GetKeyword() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["keyword"].(string)
+	return value, ok
+}
+
+func (p *ListManagementServersParams) SetName(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["name"] = v
+}
+
+func (p *ListManagementServersParams) ResetName() {
+	if p.p != nil && p.p["name"] != nil {
+		delete(p.p, "name")
+	}
+}
+
+func (p *ListManagementServersParams) GetName() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["name"].(string)
+	return value, ok
+}
+
+func (p *ListManagementServersParams) SetPage(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["page"] = v
+}
+
+func (p *ListManagementServersParams) ResetPage() {
+	if p.p != nil && p.p["page"] != nil {
+		delete(p.p, "page")
+	}
+}
+
+func (p *ListManagementServersParams) GetPage() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["page"].(int)
+	return value, ok
+}
+
+func (p *ListManagementServersParams) SetPagesize(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["pagesize"] = v
+}
+
+func (p *ListManagementServersParams) ResetPagesize() {
+	if p.p != nil && p.p["pagesize"] != nil {
+		delete(p.p, "pagesize")
+	}
+}
+
+func (p *ListManagementServersParams) 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 ListManagementServersParams instance,
+// as then you are sure you have configured all required params
+func (s *ManagementService) NewListManagementServersParams() *ListManagementServersParams {
+	p := &ListManagementServersParams{}
+	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 *ManagementService) GetManagementServerID(name string, opts ...OptionFunc) (string, int, error) {
+	p := &ListManagementServersParams{}
+	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.ListManagementServers(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.ManagementServers[0].Id, l.Count, nil
+	}
+
+	if l.Count > 1 {
+		for _, v := range l.ManagementServers {
+			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)
+}
+
+// This is a courtesy helper function, which in some cases may not work as expected!
+func (s *ManagementService) GetManagementServerByName(name string, opts ...OptionFunc) (*ManagementServer, int, error) {
+	id, count, err := s.GetManagementServerID(name, opts...)
+	if err != nil {
+		return nil, count, err
+	}
+
+	r, count, err := s.GetManagementServerByID(id, opts...)
+	if err != nil {
+		return nil, count, err
+	}
+	return r, count, nil
+}
+
+// This is a courtesy helper function, which in some cases may not work as expected!
+func (s *ManagementService) GetManagementServerByID(id string, opts ...OptionFunc) (*ManagementServer, int, error) {
+	p := &ListManagementServersParams{}
+	p.p = make(map[string]interface{})
+
+	p.p["id"] = id
+
+	for _, fn := range append(s.cs.options, opts...) {
+		if err := fn(s.cs, p); err != nil {
+			return nil, -1, err
+		}
+	}
+
+	l, err := s.ListManagementServers(p)
+	if err != nil {
+		if strings.Contains(err.Error(), fmt.Sprintf(
+			"Invalid parameter id value=%s due to incorrect long value format, "+
+				"or entity does not exist", id)) {
+			return nil, 0, fmt.Errorf("No match found for %s: %+v", id, l)
+		}
+		return nil, -1, err
+	}
+
+	if l.Count == 0 {
+		return nil, l.Count, fmt.Errorf("No match found for %s: %+v", id, l)
+	}
+
+	if l.Count == 1 {
+		return l.ManagementServers[0], l.Count, nil
+	}
+	return nil, l.Count, fmt.Errorf("There is more then one result for ManagementServer UUID: %s!", id)
+}
+
+// Lists management servers.
+func (s *ManagementService) ListManagementServers(p *ListManagementServersParams) (*ListManagementServersResponse, error) {
+	resp, err := s.cs.newRequest("listManagementServers", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r ListManagementServersResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type ListManagementServersResponse struct {
+	Count             int                 `json:"count"`
+	ManagementServers []*ManagementServer `json:"managementserver"`
+}
+
+type ManagementServer struct {
+	Id               string `json:"id"`
+	Javadistribution string `json:"javadistribution"`
+	Javaversion      string `json:"javaversion"`
+	JobID            string `json:"jobid"`
+	Jobstatus        int    `json:"jobstatus"`
+	Kernelversion    string `json:"kernelversion"`
+	Lastboottime     string `json:"lastboottime"`
+	Lastserverstart  string `json:"lastserverstart"`
+	Lastserverstop   string `json:"lastserverstop"`
+	Name             string `json:"name"`
+	Osdistribution   string `json:"osdistribution"`
+	Serviceip        string `json:"serviceip"`
+	State            string `json:"state"`
+	Version          string `json:"version"`
+}
diff --git a/cloudstack/ManagementService_mock.go b/cloudstack/ManagementService_mock.go
new file mode 100644
index 0000000..2b1e31b
--- /dev/null
+++ b/cloudstack/ManagementService_mock.go
@@ -0,0 +1,145 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: ./cloudstack/ManagementService.go
+
+// Package cloudstack is a generated GoMock package.
+package cloudstack
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockManagementServiceIface is a mock of ManagementServiceIface interface.
+type MockManagementServiceIface struct {
+	ctrl     *gomock.Controller
+	recorder *MockManagementServiceIfaceMockRecorder
+}
+
+// MockManagementServiceIfaceMockRecorder is the mock recorder for MockManagementServiceIface.
+type MockManagementServiceIfaceMockRecorder struct {
+	mock *MockManagementServiceIface
+}
+
+// NewMockManagementServiceIface creates a new mock instance.
+func NewMockManagementServiceIface(ctrl *gomock.Controller) *MockManagementServiceIface {
+	mock := &MockManagementServiceIface{ctrl: ctrl}
+	mock.recorder = &MockManagementServiceIfaceMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockManagementServiceIface) EXPECT() *MockManagementServiceIfaceMockRecorder {
+	return m.recorder
+}
+
+// GetManagementServerByID mocks base method.
+func (m *MockManagementServiceIface) GetManagementServerByID(id string, opts ...OptionFunc) (*ManagementServer, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{id}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetManagementServerByID", varargs...)
+	ret0, _ := ret[0].(*ManagementServer)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetManagementServerByID indicates an expected call of GetManagementServerByID.
+func (mr *MockManagementServiceIfaceMockRecorder) GetManagementServerByID(id interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{id}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetManagementServerByID", reflect.TypeOf((*MockManagementServiceIface)(nil).GetManagementServerByID), varargs...)
+}
+
+// GetManagementServerByName mocks base method.
+func (m *MockManagementServiceIface) GetManagementServerByName(name string, opts ...OptionFunc) (*ManagementServer, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{name}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetManagementServerByName", varargs...)
+	ret0, _ := ret[0].(*ManagementServer)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetManagementServerByName indicates an expected call of GetManagementServerByName.
+func (mr *MockManagementServiceIfaceMockRecorder) GetManagementServerByName(name interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{name}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetManagementServerByName", reflect.TypeOf((*MockManagementServiceIface)(nil).GetManagementServerByName), varargs...)
+}
+
+// GetManagementServerID mocks base method.
+func (m *MockManagementServiceIface) GetManagementServerID(name string, opts ...OptionFunc) (string, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{name}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetManagementServerID", varargs...)
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetManagementServerID indicates an expected call of GetManagementServerID.
+func (mr *MockManagementServiceIfaceMockRecorder) GetManagementServerID(name interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{name}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetManagementServerID", reflect.TypeOf((*MockManagementServiceIface)(nil).GetManagementServerID), varargs...)
+}
+
+// ListManagementServers mocks base method.
+func (m *MockManagementServiceIface) ListManagementServers(p *ListManagementServersParams) (*ListManagementServersResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ListManagementServers", p)
+	ret0, _ := ret[0].(*ListManagementServersResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListManagementServers indicates an expected call of ListManagementServers.
+func (mr *MockManagementServiceIfaceMockRecorder) ListManagementServers(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListManagementServers", reflect.TypeOf((*MockManagementServiceIface)(nil).ListManagementServers), p)
+}
+
+// NewListManagementServersParams mocks base method.
+func (m *MockManagementServiceIface) NewListManagementServersParams() *ListManagementServersParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewListManagementServersParams")
+	ret0, _ := ret[0].(*ListManagementServersParams)
+	return ret0
+}
+
+// NewListManagementServersParams indicates an expected call of NewListManagementServersParams.
+func (mr *MockManagementServiceIfaceMockRecorder) NewListManagementServersParams() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListManagementServersParams", reflect.TypeOf((*MockManagementServiceIface)(nil).NewListManagementServersParams))
+}
diff --git a/cloudstack/MetricsService.go b/cloudstack/MetricsService.go
new file mode 100644
index 0000000..77c2047
--- /dev/null
+++ b/cloudstack/MetricsService.go
@@ -0,0 +1,88 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 cloudstack
+
+import (
+	"encoding/json"
+	"net/url"
+)
+
+type MetricsServiceIface interface {
+	ListInfrastructure(p *ListInfrastructureParams) (*ListInfrastructureResponse, error)
+	NewListInfrastructureParams() *ListInfrastructureParams
+}
+
+type ListInfrastructureParams struct {
+	p map[string]interface{}
+}
+
+func (p *ListInfrastructureParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	return u
+}
+
+// You should always use this function to get a new ListInfrastructureParams instance,
+// as then you are sure you have configured all required params
+func (s *MetricsService) NewListInfrastructureParams() *ListInfrastructureParams {
+	p := &ListInfrastructureParams{}
+	p.p = make(map[string]interface{})
+	return p
+}
+
+// Lists infrastructure
+func (s *MetricsService) ListInfrastructure(p *ListInfrastructureParams) (*ListInfrastructureResponse, error) {
+	resp, err := s.cs.newRequest("listInfrastructure", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r ListInfrastructureResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type ListInfrastructureResponse struct {
+	Count          int             `json:"count"`
+	Infrastructure *Infrastructure `json:"infrastructure"`
+}
+
+type Infrastructure struct {
+	Alerts            int    `json:"alerts"`
+	Clusters          int    `json:"clusters"`
+	Cpusockets        int    `json:"cpusockets"`
+	Hosts             int    `json:"hosts"`
+	Ilbvms            int    `json:"ilbvms"`
+	Imagestores       int    `json:"imagestores"`
+	JobID             string `json:"jobid"`
+	Jobstatus         int    `json:"jobstatus"`
+	Managementservers int    `json:"managementservers"`
+	Objectstores      int    `json:"objectstores"`
+	Pods              int    `json:"pods"`
+	Routers           int    `json:"routers"`
+	Storagepools      int    `json:"storagepools"`
+	Systemvms         int    `json:"systemvms"`
+	Zones             int    `json:"zones"`
+}
diff --git a/cloudstack/MetricsService_mock.go b/cloudstack/MetricsService_mock.go
new file mode 100644
index 0000000..f3a0fdd
--- /dev/null
+++ b/cloudstack/MetricsService_mock.go
@@ -0,0 +1,82 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: ./cloudstack/MetricsService.go
+
+// Package cloudstack is a generated GoMock package.
+package cloudstack
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockMetricsServiceIface is a mock of MetricsServiceIface interface.
+type MockMetricsServiceIface struct {
+	ctrl     *gomock.Controller
+	recorder *MockMetricsServiceIfaceMockRecorder
+}
+
+// MockMetricsServiceIfaceMockRecorder is the mock recorder for MockMetricsServiceIface.
+type MockMetricsServiceIfaceMockRecorder struct {
+	mock *MockMetricsServiceIface
+}
+
+// NewMockMetricsServiceIface creates a new mock instance.
+func NewMockMetricsServiceIface(ctrl *gomock.Controller) *MockMetricsServiceIface {
+	mock := &MockMetricsServiceIface{ctrl: ctrl}
+	mock.recorder = &MockMetricsServiceIfaceMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockMetricsServiceIface) EXPECT() *MockMetricsServiceIfaceMockRecorder {
+	return m.recorder
+}
+
+// ListInfrastructure mocks base method.
+func (m *MockMetricsServiceIface) ListInfrastructure(p *ListInfrastructureParams) (*ListInfrastructureResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ListInfrastructure", p)
+	ret0, _ := ret[0].(*ListInfrastructureResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListInfrastructure indicates an expected call of ListInfrastructure.
+func (mr *MockMetricsServiceIfaceMockRecorder) ListInfrastructure(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListInfrastructure", reflect.TypeOf((*MockMetricsServiceIface)(nil).ListInfrastructure), p)
+}
+
+// NewListInfrastructureParams mocks base method.
+func (m *MockMetricsServiceIface) NewListInfrastructureParams() *ListInfrastructureParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewListInfrastructureParams")
+	ret0, _ := ret[0].(*ListInfrastructureParams)
+	return ret0
+}
+
+// NewListInfrastructureParams indicates an expected call of NewListInfrastructureParams.
+func (mr *MockMetricsServiceIfaceMockRecorder) NewListInfrastructureParams() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListInfrastructureParams", reflect.TypeOf((*MockMetricsServiceIface)(nil).NewListInfrastructureParams))
+}
diff --git a/cloudstack/NetworkService.go b/cloudstack/NetworkService.go
index 847ecfe..eb8f37d 100644
--- a/cloudstack/NetworkService.go
+++ b/cloudstack/NetworkService.go
@@ -399,7 +399,7 @@ func (s *NetworkService) NewAddOpenDaylightControllerParams(password string, phy
 	return p
 }
 
-// Adds an OpenDyalight controler
+// Adds an OpenDaylight controller
 func (s *NetworkService) AddOpenDaylightController(p *AddOpenDaylightControllerParams) (*AddOpenDaylightControllerResponse, error) {
 	resp, err := s.cs.newRequest("addOpenDaylightController", p.toURLValues())
 	if err != nil {
@@ -2697,7 +2697,7 @@ func (s *NetworkService) NewDeleteOpenDaylightControllerParams(id string) *Delet
 	return p
 }
 
-// Removes an OpenDyalight controler
+// Removes an OpenDaylight controller
 func (s *NetworkService) DeleteOpenDaylightController(p *DeleteOpenDaylightControllerParams) (*DeleteOpenDaylightControllerResponse, error) {
 	resp, err := s.cs.newRequest("deleteOpenDaylightController", p.toURLValues())
 	if err != nil {
@@ -4843,7 +4843,7 @@ func (s *NetworkService) GetOpenDaylightControllerByID(id string, opts ...Option
 	return nil, l.Count, fmt.Errorf("There is more then one result for OpenDaylightController UUID: %s!", id)
 }
 
-// Lists OpenDyalight controllers
+// Lists OpenDaylight controllers
 func (s *NetworkService) ListOpenDaylightControllers(p *ListOpenDaylightControllersParams) (*ListOpenDaylightControllersResponse, error) {
 	resp, err := s.cs.newRequest("listOpenDaylightControllers", p.toURLValues())
 	if err != nil {
diff --git a/cloudstack/OauthService.go b/cloudstack/OauthService.go
new file mode 100644
index 0000000..2918ae7
--- /dev/null
+++ b/cloudstack/OauthService.go
@@ -0,0 +1,589 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 cloudstack
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"strconv"
+	"strings"
+)
+
+type OauthServiceIface interface {
+	ListOauthProvider(p *ListOauthProviderParams) (*ListOauthProviderResponse, error)
+	NewListOauthProviderParams() *ListOauthProviderParams
+	GetOauthProviderID(keyword string, opts ...OptionFunc) (string, int, error)
+	GetOauthProviderByName(name string, opts ...OptionFunc) (*OauthProvider, int, error)
+	GetOauthProviderByID(id string, opts ...OptionFunc) (*OauthProvider, int, error)
+	UpdateOauthProvider(p *UpdateOauthProviderParams) (*UpdateOauthProviderResponse, error)
+	NewUpdateOauthProviderParams(id string) *UpdateOauthProviderParams
+	DeleteOauthProvider(p *DeleteOauthProviderParams) (*DeleteOauthProviderResponse, error)
+	NewDeleteOauthProviderParams(id string) *DeleteOauthProviderParams
+}
+
+type ListOauthProviderParams struct {
+	p map[string]interface{}
+}
+
+func (p *ListOauthProviderParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	if v, found := p.p["keyword"]; found {
+		u.Set("keyword", 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)
+	}
+	if v, found := p.p["provider"]; found {
+		u.Set("provider", v.(string))
+	}
+	return u
+}
+
+func (p *ListOauthProviderParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *ListOauthProviderParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *ListOauthProviderParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+func (p *ListOauthProviderParams) SetKeyword(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["keyword"] = v
+}
+
+func (p *ListOauthProviderParams) ResetKeyword() {
+	if p.p != nil && p.p["keyword"] != nil {
+		delete(p.p, "keyword")
+	}
+}
+
+func (p *ListOauthProviderParams) GetKeyword() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["keyword"].(string)
+	return value, ok
+}
+
+func (p *ListOauthProviderParams) SetPage(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["page"] = v
+}
+
+func (p *ListOauthProviderParams) ResetPage() {
+	if p.p != nil && p.p["page"] != nil {
+		delete(p.p, "page")
+	}
+}
+
+func (p *ListOauthProviderParams) GetPage() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["page"].(int)
+	return value, ok
+}
+
+func (p *ListOauthProviderParams) SetPagesize(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["pagesize"] = v
+}
+
+func (p *ListOauthProviderParams) ResetPagesize() {
+	if p.p != nil && p.p["pagesize"] != nil {
+		delete(p.p, "pagesize")
+	}
+}
+
+func (p *ListOauthProviderParams) GetPagesize() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["pagesize"].(int)
+	return value, ok
+}
+
+func (p *ListOauthProviderParams) SetProvider(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["provider"] = v
+}
+
+func (p *ListOauthProviderParams) ResetProvider() {
+	if p.p != nil && p.p["provider"] != nil {
+		delete(p.p, "provider")
+	}
+}
+
+func (p *ListOauthProviderParams) GetProvider() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["provider"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new ListOauthProviderParams instance,
+// as then you are sure you have configured all required params
+func (s *OauthService) NewListOauthProviderParams() *ListOauthProviderParams {
+	p := &ListOauthProviderParams{}
+	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 *OauthService) GetOauthProviderID(keyword string, opts ...OptionFunc) (string, int, error) {
+	p := &ListOauthProviderParams{}
+	p.p = make(map[string]interface{})
+
+	p.p["keyword"] = keyword
+
+	for _, fn := range append(s.cs.options, opts...) {
+		if err := fn(s.cs, p); err != nil {
+			return "", -1, err
+		}
+	}
+
+	l, err := s.ListOauthProvider(p)
+	if err != nil {
+		return "", -1, err
+	}
+
+	if l.Count == 0 {
+		return "", l.Count, fmt.Errorf("No match found for %s: %+v", keyword, l)
+	}
+
+	if l.Count == 1 {
+		return l.OauthProvider[0].Id, l.Count, nil
+	}
+
+	if l.Count > 1 {
+		for _, v := range l.OauthProvider {
+			if v.Name == keyword {
+				return v.Id, l.Count, nil
+			}
+		}
+	}
+	return "", l.Count, fmt.Errorf("Could not find an exact match for %s: %+v", keyword, l)
+}
+
+// This is a courtesy helper function, which in some cases may not work as expected!
+func (s *OauthService) GetOauthProviderByName(name string, opts ...OptionFunc) (*OauthProvider, int, error) {
+	id, count, err := s.GetOauthProviderID(name, opts...)
+	if err != nil {
+		return nil, count, err
+	}
+
+	r, count, err := s.GetOauthProviderByID(id, opts...)
+	if err != nil {
+		return nil, count, err
+	}
+	return r, count, nil
+}
+
+// This is a courtesy helper function, which in some cases may not work as expected!
+func (s *OauthService) GetOauthProviderByID(id string, opts ...OptionFunc) (*OauthProvider, int, error) {
+	p := &ListOauthProviderParams{}
+	p.p = make(map[string]interface{})
+
+	p.p["id"] = id
+
+	for _, fn := range append(s.cs.options, opts...) {
+		if err := fn(s.cs, p); err != nil {
+			return nil, -1, err
+		}
+	}
+
+	l, err := s.ListOauthProvider(p)
+	if err != nil {
+		if strings.Contains(err.Error(), fmt.Sprintf(
+			"Invalid parameter id value=%s due to incorrect long value format, "+
+				"or entity does not exist", id)) {
+			return nil, 0, fmt.Errorf("No match found for %s: %+v", id, l)
+		}
+		return nil, -1, err
+	}
+
+	if l.Count == 0 {
+		return nil, l.Count, fmt.Errorf("No match found for %s: %+v", id, l)
+	}
+
+	if l.Count == 1 {
+		return l.OauthProvider[0], l.Count, nil
+	}
+	return nil, l.Count, fmt.Errorf("There is more then one result for OauthProvider UUID: %s!", id)
+}
+
+// List OAuth providers registered
+func (s *OauthService) ListOauthProvider(p *ListOauthProviderParams) (*ListOauthProviderResponse, error) {
+	resp, err := s.cs.newRequest("listOauthProvider", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r ListOauthProviderResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type ListOauthProviderResponse struct {
+	Count         int              `json:"count"`
+	OauthProvider []*OauthProvider `json:"oauthprovider"`
+}
+
+type OauthProvider struct {
+	Clientid    string `json:"clientid"`
+	Description string `json:"description"`
+	Enabled     bool   `json:"enabled"`
+	Id          string `json:"id"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Name        string `json:"name"`
+	Provider    string `json:"provider"`
+	Redirecturi string `json:"redirecturi"`
+	Secretkey   string `json:"secretkey"`
+}
+
+type UpdateOauthProviderParams struct {
+	p map[string]interface{}
+}
+
+func (p *UpdateOauthProviderParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["clientid"]; found {
+		u.Set("clientid", v.(string))
+	}
+	if v, found := p.p["description"]; found {
+		u.Set("description", v.(string))
+	}
+	if v, found := p.p["enabled"]; found {
+		vv := strconv.FormatBool(v.(bool))
+		u.Set("enabled", vv)
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	if v, found := p.p["redirecturi"]; found {
+		u.Set("redirecturi", v.(string))
+	}
+	if v, found := p.p["secretkey"]; found {
+		u.Set("secretkey", v.(string))
+	}
+	return u
+}
+
+func (p *UpdateOauthProviderParams) SetClientid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["clientid"] = v
+}
+
+func (p *UpdateOauthProviderParams) ResetClientid() {
+	if p.p != nil && p.p["clientid"] != nil {
+		delete(p.p, "clientid")
+	}
+}
+
+func (p *UpdateOauthProviderParams) GetClientid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["clientid"].(string)
+	return value, ok
+}
+
+func (p *UpdateOauthProviderParams) SetDescription(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["description"] = v
+}
+
+func (p *UpdateOauthProviderParams) ResetDescription() {
+	if p.p != nil && p.p["description"] != nil {
+		delete(p.p, "description")
+	}
+}
+
+func (p *UpdateOauthProviderParams) GetDescription() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["description"].(string)
+	return value, ok
+}
+
+func (p *UpdateOauthProviderParams) SetEnabled(v bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["enabled"] = v
+}
+
+func (p *UpdateOauthProviderParams) ResetEnabled() {
+	if p.p != nil && p.p["enabled"] != nil {
+		delete(p.p, "enabled")
+	}
+}
+
+func (p *UpdateOauthProviderParams) GetEnabled() (bool, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["enabled"].(bool)
+	return value, ok
+}
+
+func (p *UpdateOauthProviderParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *UpdateOauthProviderParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *UpdateOauthProviderParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+func (p *UpdateOauthProviderParams) SetRedirecturi(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["redirecturi"] = v
+}
+
+func (p *UpdateOauthProviderParams) ResetRedirecturi() {
+	if p.p != nil && p.p["redirecturi"] != nil {
+		delete(p.p, "redirecturi")
+	}
+}
+
+func (p *UpdateOauthProviderParams) GetRedirecturi() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["redirecturi"].(string)
+	return value, ok
+}
+
+func (p *UpdateOauthProviderParams) SetSecretkey(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["secretkey"] = v
+}
+
+func (p *UpdateOauthProviderParams) ResetSecretkey() {
+	if p.p != nil && p.p["secretkey"] != nil {
+		delete(p.p, "secretkey")
+	}
+}
+
+func (p *UpdateOauthProviderParams) GetSecretkey() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["secretkey"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new UpdateOauthProviderParams instance,
+// as then you are sure you have configured all required params
+func (s *OauthService) NewUpdateOauthProviderParams(id string) *UpdateOauthProviderParams {
+	p := &UpdateOauthProviderParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	return p
+}
+
+// Updates the registered OAuth provider details
+func (s *OauthService) UpdateOauthProvider(p *UpdateOauthProviderParams) (*UpdateOauthProviderResponse, error) {
+	resp, err := s.cs.newRequest("updateOauthProvider", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var nested struct {
+		Response UpdateOauthProviderResponse `json:"oauthprovider"`
+	}
+	if err := json.Unmarshal(resp, &nested); err != nil {
+		return nil, err
+	}
+	r := nested.Response
+
+	return &r, nil
+}
+
+type UpdateOauthProviderResponse struct {
+	Clientid    string `json:"clientid"`
+	Description string `json:"description"`
+	Enabled     bool   `json:"enabled"`
+	Id          string `json:"id"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Name        string `json:"name"`
+	Provider    string `json:"provider"`
+	Redirecturi string `json:"redirecturi"`
+	Secretkey   string `json:"secretkey"`
+}
+
+type DeleteOauthProviderParams struct {
+	p map[string]interface{}
+}
+
+func (p *DeleteOauthProviderParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	return u
+}
+
+func (p *DeleteOauthProviderParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *DeleteOauthProviderParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *DeleteOauthProviderParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new DeleteOauthProviderParams instance,
+// as then you are sure you have configured all required params
+func (s *OauthService) NewDeleteOauthProviderParams(id string) *DeleteOauthProviderParams {
+	p := &DeleteOauthProviderParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	return p
+}
+
+// Deletes the registered OAuth provider
+func (s *OauthService) DeleteOauthProvider(p *DeleteOauthProviderParams) (*DeleteOauthProviderResponse, error) {
+	resp, err := s.cs.newRequest("deleteOauthProvider", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r DeleteOauthProviderResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type DeleteOauthProviderResponse struct {
+	Displaytext string `json:"displaytext"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Success     bool   `json:"success"`
+}
+
+func (r *DeleteOauthProviderResponse) UnmarshalJSON(b []byte) error {
+	var m map[string]interface{}
+	err := json.Unmarshal(b, &m)
+	if err != nil {
+		return err
+	}
+
+	if success, ok := m["success"].(string); ok {
+		m["success"] = success == "true"
+		b, err = json.Marshal(m)
+		if err != nil {
+			return err
+		}
+	}
+
+	if ostypeid, ok := m["ostypeid"].(float64); ok {
+		m["ostypeid"] = strconv.Itoa(int(ostypeid))
+		b, err = json.Marshal(m)
+		if err != nil {
+			return err
+		}
+	}
+
+	type alias DeleteOauthProviderResponse
+	return json.Unmarshal(b, (*alias)(r))
+}
diff --git a/cloudstack/OauthService_mock.go b/cloudstack/OauthService_mock.go
new file mode 100644
index 0000000..9accbcb
--- /dev/null
+++ b/cloudstack/OauthService_mock.go
@@ -0,0 +1,203 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: ./cloudstack/OauthService.go
+
+// Package cloudstack is a generated GoMock package.
+package cloudstack
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockOauthServiceIface is a mock of OauthServiceIface interface.
+type MockOauthServiceIface struct {
+	ctrl     *gomock.Controller
+	recorder *MockOauthServiceIfaceMockRecorder
+}
+
+// MockOauthServiceIfaceMockRecorder is the mock recorder for MockOauthServiceIface.
+type MockOauthServiceIfaceMockRecorder struct {
+	mock *MockOauthServiceIface
+}
+
+// NewMockOauthServiceIface creates a new mock instance.
+func NewMockOauthServiceIface(ctrl *gomock.Controller) *MockOauthServiceIface {
+	mock := &MockOauthServiceIface{ctrl: ctrl}
+	mock.recorder = &MockOauthServiceIfaceMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockOauthServiceIface) EXPECT() *MockOauthServiceIfaceMockRecorder {
+	return m.recorder
+}
+
+// DeleteOauthProvider mocks base method.
+func (m *MockOauthServiceIface) DeleteOauthProvider(p *DeleteOauthProviderParams) (*DeleteOauthProviderResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DeleteOauthProvider", p)
+	ret0, _ := ret[0].(*DeleteOauthProviderResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// DeleteOauthProvider indicates an expected call of DeleteOauthProvider.
+func (mr *MockOauthServiceIfaceMockRecorder) DeleteOauthProvider(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOauthProvider", reflect.TypeOf((*MockOauthServiceIface)(nil).DeleteOauthProvider), p)
+}
+
+// GetOauthProviderByID mocks base method.
+func (m *MockOauthServiceIface) GetOauthProviderByID(id string, opts ...OptionFunc) (*OauthProvider, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{id}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetOauthProviderByID", varargs...)
+	ret0, _ := ret[0].(*OauthProvider)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetOauthProviderByID indicates an expected call of GetOauthProviderByID.
+func (mr *MockOauthServiceIfaceMockRecorder) GetOauthProviderByID(id interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{id}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOauthProviderByID", reflect.TypeOf((*MockOauthServiceIface)(nil).GetOauthProviderByID), varargs...)
+}
+
+// GetOauthProviderByName mocks base method.
+func (m *MockOauthServiceIface) GetOauthProviderByName(name string, opts ...OptionFunc) (*OauthProvider, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{name}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetOauthProviderByName", varargs...)
+	ret0, _ := ret[0].(*OauthProvider)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetOauthProviderByName indicates an expected call of GetOauthProviderByName.
+func (mr *MockOauthServiceIfaceMockRecorder) GetOauthProviderByName(name interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{name}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOauthProviderByName", reflect.TypeOf((*MockOauthServiceIface)(nil).GetOauthProviderByName), varargs...)
+}
+
+// GetOauthProviderID mocks base method.
+func (m *MockOauthServiceIface) GetOauthProviderID(keyword string, opts ...OptionFunc) (string, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{keyword}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetOauthProviderID", varargs...)
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetOauthProviderID indicates an expected call of GetOauthProviderID.
+func (mr *MockOauthServiceIfaceMockRecorder) GetOauthProviderID(keyword interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{keyword}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOauthProviderID", reflect.TypeOf((*MockOauthServiceIface)(nil).GetOauthProviderID), varargs...)
+}
+
+// ListOauthProvider mocks base method.
+func (m *MockOauthServiceIface) ListOauthProvider(p *ListOauthProviderParams) (*ListOauthProviderResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ListOauthProvider", p)
+	ret0, _ := ret[0].(*ListOauthProviderResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListOauthProvider indicates an expected call of ListOauthProvider.
+func (mr *MockOauthServiceIfaceMockRecorder) ListOauthProvider(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListOauthProvider", reflect.TypeOf((*MockOauthServiceIface)(nil).ListOauthProvider), p)
+}
+
+// NewDeleteOauthProviderParams mocks base method.
+func (m *MockOauthServiceIface) NewDeleteOauthProviderParams(id string) *DeleteOauthProviderParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewDeleteOauthProviderParams", id)
+	ret0, _ := ret[0].(*DeleteOauthProviderParams)
+	return ret0
+}
+
+// NewDeleteOauthProviderParams indicates an expected call of NewDeleteOauthProviderParams.
+func (mr *MockOauthServiceIfaceMockRecorder) NewDeleteOauthProviderParams(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewDeleteOauthProviderParams", reflect.TypeOf((*MockOauthServiceIface)(nil).NewDeleteOauthProviderParams), id)
+}
+
+// NewListOauthProviderParams mocks base method.
+func (m *MockOauthServiceIface) NewListOauthProviderParams() *ListOauthProviderParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewListOauthProviderParams")
+	ret0, _ := ret[0].(*ListOauthProviderParams)
+	return ret0
+}
+
+// NewListOauthProviderParams indicates an expected call of NewListOauthProviderParams.
+func (mr *MockOauthServiceIfaceMockRecorder) NewListOauthProviderParams() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListOauthProviderParams", reflect.TypeOf((*MockOauthServiceIface)(nil).NewListOauthProviderParams))
+}
+
+// NewUpdateOauthProviderParams mocks base method.
+func (m *MockOauthServiceIface) NewUpdateOauthProviderParams(id string) *UpdateOauthProviderParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewUpdateOauthProviderParams", id)
+	ret0, _ := ret[0].(*UpdateOauthProviderParams)
+	return ret0
+}
+
+// NewUpdateOauthProviderParams indicates an expected call of NewUpdateOauthProviderParams.
+func (mr *MockOauthServiceIfaceMockRecorder) NewUpdateOauthProviderParams(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewUpdateOauthProviderParams", reflect.TypeOf((*MockOauthServiceIface)(nil).NewUpdateOauthProviderParams), id)
+}
+
+// UpdateOauthProvider mocks base method.
+func (m *MockOauthServiceIface) UpdateOauthProvider(p *UpdateOauthProviderParams) (*UpdateOauthProviderResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "UpdateOauthProvider", p)
+	ret0, _ := ret[0].(*UpdateOauthProviderResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// UpdateOauthProvider indicates an expected call of UpdateOauthProvider.
+func (mr *MockOauthServiceIfaceMockRecorder) UpdateOauthProvider(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateOauthProvider", reflect.TypeOf((*MockOauthServiceIface)(nil).UpdateOauthProvider), p)
+}
diff --git a/cloudstack/ObjectStoreService.go b/cloudstack/ObjectStoreService.go
new file mode 100644
index 0000000..57f633a
--- /dev/null
+++ b/cloudstack/ObjectStoreService.go
@@ -0,0 +1,1130 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 cloudstack
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"strconv"
+	"strings"
+)
+
+type ObjectStoreServiceIface interface {
+	CreateBucket(p *CreateBucketParams) (*CreateBucketResponse, error)
+	NewCreateBucketParams(name string, objectstorageid string) *CreateBucketParams
+	DeleteBucket(p *DeleteBucketParams) (*DeleteBucketResponse, error)
+	NewDeleteBucketParams(id string) *DeleteBucketParams
+	UpdateBucket(p *UpdateBucketParams) (*UpdateBucketResponse, error)
+	NewUpdateBucketParams(id string) *UpdateBucketParams
+	ListBuckets(p *ListBucketsParams) (*ListBucketsResponse, error)
+	NewListBucketsParams() *ListBucketsParams
+	GetBucketID(name string, opts ...OptionFunc) (string, int, error)
+	GetBucketByName(name string, opts ...OptionFunc) (*Bucket, int, error)
+	GetBucketByID(id string, opts ...OptionFunc) (*Bucket, int, error)
+}
+
+type CreateBucketParams struct {
+	p map[string]interface{}
+}
+
+func (p *CreateBucketParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["account"]; found {
+		u.Set("account", v.(string))
+	}
+	if v, found := p.p["domainid"]; found {
+		u.Set("domainid", v.(string))
+	}
+	if v, found := p.p["encryption"]; found {
+		vv := strconv.FormatBool(v.(bool))
+		u.Set("encryption", vv)
+	}
+	if v, found := p.p["name"]; found {
+		u.Set("name", v.(string))
+	}
+	if v, found := p.p["objectlocking"]; found {
+		vv := strconv.FormatBool(v.(bool))
+		u.Set("objectlocking", vv)
+	}
+	if v, found := p.p["objectstorageid"]; found {
+		u.Set("objectstorageid", v.(string))
+	}
+	if v, found := p.p["policy"]; found {
+		u.Set("policy", v.(string))
+	}
+	if v, found := p.p["projectid"]; found {
+		u.Set("projectid", v.(string))
+	}
+	if v, found := p.p["quota"]; found {
+		vv := strconv.Itoa(v.(int))
+		u.Set("quota", vv)
+	}
+	if v, found := p.p["versioning"]; found {
+		vv := strconv.FormatBool(v.(bool))
+		u.Set("versioning", vv)
+	}
+	return u
+}
+
+func (p *CreateBucketParams) SetAccount(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["account"] = v
+}
+
+func (p *CreateBucketParams) ResetAccount() {
+	if p.p != nil && p.p["account"] != nil {
+		delete(p.p, "account")
+	}
+}
+
+func (p *CreateBucketParams) GetAccount() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["account"].(string)
+	return value, ok
+}
+
+func (p *CreateBucketParams) SetDomainid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["domainid"] = v
+}
+
+func (p *CreateBucketParams) ResetDomainid() {
+	if p.p != nil && p.p["domainid"] != nil {
+		delete(p.p, "domainid")
+	}
+}
+
+func (p *CreateBucketParams) GetDomainid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["domainid"].(string)
+	return value, ok
+}
+
+func (p *CreateBucketParams) SetEncryption(v bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["encryption"] = v
+}
+
+func (p *CreateBucketParams) ResetEncryption() {
+	if p.p != nil && p.p["encryption"] != nil {
+		delete(p.p, "encryption")
+	}
+}
+
+func (p *CreateBucketParams) GetEncryption() (bool, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["encryption"].(bool)
+	return value, ok
+}
+
+func (p *CreateBucketParams) SetName(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["name"] = v
+}
+
+func (p *CreateBucketParams) ResetName() {
+	if p.p != nil && p.p["name"] != nil {
+		delete(p.p, "name")
+	}
+}
+
+func (p *CreateBucketParams) GetName() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["name"].(string)
+	return value, ok
+}
+
+func (p *CreateBucketParams) SetObjectlocking(v bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["objectlocking"] = v
+}
+
+func (p *CreateBucketParams) ResetObjectlocking() {
+	if p.p != nil && p.p["objectlocking"] != nil {
+		delete(p.p, "objectlocking")
+	}
+}
+
+func (p *CreateBucketParams) GetObjectlocking() (bool, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["objectlocking"].(bool)
+	return value, ok
+}
+
+func (p *CreateBucketParams) SetObjectstorageid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["objectstorageid"] = v
+}
+
+func (p *CreateBucketParams) ResetObjectstorageid() {
+	if p.p != nil && p.p["objectstorageid"] != nil {
+		delete(p.p, "objectstorageid")
+	}
+}
+
+func (p *CreateBucketParams) GetObjectstorageid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["objectstorageid"].(string)
+	return value, ok
+}
+
+func (p *CreateBucketParams) SetPolicy(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["policy"] = v
+}
+
+func (p *CreateBucketParams) ResetPolicy() {
+	if p.p != nil && p.p["policy"] != nil {
+		delete(p.p, "policy")
+	}
+}
+
+func (p *CreateBucketParams) GetPolicy() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["policy"].(string)
+	return value, ok
+}
+
+func (p *CreateBucketParams) SetProjectid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["projectid"] = v
+}
+
+func (p *CreateBucketParams) ResetProjectid() {
+	if p.p != nil && p.p["projectid"] != nil {
+		delete(p.p, "projectid")
+	}
+}
+
+func (p *CreateBucketParams) GetProjectid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["projectid"].(string)
+	return value, ok
+}
+
+func (p *CreateBucketParams) SetQuota(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["quota"] = v
+}
+
+func (p *CreateBucketParams) ResetQuota() {
+	if p.p != nil && p.p["quota"] != nil {
+		delete(p.p, "quota")
+	}
+}
+
+func (p *CreateBucketParams) GetQuota() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["quota"].(int)
+	return value, ok
+}
+
+func (p *CreateBucketParams) SetVersioning(v bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["versioning"] = v
+}
+
+func (p *CreateBucketParams) ResetVersioning() {
+	if p.p != nil && p.p["versioning"] != nil {
+		delete(p.p, "versioning")
+	}
+}
+
+func (p *CreateBucketParams) GetVersioning() (bool, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["versioning"].(bool)
+	return value, ok
+}
+
+// You should always use this function to get a new CreateBucketParams instance,
+// as then you are sure you have configured all required params
+func (s *ObjectStoreService) NewCreateBucketParams(name string, objectstorageid string) *CreateBucketParams {
+	p := &CreateBucketParams{}
+	p.p = make(map[string]interface{})
+	p.p["name"] = name
+	p.p["objectstorageid"] = objectstorageid
+	return p
+}
+
+// Creates a bucket in the specified object storage pool.
+func (s *ObjectStoreService) CreateBucket(p *CreateBucketParams) (*CreateBucketResponse, error) {
+	resp, err := s.cs.newRequest("createBucket", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r CreateBucketResponse
+	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
+		}
+
+		b, err = getRawValue(b)
+		if err != nil {
+			return nil, err
+		}
+
+		if err := json.Unmarshal(b, &r); err != nil {
+			return nil, err
+		}
+	}
+
+	return &r, nil
+}
+
+type CreateBucketResponse struct {
+	Accesskey       string `json:"accesskey"`
+	Account         string `json:"account"`
+	Created         string `json:"created"`
+	Domain          string `json:"domain"`
+	Domainid        string `json:"domainid"`
+	Encryption      bool   `json:"encryption"`
+	Hasannotations  bool   `json:"hasannotations"`
+	Id              string `json:"id"`
+	JobID           string `json:"jobid"`
+	Jobstatus       int    `json:"jobstatus"`
+	Name            string `json:"name"`
+	Objectlocking   bool   `json:"objectlocking"`
+	Objectstorageid string `json:"objectstorageid"`
+	Objectstore     string `json:"objectstore"`
+	Policy          string `json:"policy"`
+	Project         string `json:"project"`
+	Projectid       string `json:"projectid"`
+	Provider        string `json:"provider"`
+	Quota           int    `json:"quota"`
+	Size            int64  `json:"size"`
+	State           string `json:"state"`
+	Tags            []Tags `json:"tags"`
+	Url             string `json:"url"`
+	Usersecretkey   string `json:"usersecretkey"`
+	Versioning      bool   `json:"versioning"`
+}
+
+type DeleteBucketParams struct {
+	p map[string]interface{}
+}
+
+func (p *DeleteBucketParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	return u
+}
+
+func (p *DeleteBucketParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *DeleteBucketParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *DeleteBucketParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new DeleteBucketParams instance,
+// as then you are sure you have configured all required params
+func (s *ObjectStoreService) NewDeleteBucketParams(id string) *DeleteBucketParams {
+	p := &DeleteBucketParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	return p
+}
+
+// Deletes an empty Bucket.
+func (s *ObjectStoreService) DeleteBucket(p *DeleteBucketParams) (*DeleteBucketResponse, error) {
+	resp, err := s.cs.newRequest("deleteBucket", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r DeleteBucketResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type DeleteBucketResponse struct {
+	Displaytext string `json:"displaytext"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Success     bool   `json:"success"`
+}
+
+func (r *DeleteBucketResponse) UnmarshalJSON(b []byte) error {
+	var m map[string]interface{}
+	err := json.Unmarshal(b, &m)
+	if err != nil {
+		return err
+	}
+
+	if success, ok := m["success"].(string); ok {
+		m["success"] = success == "true"
+		b, err = json.Marshal(m)
+		if err != nil {
+			return err
+		}
+	}
+
+	if ostypeid, ok := m["ostypeid"].(float64); ok {
+		m["ostypeid"] = strconv.Itoa(int(ostypeid))
+		b, err = json.Marshal(m)
+		if err != nil {
+			return err
+		}
+	}
+
+	type alias DeleteBucketResponse
+	return json.Unmarshal(b, (*alias)(r))
+}
+
+type UpdateBucketParams struct {
+	p map[string]interface{}
+}
+
+func (p *UpdateBucketParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["encryption"]; found {
+		vv := strconv.FormatBool(v.(bool))
+		u.Set("encryption", vv)
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	if v, found := p.p["policy"]; found {
+		u.Set("policy", v.(string))
+	}
+	if v, found := p.p["quota"]; found {
+		vv := strconv.Itoa(v.(int))
+		u.Set("quota", vv)
+	}
+	if v, found := p.p["versioning"]; found {
+		vv := strconv.FormatBool(v.(bool))
+		u.Set("versioning", vv)
+	}
+	return u
+}
+
+func (p *UpdateBucketParams) SetEncryption(v bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["encryption"] = v
+}
+
+func (p *UpdateBucketParams) ResetEncryption() {
+	if p.p != nil && p.p["encryption"] != nil {
+		delete(p.p, "encryption")
+	}
+}
+
+func (p *UpdateBucketParams) GetEncryption() (bool, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["encryption"].(bool)
+	return value, ok
+}
+
+func (p *UpdateBucketParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *UpdateBucketParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *UpdateBucketParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+func (p *UpdateBucketParams) SetPolicy(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["policy"] = v
+}
+
+func (p *UpdateBucketParams) ResetPolicy() {
+	if p.p != nil && p.p["policy"] != nil {
+		delete(p.p, "policy")
+	}
+}
+
+func (p *UpdateBucketParams) GetPolicy() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["policy"].(string)
+	return value, ok
+}
+
+func (p *UpdateBucketParams) SetQuota(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["quota"] = v
+}
+
+func (p *UpdateBucketParams) ResetQuota() {
+	if p.p != nil && p.p["quota"] != nil {
+		delete(p.p, "quota")
+	}
+}
+
+func (p *UpdateBucketParams) GetQuota() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["quota"].(int)
+	return value, ok
+}
+
+func (p *UpdateBucketParams) SetVersioning(v bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["versioning"] = v
+}
+
+func (p *UpdateBucketParams) ResetVersioning() {
+	if p.p != nil && p.p["versioning"] != nil {
+		delete(p.p, "versioning")
+	}
+}
+
+func (p *UpdateBucketParams) GetVersioning() (bool, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["versioning"].(bool)
+	return value, ok
+}
+
+// You should always use this function to get a new UpdateBucketParams instance,
+// as then you are sure you have configured all required params
+func (s *ObjectStoreService) NewUpdateBucketParams(id string) *UpdateBucketParams {
+	p := &UpdateBucketParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	return p
+}
+
+// Updates Bucket properties
+func (s *ObjectStoreService) UpdateBucket(p *UpdateBucketParams) (*UpdateBucketResponse, error) {
+	resp, err := s.cs.newRequest("updateBucket", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r UpdateBucketResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type UpdateBucketResponse struct {
+	Displaytext string `json:"displaytext"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Success     bool   `json:"success"`
+}
+
+func (r *UpdateBucketResponse) UnmarshalJSON(b []byte) error {
+	var m map[string]interface{}
+	err := json.Unmarshal(b, &m)
+	if err != nil {
+		return err
+	}
+
+	if success, ok := m["success"].(string); ok {
+		m["success"] = success == "true"
+		b, err = json.Marshal(m)
+		if err != nil {
+			return err
+		}
+	}
+
+	if ostypeid, ok := m["ostypeid"].(float64); ok {
+		m["ostypeid"] = strconv.Itoa(int(ostypeid))
+		b, err = json.Marshal(m)
+		if err != nil {
+			return err
+		}
+	}
+
+	type alias UpdateBucketResponse
+	return json.Unmarshal(b, (*alias)(r))
+}
+
+type ListBucketsParams struct {
+	p map[string]interface{}
+}
+
+func (p *ListBucketsParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["account"]; found {
+		u.Set("account", v.(string))
+	}
+	if v, found := p.p["domainid"]; found {
+		u.Set("domainid", v.(string))
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	if v, found := p.p["ids"]; found {
+		vv := strings.Join(v.([]string), ",")
+		u.Set("ids", vv)
+	}
+	if v, found := p.p["isrecursive"]; found {
+		vv := strconv.FormatBool(v.(bool))
+		u.Set("isrecursive", vv)
+	}
+	if v, found := p.p["keyword"]; found {
+		u.Set("keyword", v.(string))
+	}
+	if v, found := p.p["listall"]; found {
+		vv := strconv.FormatBool(v.(bool))
+		u.Set("listall", vv)
+	}
+	if v, found := p.p["name"]; found {
+		u.Set("name", v.(string))
+	}
+	if v, found := p.p["objectstorageid"]; found {
+		u.Set("objectstorageid", 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)
+	}
+	if v, found := p.p["projectid"]; found {
+		u.Set("projectid", v.(string))
+	}
+	if v, found := p.p["tags"]; found {
+		m := v.(map[string]string)
+		for i, k := range getSortedKeysFromMap(m) {
+			u.Set(fmt.Sprintf("tags[%d].key", i), k)
+			u.Set(fmt.Sprintf("tags[%d].value", i), m[k])
+		}
+	}
+	return u
+}
+
+func (p *ListBucketsParams) SetAccount(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["account"] = v
+}
+
+func (p *ListBucketsParams) ResetAccount() {
+	if p.p != nil && p.p["account"] != nil {
+		delete(p.p, "account")
+	}
+}
+
+func (p *ListBucketsParams) GetAccount() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["account"].(string)
+	return value, ok
+}
+
+func (p *ListBucketsParams) SetDomainid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["domainid"] = v
+}
+
+func (p *ListBucketsParams) ResetDomainid() {
+	if p.p != nil && p.p["domainid"] != nil {
+		delete(p.p, "domainid")
+	}
+}
+
+func (p *ListBucketsParams) GetDomainid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["domainid"].(string)
+	return value, ok
+}
+
+func (p *ListBucketsParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *ListBucketsParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *ListBucketsParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+func (p *ListBucketsParams) SetIds(v []string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["ids"] = v
+}
+
+func (p *ListBucketsParams) ResetIds() {
+	if p.p != nil && p.p["ids"] != nil {
+		delete(p.p, "ids")
+	}
+}
+
+func (p *ListBucketsParams) GetIds() ([]string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["ids"].([]string)
+	return value, ok
+}
+
+func (p *ListBucketsParams) SetIsrecursive(v bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["isrecursive"] = v
+}
+
+func (p *ListBucketsParams) ResetIsrecursive() {
+	if p.p != nil && p.p["isrecursive"] != nil {
+		delete(p.p, "isrecursive")
+	}
+}
+
+func (p *ListBucketsParams) GetIsrecursive() (bool, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["isrecursive"].(bool)
+	return value, ok
+}
+
+func (p *ListBucketsParams) SetKeyword(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["keyword"] = v
+}
+
+func (p *ListBucketsParams) ResetKeyword() {
+	if p.p != nil && p.p["keyword"] != nil {
+		delete(p.p, "keyword")
+	}
+}
+
+func (p *ListBucketsParams) GetKeyword() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["keyword"].(string)
+	return value, ok
+}
+
+func (p *ListBucketsParams) SetListall(v bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["listall"] = v
+}
+
+func (p *ListBucketsParams) ResetListall() {
+	if p.p != nil && p.p["listall"] != nil {
+		delete(p.p, "listall")
+	}
+}
+
+func (p *ListBucketsParams) GetListall() (bool, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["listall"].(bool)
+	return value, ok
+}
+
+func (p *ListBucketsParams) SetName(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["name"] = v
+}
+
+func (p *ListBucketsParams) ResetName() {
+	if p.p != nil && p.p["name"] != nil {
+		delete(p.p, "name")
+	}
+}
+
+func (p *ListBucketsParams) GetName() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["name"].(string)
+	return value, ok
+}
+
+func (p *ListBucketsParams) SetObjectstorageid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["objectstorageid"] = v
+}
+
+func (p *ListBucketsParams) ResetObjectstorageid() {
+	if p.p != nil && p.p["objectstorageid"] != nil {
+		delete(p.p, "objectstorageid")
+	}
+}
+
+func (p *ListBucketsParams) GetObjectstorageid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["objectstorageid"].(string)
+	return value, ok
+}
+
+func (p *ListBucketsParams) SetPage(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["page"] = v
+}
+
+func (p *ListBucketsParams) ResetPage() {
+	if p.p != nil && p.p["page"] != nil {
+		delete(p.p, "page")
+	}
+}
+
+func (p *ListBucketsParams) GetPage() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["page"].(int)
+	return value, ok
+}
+
+func (p *ListBucketsParams) SetPagesize(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["pagesize"] = v
+}
+
+func (p *ListBucketsParams) ResetPagesize() {
+	if p.p != nil && p.p["pagesize"] != nil {
+		delete(p.p, "pagesize")
+	}
+}
+
+func (p *ListBucketsParams) GetPagesize() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["pagesize"].(int)
+	return value, ok
+}
+
+func (p *ListBucketsParams) SetProjectid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["projectid"] = v
+}
+
+func (p *ListBucketsParams) ResetProjectid() {
+	if p.p != nil && p.p["projectid"] != nil {
+		delete(p.p, "projectid")
+	}
+}
+
+func (p *ListBucketsParams) GetProjectid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["projectid"].(string)
+	return value, ok
+}
+
+func (p *ListBucketsParams) SetTags(v map[string]string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["tags"] = v
+}
+
+func (p *ListBucketsParams) ResetTags() {
+	if p.p != nil && p.p["tags"] != nil {
+		delete(p.p, "tags")
+	}
+}
+
+func (p *ListBucketsParams) GetTags() (map[string]string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["tags"].(map[string]string)
+	return value, ok
+}
+
+// You should always use this function to get a new ListBucketsParams instance,
+// as then you are sure you have configured all required params
+func (s *ObjectStoreService) NewListBucketsParams() *ListBucketsParams {
+	p := &ListBucketsParams{}
+	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 *ObjectStoreService) GetBucketID(name string, opts ...OptionFunc) (string, int, error) {
+	p := &ListBucketsParams{}
+	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.ListBuckets(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.Buckets[0].Id, l.Count, nil
+	}
+
+	if l.Count > 1 {
+		for _, v := range l.Buckets {
+			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)
+}
+
+// This is a courtesy helper function, which in some cases may not work as expected!
+func (s *ObjectStoreService) GetBucketByName(name string, opts ...OptionFunc) (*Bucket, int, error) {
+	id, count, err := s.GetBucketID(name, opts...)
+	if err != nil {
+		return nil, count, err
+	}
+
+	r, count, err := s.GetBucketByID(id, opts...)
+	if err != nil {
+		return nil, count, err
+	}
+	return r, count, nil
+}
+
+// This is a courtesy helper function, which in some cases may not work as expected!
+func (s *ObjectStoreService) GetBucketByID(id string, opts ...OptionFunc) (*Bucket, int, error) {
+	p := &ListBucketsParams{}
+	p.p = make(map[string]interface{})
+
+	p.p["id"] = id
+
+	for _, fn := range append(s.cs.options, opts...) {
+		if err := fn(s.cs, p); err != nil {
+			return nil, -1, err
+		}
+	}
+
+	l, err := s.ListBuckets(p)
+	if err != nil {
+		if strings.Contains(err.Error(), fmt.Sprintf(
+			"Invalid parameter id value=%s due to incorrect long value format, "+
+				"or entity does not exist", id)) {
+			return nil, 0, fmt.Errorf("No match found for %s: %+v", id, l)
+		}
+		return nil, -1, err
+	}
+
+	if l.Count == 0 {
+		return nil, l.Count, fmt.Errorf("No match found for %s: %+v", id, l)
+	}
+
+	if l.Count == 1 {
+		return l.Buckets[0], l.Count, nil
+	}
+	return nil, l.Count, fmt.Errorf("There is more then one result for Bucket UUID: %s!", id)
+}
+
+// Lists all Buckets.
+func (s *ObjectStoreService) ListBuckets(p *ListBucketsParams) (*ListBucketsResponse, error) {
+	resp, err := s.cs.newRequest("listBuckets", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r ListBucketsResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type ListBucketsResponse struct {
+	Count   int       `json:"count"`
+	Buckets []*Bucket `json:"bucket"`
+}
+
+type Bucket struct {
+	Accesskey       string `json:"accesskey"`
+	Account         string `json:"account"`
+	Created         string `json:"created"`
+	Domain          string `json:"domain"`
+	Domainid        string `json:"domainid"`
+	Encryption      bool   `json:"encryption"`
+	Hasannotations  bool   `json:"hasannotations"`
+	Id              string `json:"id"`
+	JobID           string `json:"jobid"`
+	Jobstatus       int    `json:"jobstatus"`
+	Name            string `json:"name"`
+	Objectlocking   bool   `json:"objectlocking"`
+	Objectstorageid string `json:"objectstorageid"`
+	Objectstore     string `json:"objectstore"`
+	Policy          string `json:"policy"`
+	Project         string `json:"project"`
+	Projectid       string `json:"projectid"`
+	Provider        string `json:"provider"`
+	Quota           int    `json:"quota"`
+	Size            int64  `json:"size"`
+	State           string `json:"state"`
+	Tags            []Tags `json:"tags"`
+	Url             string `json:"url"`
+	Usersecretkey   string `json:"usersecretkey"`
+	Versioning      bool   `json:"versioning"`
+}
diff --git a/cloudstack/ObjectStoreService_mock.go b/cloudstack/ObjectStoreService_mock.go
new file mode 100644
index 0000000..c7f014e
--- /dev/null
+++ b/cloudstack/ObjectStoreService_mock.go
@@ -0,0 +1,232 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: ./cloudstack/ObjectStoreService.go
+
+// Package cloudstack is a generated GoMock package.
+package cloudstack
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockObjectStoreServiceIface is a mock of ObjectStoreServiceIface interface.
+type MockObjectStoreServiceIface struct {
+	ctrl     *gomock.Controller
+	recorder *MockObjectStoreServiceIfaceMockRecorder
+}
+
+// MockObjectStoreServiceIfaceMockRecorder is the mock recorder for MockObjectStoreServiceIface.
+type MockObjectStoreServiceIfaceMockRecorder struct {
+	mock *MockObjectStoreServiceIface
+}
+
+// NewMockObjectStoreServiceIface creates a new mock instance.
+func NewMockObjectStoreServiceIface(ctrl *gomock.Controller) *MockObjectStoreServiceIface {
+	mock := &MockObjectStoreServiceIface{ctrl: ctrl}
+	mock.recorder = &MockObjectStoreServiceIfaceMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockObjectStoreServiceIface) EXPECT() *MockObjectStoreServiceIfaceMockRecorder {
+	return m.recorder
+}
+
+// CreateBucket mocks base method.
+func (m *MockObjectStoreServiceIface) CreateBucket(p *CreateBucketParams) (*CreateBucketResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateBucket", p)
+	ret0, _ := ret[0].(*CreateBucketResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateBucket indicates an expected call of CreateBucket.
+func (mr *MockObjectStoreServiceIfaceMockRecorder) CreateBucket(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateBucket", reflect.TypeOf((*MockObjectStoreServiceIface)(nil).CreateBucket), p)
+}
+
+// DeleteBucket mocks base method.
+func (m *MockObjectStoreServiceIface) DeleteBucket(p *DeleteBucketParams) (*DeleteBucketResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DeleteBucket", p)
+	ret0, _ := ret[0].(*DeleteBucketResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// DeleteBucket indicates an expected call of DeleteBucket.
+func (mr *MockObjectStoreServiceIfaceMockRecorder) DeleteBucket(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteBucket", reflect.TypeOf((*MockObjectStoreServiceIface)(nil).DeleteBucket), p)
+}
+
+// GetBucketByID mocks base method.
+func (m *MockObjectStoreServiceIface) GetBucketByID(id string, opts ...OptionFunc) (*Bucket, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{id}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetBucketByID", varargs...)
+	ret0, _ := ret[0].(*Bucket)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetBucketByID indicates an expected call of GetBucketByID.
+func (mr *MockObjectStoreServiceIfaceMockRecorder) GetBucketByID(id interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{id}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBucketByID", reflect.TypeOf((*MockObjectStoreServiceIface)(nil).GetBucketByID), varargs...)
+}
+
+// GetBucketByName mocks base method.
+func (m *MockObjectStoreServiceIface) GetBucketByName(name string, opts ...OptionFunc) (*Bucket, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{name}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetBucketByName", varargs...)
+	ret0, _ := ret[0].(*Bucket)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetBucketByName indicates an expected call of GetBucketByName.
+func (mr *MockObjectStoreServiceIfaceMockRecorder) GetBucketByName(name interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{name}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBucketByName", reflect.TypeOf((*MockObjectStoreServiceIface)(nil).GetBucketByName), varargs...)
+}
+
+// GetBucketID mocks base method.
+func (m *MockObjectStoreServiceIface) GetBucketID(name string, opts ...OptionFunc) (string, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{name}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetBucketID", varargs...)
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetBucketID indicates an expected call of GetBucketID.
+func (mr *MockObjectStoreServiceIfaceMockRecorder) GetBucketID(name interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{name}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBucketID", reflect.TypeOf((*MockObjectStoreServiceIface)(nil).GetBucketID), varargs...)
+}
+
+// ListBuckets mocks base method.
+func (m *MockObjectStoreServiceIface) ListBuckets(p *ListBucketsParams) (*ListBucketsResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ListBuckets", p)
+	ret0, _ := ret[0].(*ListBucketsResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListBuckets indicates an expected call of ListBuckets.
+func (mr *MockObjectStoreServiceIfaceMockRecorder) ListBuckets(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListBuckets", reflect.TypeOf((*MockObjectStoreServiceIface)(nil).ListBuckets), p)
+}
+
+// NewCreateBucketParams mocks base method.
+func (m *MockObjectStoreServiceIface) NewCreateBucketParams(name, objectstorageid string) *CreateBucketParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewCreateBucketParams", name, objectstorageid)
+	ret0, _ := ret[0].(*CreateBucketParams)
+	return ret0
+}
+
+// NewCreateBucketParams indicates an expected call of NewCreateBucketParams.
+func (mr *MockObjectStoreServiceIfaceMockRecorder) NewCreateBucketParams(name, objectstorageid interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewCreateBucketParams", reflect.TypeOf((*MockObjectStoreServiceIface)(nil).NewCreateBucketParams), name, objectstorageid)
+}
+
+// NewDeleteBucketParams mocks base method.
+func (m *MockObjectStoreServiceIface) NewDeleteBucketParams(id string) *DeleteBucketParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewDeleteBucketParams", id)
+	ret0, _ := ret[0].(*DeleteBucketParams)
+	return ret0
+}
+
+// NewDeleteBucketParams indicates an expected call of NewDeleteBucketParams.
+func (mr *MockObjectStoreServiceIfaceMockRecorder) NewDeleteBucketParams(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewDeleteBucketParams", reflect.TypeOf((*MockObjectStoreServiceIface)(nil).NewDeleteBucketParams), id)
+}
+
+// NewListBucketsParams mocks base method.
+func (m *MockObjectStoreServiceIface) NewListBucketsParams() *ListBucketsParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewListBucketsParams")
+	ret0, _ := ret[0].(*ListBucketsParams)
+	return ret0
+}
+
+// NewListBucketsParams indicates an expected call of NewListBucketsParams.
+func (mr *MockObjectStoreServiceIfaceMockRecorder) NewListBucketsParams() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListBucketsParams", reflect.TypeOf((*MockObjectStoreServiceIface)(nil).NewListBucketsParams))
+}
+
+// NewUpdateBucketParams mocks base method.
+func (m *MockObjectStoreServiceIface) NewUpdateBucketParams(id string) *UpdateBucketParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewUpdateBucketParams", id)
+	ret0, _ := ret[0].(*UpdateBucketParams)
+	return ret0
+}
+
+// NewUpdateBucketParams indicates an expected call of NewUpdateBucketParams.
+func (mr *MockObjectStoreServiceIfaceMockRecorder) NewUpdateBucketParams(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewUpdateBucketParams", reflect.TypeOf((*MockObjectStoreServiceIface)(nil).NewUpdateBucketParams), id)
+}
+
+// UpdateBucket mocks base method.
+func (m *MockObjectStoreServiceIface) UpdateBucket(p *UpdateBucketParams) (*UpdateBucketResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "UpdateBucket", p)
+	ret0, _ := ret[0].(*UpdateBucketResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// UpdateBucket indicates an expected call of UpdateBucket.
+func (mr *MockObjectStoreServiceIfaceMockRecorder) UpdateBucket(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateBucket", reflect.TypeOf((*MockObjectStoreServiceIface)(nil).UpdateBucket), p)
+}
diff --git a/cloudstack/PodService.go b/cloudstack/PodService.go
index 34f70f8..d103bfa 100644
--- a/cloudstack/PodService.go
+++ b/cloudstack/PodService.go
@@ -45,6 +45,8 @@ type PodServiceIface interface {
 	NewReleaseDedicatedPodParams(podid string) *ReleaseDedicatedPodParams
 	UpdatePod(p *UpdatePodParams) (*UpdatePodResponse, error)
 	NewUpdatePodParams(id string) *UpdatePodParams
+	UpdatePodManagementNetworkIpRange(p *UpdatePodManagementNetworkIpRangeParams) (*UpdatePodManagementNetworkIpRangeResponse, error)
+	NewUpdatePodManagementNetworkIpRangeParams(currentendip string, currentstartip string, podid string) *UpdatePodManagementNetworkIpRangeParams
 }
 
 type CreatePodParams struct {
@@ -1443,3 +1445,183 @@ type UpdatePodResponseCapacity struct {
 	Zoneid            string `json:"zoneid"`
 	Zonename          string `json:"zonename"`
 }
+
+type UpdatePodManagementNetworkIpRangeParams struct {
+	p map[string]interface{}
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["currentendip"]; found {
+		u.Set("currentendip", v.(string))
+	}
+	if v, found := p.p["currentstartip"]; found {
+		u.Set("currentstartip", v.(string))
+	}
+	if v, found := p.p["newendip"]; found {
+		u.Set("newendip", v.(string))
+	}
+	if v, found := p.p["newstartip"]; found {
+		u.Set("newstartip", v.(string))
+	}
+	if v, found := p.p["podid"]; found {
+		u.Set("podid", v.(string))
+	}
+	return u
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) SetCurrentendip(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["currentendip"] = v
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) ResetCurrentendip() {
+	if p.p != nil && p.p["currentendip"] != nil {
+		delete(p.p, "currentendip")
+	}
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) GetCurrentendip() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["currentendip"].(string)
+	return value, ok
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) SetCurrentstartip(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["currentstartip"] = v
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) ResetCurrentstartip() {
+	if p.p != nil && p.p["currentstartip"] != nil {
+		delete(p.p, "currentstartip")
+	}
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) GetCurrentstartip() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["currentstartip"].(string)
+	return value, ok
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) SetNewendip(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["newendip"] = v
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) ResetNewendip() {
+	if p.p != nil && p.p["newendip"] != nil {
+		delete(p.p, "newendip")
+	}
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) GetNewendip() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["newendip"].(string)
+	return value, ok
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) SetNewstartip(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["newstartip"] = v
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) ResetNewstartip() {
+	if p.p != nil && p.p["newstartip"] != nil {
+		delete(p.p, "newstartip")
+	}
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) GetNewstartip() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["newstartip"].(string)
+	return value, ok
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) SetPodid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["podid"] = v
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) ResetPodid() {
+	if p.p != nil && p.p["podid"] != nil {
+		delete(p.p, "podid")
+	}
+}
+
+func (p *UpdatePodManagementNetworkIpRangeParams) GetPodid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["podid"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new UpdatePodManagementNetworkIpRangeParams instance,
+// as then you are sure you have configured all required params
+func (s *PodService) NewUpdatePodManagementNetworkIpRangeParams(currentendip string, currentstartip string, podid string) *UpdatePodManagementNetworkIpRangeParams {
+	p := &UpdatePodManagementNetworkIpRangeParams{}
+	p.p = make(map[string]interface{})
+	p.p["currentendip"] = currentendip
+	p.p["currentstartip"] = currentstartip
+	p.p["podid"] = podid
+	return p
+}
+
+// Updates a management network IP range. Only allowed when no IPs are allocated.
+func (s *PodService) UpdatePodManagementNetworkIpRange(p *UpdatePodManagementNetworkIpRangeParams) (*UpdatePodManagementNetworkIpRangeResponse, error) {
+	resp, err := s.cs.newRequest("updatePodManagementNetworkIpRange", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r UpdatePodManagementNetworkIpRangeResponse
+	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 UpdatePodManagementNetworkIpRangeResponse struct {
+	Displaytext string `json:"displaytext"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Success     bool   `json:"success"`
+}
diff --git a/cloudstack/PodService_mock.go b/cloudstack/PodService_mock.go
index 8d4cd3b..4e7bb9f 100644
--- a/cloudstack/PodService_mock.go
+++ b/cloudstack/PodService_mock.go
@@ -274,6 +274,20 @@ func (mr *MockPodServiceIfaceMockRecorder) NewReleaseDedicatedPodParams(podid in
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewReleaseDedicatedPodParams", reflect.TypeOf((*MockPodServiceIface)(nil).NewReleaseDedicatedPodParams), podid)
 }
 
+// NewUpdatePodManagementNetworkIpRangeParams mocks base method.
+func (m *MockPodServiceIface) NewUpdatePodManagementNetworkIpRangeParams(currentendip, currentstartip, podid string) *UpdatePodManagementNetworkIpRangeParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewUpdatePodManagementNetworkIpRangeParams", currentendip, currentstartip, podid)
+	ret0, _ := ret[0].(*UpdatePodManagementNetworkIpRangeParams)
+	return ret0
+}
+
+// NewUpdatePodManagementNetworkIpRangeParams indicates an expected call of NewUpdatePodManagementNetworkIpRangeParams.
+func (mr *MockPodServiceIfaceMockRecorder) NewUpdatePodManagementNetworkIpRangeParams(currentendip, currentstartip, podid interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewUpdatePodManagementNetworkIpRangeParams", reflect.TypeOf((*MockPodServiceIface)(nil).NewUpdatePodManagementNetworkIpRangeParams), currentendip, currentstartip, podid)
+}
+
 // NewUpdatePodParams mocks base method.
 func (m *MockPodServiceIface) NewUpdatePodParams(id string) *UpdatePodParams {
 	m.ctrl.T.Helper()
@@ -317,3 +331,18 @@ func (mr *MockPodServiceIfaceMockRecorder) UpdatePod(p interface{}) *gomock.Call
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePod", reflect.TypeOf((*MockPodServiceIface)(nil).UpdatePod), p)
 }
+
+// UpdatePodManagementNetworkIpRange mocks base method.
+func (m *MockPodServiceIface) UpdatePodManagementNetworkIpRange(p *UpdatePodManagementNetworkIpRangeParams) (*UpdatePodManagementNetworkIpRangeResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "UpdatePodManagementNetworkIpRange", p)
+	ret0, _ := ret[0].(*UpdatePodManagementNetworkIpRangeResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// UpdatePodManagementNetworkIpRange indicates an expected call of UpdatePodManagementNetworkIpRange.
+func (mr *MockPodServiceIfaceMockRecorder) UpdatePodManagementNetworkIpRange(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePodManagementNetworkIpRange", reflect.TypeOf((*MockPodServiceIface)(nil).UpdatePodManagementNetworkIpRange), p)
+}
diff --git a/cloudstack/ProjectService.go b/cloudstack/ProjectService.go
index c395376..4877ce1 100644
--- a/cloudstack/ProjectService.go
+++ b/cloudstack/ProjectService.go
@@ -66,6 +66,12 @@ type ProjectServiceIface interface {
 	NewUpdateProjectRolePermissionParams(projectid string, projectroleid string) *UpdateProjectRolePermissionParams
 	DeleteProjectRolePermission(p *DeleteProjectRolePermissionParams) (*DeleteProjectRolePermissionResponse, error)
 	NewDeleteProjectRolePermissionParams(id string, projectid string) *DeleteProjectRolePermissionParams
+	CreateProjectRole(p *CreateProjectRoleParams) (*CreateProjectRoleResponse, error)
+	NewCreateProjectRoleParams(name string, projectid string) *CreateProjectRoleParams
+	UpdateProjectRole(p *UpdateProjectRoleParams) (*UpdateProjectRoleResponse, error)
+	NewUpdateProjectRoleParams(id string, projectid string) *UpdateProjectRoleParams
+	DeleteProjectRole(p *DeleteProjectRoleParams) (*DeleteProjectRoleResponse, error)
+	NewDeleteProjectRoleParams(id string, projectid string) *DeleteProjectRoleParams
 }
 
 type ActivateProjectParams struct {
@@ -3303,3 +3309,390 @@ func (r *DeleteProjectRolePermissionResponse) UnmarshalJSON(b []byte) error {
 	type alias DeleteProjectRolePermissionResponse
 	return json.Unmarshal(b, (*alias)(r))
 }
+
+type CreateProjectRoleParams struct {
+	p map[string]interface{}
+}
+
+func (p *CreateProjectRoleParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["description"]; found {
+		u.Set("description", v.(string))
+	}
+	if v, found := p.p["name"]; found {
+		u.Set("name", v.(string))
+	}
+	if v, found := p.p["projectid"]; found {
+		u.Set("projectid", v.(string))
+	}
+	return u
+}
+
+func (p *CreateProjectRoleParams) SetDescription(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["description"] = v
+}
+
+func (p *CreateProjectRoleParams) ResetDescription() {
+	if p.p != nil && p.p["description"] != nil {
+		delete(p.p, "description")
+	}
+}
+
+func (p *CreateProjectRoleParams) GetDescription() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["description"].(string)
+	return value, ok
+}
+
+func (p *CreateProjectRoleParams) SetName(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["name"] = v
+}
+
+func (p *CreateProjectRoleParams) ResetName() {
+	if p.p != nil && p.p["name"] != nil {
+		delete(p.p, "name")
+	}
+}
+
+func (p *CreateProjectRoleParams) GetName() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["name"].(string)
+	return value, ok
+}
+
+func (p *CreateProjectRoleParams) SetProjectid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["projectid"] = v
+}
+
+func (p *CreateProjectRoleParams) ResetProjectid() {
+	if p.p != nil && p.p["projectid"] != nil {
+		delete(p.p, "projectid")
+	}
+}
+
+func (p *CreateProjectRoleParams) GetProjectid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["projectid"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new CreateProjectRoleParams instance,
+// as then you are sure you have configured all required params
+func (s *ProjectService) NewCreateProjectRoleParams(name string, projectid string) *CreateProjectRoleParams {
+	p := &CreateProjectRoleParams{}
+	p.p = make(map[string]interface{})
+	p.p["name"] = name
+	p.p["projectid"] = projectid
+	return p
+}
+
+// Creates a Project role
+func (s *ProjectService) CreateProjectRole(p *CreateProjectRoleParams) (*CreateProjectRoleResponse, error) {
+	resp, err := s.cs.newRequest("createProjectRole", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var nested struct {
+		Response CreateProjectRoleResponse `json:"projectrole"`
+	}
+	if err := json.Unmarshal(resp, &nested); err != nil {
+		return nil, err
+	}
+	r := nested.Response
+
+	return &r, nil
+}
+
+type CreateProjectRoleResponse struct {
+	Description string `json:"description"`
+	Id          string `json:"id"`
+	Ispublic    bool   `json:"ispublic"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Name        string `json:"name"`
+	Projectid   string `json:"projectid"`
+}
+
+type UpdateProjectRoleParams struct {
+	p map[string]interface{}
+}
+
+func (p *UpdateProjectRoleParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["description"]; found {
+		u.Set("description", v.(string))
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	if v, found := p.p["name"]; found {
+		u.Set("name", v.(string))
+	}
+	if v, found := p.p["projectid"]; found {
+		u.Set("projectid", v.(string))
+	}
+	return u
+}
+
+func (p *UpdateProjectRoleParams) SetDescription(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["description"] = v
+}
+
+func (p *UpdateProjectRoleParams) ResetDescription() {
+	if p.p != nil && p.p["description"] != nil {
+		delete(p.p, "description")
+	}
+}
+
+func (p *UpdateProjectRoleParams) GetDescription() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["description"].(string)
+	return value, ok
+}
+
+func (p *UpdateProjectRoleParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *UpdateProjectRoleParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *UpdateProjectRoleParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+func (p *UpdateProjectRoleParams) SetName(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["name"] = v
+}
+
+func (p *UpdateProjectRoleParams) ResetName() {
+	if p.p != nil && p.p["name"] != nil {
+		delete(p.p, "name")
+	}
+}
+
+func (p *UpdateProjectRoleParams) GetName() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["name"].(string)
+	return value, ok
+}
+
+func (p *UpdateProjectRoleParams) SetProjectid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["projectid"] = v
+}
+
+func (p *UpdateProjectRoleParams) ResetProjectid() {
+	if p.p != nil && p.p["projectid"] != nil {
+		delete(p.p, "projectid")
+	}
+}
+
+func (p *UpdateProjectRoleParams) GetProjectid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["projectid"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new UpdateProjectRoleParams instance,
+// as then you are sure you have configured all required params
+func (s *ProjectService) NewUpdateProjectRoleParams(id string, projectid string) *UpdateProjectRoleParams {
+	p := &UpdateProjectRoleParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	p.p["projectid"] = projectid
+	return p
+}
+
+// Creates a Project role
+func (s *ProjectService) UpdateProjectRole(p *UpdateProjectRoleParams) (*UpdateProjectRoleResponse, error) {
+	resp, err := s.cs.newRequest("updateProjectRole", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var nested struct {
+		Response UpdateProjectRoleResponse `json:"projectrole"`
+	}
+	if err := json.Unmarshal(resp, &nested); err != nil {
+		return nil, err
+	}
+	r := nested.Response
+
+	return &r, nil
+}
+
+type UpdateProjectRoleResponse struct {
+	Description string `json:"description"`
+	Id          string `json:"id"`
+	Ispublic    bool   `json:"ispublic"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Name        string `json:"name"`
+	Projectid   string `json:"projectid"`
+}
+
+type DeleteProjectRoleParams struct {
+	p map[string]interface{}
+}
+
+func (p *DeleteProjectRoleParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	if v, found := p.p["projectid"]; found {
+		u.Set("projectid", v.(string))
+	}
+	return u
+}
+
+func (p *DeleteProjectRoleParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *DeleteProjectRoleParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *DeleteProjectRoleParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+func (p *DeleteProjectRoleParams) SetProjectid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["projectid"] = v
+}
+
+func (p *DeleteProjectRoleParams) ResetProjectid() {
+	if p.p != nil && p.p["projectid"] != nil {
+		delete(p.p, "projectid")
+	}
+}
+
+func (p *DeleteProjectRoleParams) GetProjectid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["projectid"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new DeleteProjectRoleParams instance,
+// as then you are sure you have configured all required params
+func (s *ProjectService) NewDeleteProjectRoleParams(id string, projectid string) *DeleteProjectRoleParams {
+	p := &DeleteProjectRoleParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	p.p["projectid"] = projectid
+	return p
+}
+
+// Delete Project roles in CloudStack
+func (s *ProjectService) DeleteProjectRole(p *DeleteProjectRoleParams) (*DeleteProjectRoleResponse, error) {
+	resp, err := s.cs.newRequest("deleteProjectRole", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r DeleteProjectRoleResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type DeleteProjectRoleResponse struct {
+	Displaytext string `json:"displaytext"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Success     bool   `json:"success"`
+}
+
+func (r *DeleteProjectRoleResponse) UnmarshalJSON(b []byte) error {
+	var m map[string]interface{}
+	err := json.Unmarshal(b, &m)
+	if err != nil {
+		return err
+	}
+
+	if success, ok := m["success"].(string); ok {
+		m["success"] = success == "true"
+		b, err = json.Marshal(m)
+		if err != nil {
+			return err
+		}
+	}
+
+	if ostypeid, ok := m["ostypeid"].(float64); ok {
+		m["ostypeid"] = strconv.Itoa(int(ostypeid))
+		b, err = json.Marshal(m)
+		if err != nil {
+			return err
+		}
+	}
+
+	type alias DeleteProjectRoleResponse
+	return json.Unmarshal(b, (*alias)(r))
+}
diff --git a/cloudstack/ProjectService_mock.go b/cloudstack/ProjectService_mock.go
index a2481e0..6a5b974 100644
--- a/cloudstack/ProjectService_mock.go
+++ b/cloudstack/ProjectService_mock.go
@@ -112,6 +112,21 @@ func (mr *MockProjectServiceIfaceMockRecorder) CreateProject(p interface{}) *gom
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateProject", reflect.TypeOf((*MockProjectServiceIface)(nil).CreateProject), p)
 }
 
+// CreateProjectRole mocks base method.
+func (m *MockProjectServiceIface) CreateProjectRole(p *CreateProjectRoleParams) (*CreateProjectRoleResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateProjectRole", p)
+	ret0, _ := ret[0].(*CreateProjectRoleResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateProjectRole indicates an expected call of CreateProjectRole.
+func (mr *MockProjectServiceIfaceMockRecorder) CreateProjectRole(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateProjectRole", reflect.TypeOf((*MockProjectServiceIface)(nil).CreateProjectRole), p)
+}
+
 // CreateProjectRolePermission mocks base method.
 func (m *MockProjectServiceIface) CreateProjectRolePermission(p *CreateProjectRolePermissionParams) (*CreateProjectRolePermissionResponse, error) {
 	m.ctrl.T.Helper()
@@ -172,6 +187,21 @@ func (mr *MockProjectServiceIfaceMockRecorder) DeleteProjectInvitation(p interfa
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteProjectInvitation", reflect.TypeOf((*MockProjectServiceIface)(nil).DeleteProjectInvitation), p)
 }
 
+// DeleteProjectRole mocks base method.
+func (m *MockProjectServiceIface) DeleteProjectRole(p *DeleteProjectRoleParams) (*DeleteProjectRoleResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DeleteProjectRole", p)
+	ret0, _ := ret[0].(*DeleteProjectRoleResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// DeleteProjectRole indicates an expected call of DeleteProjectRole.
+func (mr *MockProjectServiceIfaceMockRecorder) DeleteProjectRole(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteProjectRole", reflect.TypeOf((*MockProjectServiceIface)(nil).DeleteProjectRole), p)
+}
+
 // DeleteProjectRolePermission mocks base method.
 func (m *MockProjectServiceIface) DeleteProjectRolePermission(p *DeleteProjectRolePermissionParams) (*DeleteProjectRolePermissionResponse, error) {
 	m.ctrl.T.Helper()
@@ -387,6 +417,20 @@ func (mr *MockProjectServiceIfaceMockRecorder) NewCreateProjectParams(displaytex
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewCreateProjectParams", reflect.TypeOf((*MockProjectServiceIface)(nil).NewCreateProjectParams), displaytext, name)
 }
 
+// NewCreateProjectRoleParams mocks base method.
+func (m *MockProjectServiceIface) NewCreateProjectRoleParams(name, projectid string) *CreateProjectRoleParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewCreateProjectRoleParams", name, projectid)
+	ret0, _ := ret[0].(*CreateProjectRoleParams)
+	return ret0
+}
+
+// NewCreateProjectRoleParams indicates an expected call of NewCreateProjectRoleParams.
+func (mr *MockProjectServiceIfaceMockRecorder) NewCreateProjectRoleParams(name, projectid interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewCreateProjectRoleParams", reflect.TypeOf((*MockProjectServiceIface)(nil).NewCreateProjectRoleParams), name, projectid)
+}
+
 // NewCreateProjectRolePermissionParams mocks base method.
 func (m *MockProjectServiceIface) NewCreateProjectRolePermissionParams(permission, projectid, projectroleid, rule string) *CreateProjectRolePermissionParams {
 	m.ctrl.T.Helper()
@@ -443,6 +487,20 @@ func (mr *MockProjectServiceIfaceMockRecorder) NewDeleteProjectParams(id interfa
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewDeleteProjectParams", reflect.TypeOf((*MockProjectServiceIface)(nil).NewDeleteProjectParams), id)
 }
 
+// NewDeleteProjectRoleParams mocks base method.
+func (m *MockProjectServiceIface) NewDeleteProjectRoleParams(id, projectid string) *DeleteProjectRoleParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewDeleteProjectRoleParams", id, projectid)
+	ret0, _ := ret[0].(*DeleteProjectRoleParams)
+	return ret0
+}
+
+// NewDeleteProjectRoleParams indicates an expected call of NewDeleteProjectRoleParams.
+func (mr *MockProjectServiceIfaceMockRecorder) NewDeleteProjectRoleParams(id, projectid interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewDeleteProjectRoleParams", reflect.TypeOf((*MockProjectServiceIface)(nil).NewDeleteProjectRoleParams), id, projectid)
+}
+
 // NewDeleteProjectRolePermissionParams mocks base method.
 func (m *MockProjectServiceIface) NewDeleteProjectRolePermissionParams(id, projectid string) *DeleteProjectRolePermissionParams {
 	m.ctrl.T.Helper()
@@ -555,6 +613,20 @@ func (mr *MockProjectServiceIfaceMockRecorder) NewUpdateProjectParams(id interfa
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewUpdateProjectParams", reflect.TypeOf((*MockProjectServiceIface)(nil).NewUpdateProjectParams), id)
 }
 
+// NewUpdateProjectRoleParams mocks base method.
+func (m *MockProjectServiceIface) NewUpdateProjectRoleParams(id, projectid string) *UpdateProjectRoleParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewUpdateProjectRoleParams", id, projectid)
+	ret0, _ := ret[0].(*UpdateProjectRoleParams)
+	return ret0
+}
+
+// NewUpdateProjectRoleParams indicates an expected call of NewUpdateProjectRoleParams.
+func (mr *MockProjectServiceIfaceMockRecorder) NewUpdateProjectRoleParams(id, projectid interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewUpdateProjectRoleParams", reflect.TypeOf((*MockProjectServiceIface)(nil).NewUpdateProjectRoleParams), id, projectid)
+}
+
 // NewUpdateProjectRolePermissionParams mocks base method.
 func (m *MockProjectServiceIface) NewUpdateProjectRolePermissionParams(projectid, projectroleid string) *UpdateProjectRolePermissionParams {
 	m.ctrl.T.Helper()
@@ -614,6 +686,21 @@ func (mr *MockProjectServiceIfaceMockRecorder) UpdateProjectInvitation(p interfa
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateProjectInvitation", reflect.TypeOf((*MockProjectServiceIface)(nil).UpdateProjectInvitation), p)
 }
 
+// UpdateProjectRole mocks base method.
+func (m *MockProjectServiceIface) UpdateProjectRole(p *UpdateProjectRoleParams) (*UpdateProjectRoleResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "UpdateProjectRole", p)
+	ret0, _ := ret[0].(*UpdateProjectRoleResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// UpdateProjectRole indicates an expected call of UpdateProjectRole.
+func (mr *MockProjectServiceIfaceMockRecorder) UpdateProjectRole(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateProjectRole", reflect.TypeOf((*MockProjectServiceIface)(nil).UpdateProjectRole), p)
+}
+
 // UpdateProjectRolePermission mocks base method.
 func (m *MockProjectServiceIface) UpdateProjectRolePermission(p *UpdateProjectRolePermissionParams) (*UpdateProjectRolePermissionResponse, error) {
 	m.ctrl.T.Helper()
diff --git a/cloudstack/RegistrationService.go b/cloudstack/RegistrationService.go
new file mode 100644
index 0000000..56a508e
--- /dev/null
+++ b/cloudstack/RegistrationService.go
@@ -0,0 +1,269 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 cloudstack
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/url"
+	"strconv"
+)
+
+type RegistrationServiceIface interface {
+	RegisterOauthProvider(p *RegisterOauthProviderParams) (*RegisterOauthProviderResponse, error)
+	NewRegisterOauthProviderParams(clientid string, description string, provider string, redirecturi string, secretkey string) *RegisterOauthProviderParams
+}
+
+type RegisterOauthProviderParams struct {
+	p map[string]interface{}
+}
+
+func (p *RegisterOauthProviderParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["clientid"]; found {
+		u.Set("clientid", v.(string))
+	}
+	if v, found := p.p["description"]; found {
+		u.Set("description", v.(string))
+	}
+	if v, found := p.p["details"]; found {
+		l := v.([]map[string]string)
+		for i, m := range l {
+			for key, val := range m {
+				u.Set(fmt.Sprintf("details[%d].%s", i, key), val)
+			}
+		}
+	}
+	if v, found := p.p["provider"]; found {
+		u.Set("provider", v.(string))
+	}
+	if v, found := p.p["redirecturi"]; found {
+		u.Set("redirecturi", v.(string))
+	}
+	if v, found := p.p["secretkey"]; found {
+		u.Set("secretkey", v.(string))
+	}
+	return u
+}
+
+func (p *RegisterOauthProviderParams) SetClientid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["clientid"] = v
+}
+
+func (p *RegisterOauthProviderParams) ResetClientid() {
+	if p.p != nil && p.p["clientid"] != nil {
+		delete(p.p, "clientid")
+	}
+}
+
+func (p *RegisterOauthProviderParams) GetClientid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["clientid"].(string)
+	return value, ok
+}
+
+func (p *RegisterOauthProviderParams) SetDescription(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["description"] = v
+}
+
+func (p *RegisterOauthProviderParams) ResetDescription() {
+	if p.p != nil && p.p["description"] != nil {
+		delete(p.p, "description")
+	}
+}
+
+func (p *RegisterOauthProviderParams) GetDescription() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["description"].(string)
+	return value, ok
+}
+
+func (p *RegisterOauthProviderParams) SetDetails(v []map[string]string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["details"] = v
+}
+
+func (p *RegisterOauthProviderParams) ResetDetails() {
+	if p.p != nil && p.p["details"] != nil {
+		delete(p.p, "details")
+	}
+}
+
+func (p *RegisterOauthProviderParams) GetDetails() ([]map[string]string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["details"].([]map[string]string)
+	return value, ok
+}
+
+func (p *RegisterOauthProviderParams) AddDetails(item map[string]string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	val, found := p.p["details"]
+	if !found {
+		p.p["details"] = []map[string]string{}
+		val = p.p["details"]
+	}
+	l := val.([]map[string]string)
+	l = append(l, item)
+	p.p["details"] = l
+}
+
+func (p *RegisterOauthProviderParams) SetProvider(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["provider"] = v
+}
+
+func (p *RegisterOauthProviderParams) ResetProvider() {
+	if p.p != nil && p.p["provider"] != nil {
+		delete(p.p, "provider")
+	}
+}
+
+func (p *RegisterOauthProviderParams) GetProvider() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["provider"].(string)
+	return value, ok
+}
+
+func (p *RegisterOauthProviderParams) SetRedirecturi(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["redirecturi"] = v
+}
+
+func (p *RegisterOauthProviderParams) ResetRedirecturi() {
+	if p.p != nil && p.p["redirecturi"] != nil {
+		delete(p.p, "redirecturi")
+	}
+}
+
+func (p *RegisterOauthProviderParams) GetRedirecturi() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["redirecturi"].(string)
+	return value, ok
+}
+
+func (p *RegisterOauthProviderParams) SetSecretkey(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["secretkey"] = v
+}
+
+func (p *RegisterOauthProviderParams) ResetSecretkey() {
+	if p.p != nil && p.p["secretkey"] != nil {
+		delete(p.p, "secretkey")
+	}
+}
+
+func (p *RegisterOauthProviderParams) GetSecretkey() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["secretkey"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new RegisterOauthProviderParams instance,
+// as then you are sure you have configured all required params
+func (s *RegistrationService) NewRegisterOauthProviderParams(clientid string, description string, provider string, redirecturi string, secretkey string) *RegisterOauthProviderParams {
+	p := &RegisterOauthProviderParams{}
+	p.p = make(map[string]interface{})
+	p.p["clientid"] = clientid
+	p.p["description"] = description
+	p.p["provider"] = provider
+	p.p["redirecturi"] = redirecturi
+	p.p["secretkey"] = secretkey
+	return p
+}
+
+// Register the OAuth2 provider in CloudStack
+func (s *RegistrationService) RegisterOauthProvider(p *RegisterOauthProviderParams) (*RegisterOauthProviderResponse, error) {
+	resp, err := s.cs.newRequest("registerOauthProvider", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r RegisterOauthProviderResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type RegisterOauthProviderResponse struct {
+	Displaytext string `json:"displaytext"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Success     bool   `json:"success"`
+}
+
+func (r *RegisterOauthProviderResponse) UnmarshalJSON(b []byte) error {
+	var m map[string]interface{}
+	err := json.Unmarshal(b, &m)
+	if err != nil {
+		return err
+	}
+
+	if success, ok := m["success"].(string); ok {
+		m["success"] = success == "true"
+		b, err = json.Marshal(m)
+		if err != nil {
+			return err
+		}
+	}
+
+	if ostypeid, ok := m["ostypeid"].(float64); ok {
+		m["ostypeid"] = strconv.Itoa(int(ostypeid))
+		b, err = json.Marshal(m)
+		if err != nil {
+			return err
+		}
+	}
+
+	type alias RegisterOauthProviderResponse
+	return json.Unmarshal(b, (*alias)(r))
+}
diff --git a/cloudstack/RegistrationService_mock.go b/cloudstack/RegistrationService_mock.go
new file mode 100644
index 0000000..11097cf
--- /dev/null
+++ b/cloudstack/RegistrationService_mock.go
@@ -0,0 +1,82 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: ./cloudstack/RegistrationService.go
+
+// Package cloudstack is a generated GoMock package.
+package cloudstack
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockRegistrationServiceIface is a mock of RegistrationServiceIface interface.
+type MockRegistrationServiceIface struct {
+	ctrl     *gomock.Controller
+	recorder *MockRegistrationServiceIfaceMockRecorder
+}
+
+// MockRegistrationServiceIfaceMockRecorder is the mock recorder for MockRegistrationServiceIface.
+type MockRegistrationServiceIfaceMockRecorder struct {
+	mock *MockRegistrationServiceIface
+}
+
+// NewMockRegistrationServiceIface creates a new mock instance.
+func NewMockRegistrationServiceIface(ctrl *gomock.Controller) *MockRegistrationServiceIface {
+	mock := &MockRegistrationServiceIface{ctrl: ctrl}
+	mock.recorder = &MockRegistrationServiceIfaceMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockRegistrationServiceIface) EXPECT() *MockRegistrationServiceIfaceMockRecorder {
+	return m.recorder
+}
+
+// NewRegisterOauthProviderParams mocks base method.
+func (m *MockRegistrationServiceIface) NewRegisterOauthProviderParams(clientid, description, provider, redirecturi, secretkey string) *RegisterOauthProviderParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewRegisterOauthProviderParams", clientid, description, provider, redirecturi, secretkey)
+	ret0, _ := ret[0].(*RegisterOauthProviderParams)
+	return ret0
+}
+
+// NewRegisterOauthProviderParams indicates an expected call of NewRegisterOauthProviderParams.
+func (mr *MockRegistrationServiceIfaceMockRecorder) NewRegisterOauthProviderParams(clientid, description, provider, redirecturi, secretkey interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewRegisterOauthProviderParams", reflect.TypeOf((*MockRegistrationServiceIface)(nil).NewRegisterOauthProviderParams), clientid, description, provider, redirecturi, secretkey)
+}
+
+// RegisterOauthProvider mocks base method.
+func (m *MockRegistrationServiceIface) RegisterOauthProvider(p *RegisterOauthProviderParams) (*RegisterOauthProviderResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "RegisterOauthProvider", p)
+	ret0, _ := ret[0].(*RegisterOauthProviderResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// RegisterOauthProvider indicates an expected call of RegisterOauthProvider.
+func (mr *MockRegistrationServiceIfaceMockRecorder) RegisterOauthProvider(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterOauthProvider", reflect.TypeOf((*MockRegistrationServiceIface)(nil).RegisterOauthProvider), p)
+}
diff --git a/cloudstack/RoleService.go b/cloudstack/RoleService.go
index d3d2cf2..533badb 100644
--- a/cloudstack/RoleService.go
+++ b/cloudstack/RoleService.go
@@ -49,6 +49,9 @@ type RoleServiceIface interface {
 	NewUpdateRoleParams(id string) *UpdateRoleParams
 	UpdateRolePermission(p *UpdateRolePermissionParams) (*UpdateRolePermissionResponse, error)
 	NewUpdateRolePermissionParams(roleid string) *UpdateRolePermissionParams
+	ListProjectRoles(p *ListProjectRolesParams) (*ListProjectRolesResponse, error)
+	NewListProjectRolesParams(projectid string) *ListProjectRolesParams
+	GetProjectRoleID(name string, projectid string, opts ...OptionFunc) (string, int, error)
 }
 
 type CreateRoleParams struct {
@@ -1448,3 +1451,237 @@ func (r *UpdateRolePermissionResponse) UnmarshalJSON(b []byte) error {
 	type alias UpdateRolePermissionResponse
 	return json.Unmarshal(b, (*alias)(r))
 }
+
+type ListProjectRolesParams struct {
+	p map[string]interface{}
+}
+
+func (p *ListProjectRolesParams) 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)
+	}
+	if v, found := p.p["projectid"]; found {
+		u.Set("projectid", v.(string))
+	}
+	if v, found := p.p["projectroleid"]; found {
+		u.Set("projectroleid", v.(string))
+	}
+	return u
+}
+
+func (p *ListProjectRolesParams) SetKeyword(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["keyword"] = v
+}
+
+func (p *ListProjectRolesParams) ResetKeyword() {
+	if p.p != nil && p.p["keyword"] != nil {
+		delete(p.p, "keyword")
+	}
+}
+
+func (p *ListProjectRolesParams) GetKeyword() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["keyword"].(string)
+	return value, ok
+}
+
+func (p *ListProjectRolesParams) SetName(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["name"] = v
+}
+
+func (p *ListProjectRolesParams) ResetName() {
+	if p.p != nil && p.p["name"] != nil {
+		delete(p.p, "name")
+	}
+}
+
+func (p *ListProjectRolesParams) GetName() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["name"].(string)
+	return value, ok
+}
+
+func (p *ListProjectRolesParams) SetPage(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["page"] = v
+}
+
+func (p *ListProjectRolesParams) ResetPage() {
+	if p.p != nil && p.p["page"] != nil {
+		delete(p.p, "page")
+	}
+}
+
+func (p *ListProjectRolesParams) GetPage() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["page"].(int)
+	return value, ok
+}
+
+func (p *ListProjectRolesParams) SetPagesize(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["pagesize"] = v
+}
+
+func (p *ListProjectRolesParams) ResetPagesize() {
+	if p.p != nil && p.p["pagesize"] != nil {
+		delete(p.p, "pagesize")
+	}
+}
+
+func (p *ListProjectRolesParams) GetPagesize() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["pagesize"].(int)
+	return value, ok
+}
+
+func (p *ListProjectRolesParams) SetProjectid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["projectid"] = v
+}
+
+func (p *ListProjectRolesParams) ResetProjectid() {
+	if p.p != nil && p.p["projectid"] != nil {
+		delete(p.p, "projectid")
+	}
+}
+
+func (p *ListProjectRolesParams) GetProjectid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["projectid"].(string)
+	return value, ok
+}
+
+func (p *ListProjectRolesParams) SetProjectroleid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["projectroleid"] = v
+}
+
+func (p *ListProjectRolesParams) ResetProjectroleid() {
+	if p.p != nil && p.p["projectroleid"] != nil {
+		delete(p.p, "projectroleid")
+	}
+}
+
+func (p *ListProjectRolesParams) GetProjectroleid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["projectroleid"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new ListProjectRolesParams instance,
+// as then you are sure you have configured all required params
+func (s *RoleService) NewListProjectRolesParams(projectid string) *ListProjectRolesParams {
+	p := &ListProjectRolesParams{}
+	p.p = make(map[string]interface{})
+	p.p["projectid"] = projectid
+	return p
+}
+
+// This is a courtesy helper function, which in some cases may not work as expected!
+func (s *RoleService) GetProjectRoleID(name string, projectid string, opts ...OptionFunc) (string, int, error) {
+	p := &ListProjectRolesParams{}
+	p.p = make(map[string]interface{})
+
+	p.p["name"] = name
+	p.p["projectid"] = projectid
+
+	for _, fn := range append(s.cs.options, opts...) {
+		if err := fn(s.cs, p); err != nil {
+			return "", -1, err
+		}
+	}
+
+	l, err := s.ListProjectRoles(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.ProjectRoles[0].Id, l.Count, nil
+	}
+
+	if l.Count > 1 {
+		for _, v := range l.ProjectRoles {
+			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 Project roles in CloudStack
+func (s *RoleService) ListProjectRoles(p *ListProjectRolesParams) (*ListProjectRolesResponse, error) {
+	resp, err := s.cs.newRequest("listProjectRoles", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r ListProjectRolesResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type ListProjectRolesResponse struct {
+	Count        int            `json:"count"`
+	ProjectRoles []*ProjectRole `json:"projectrole"`
+}
+
+type ProjectRole struct {
+	Description string `json:"description"`
+	Id          string `json:"id"`
+	Ispublic    bool   `json:"ispublic"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Name        string `json:"name"`
+	Projectid   string `json:"projectid"`
+}
diff --git a/cloudstack/RoleService_mock.go b/cloudstack/RoleService_mock.go
index cac7e6b..50c87ed 100644
--- a/cloudstack/RoleService_mock.go
+++ b/cloudstack/RoleService_mock.go
@@ -112,6 +112,27 @@ func (mr *MockRoleServiceIfaceMockRecorder) DeleteRolePermission(p interface{})
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRolePermission", reflect.TypeOf((*MockRoleServiceIface)(nil).DeleteRolePermission), p)
 }
 
+// GetProjectRoleID mocks base method.
+func (m *MockRoleServiceIface) GetProjectRoleID(name, projectid string, opts ...OptionFunc) (string, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{name, projectid}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetProjectRoleID", varargs...)
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetProjectRoleID indicates an expected call of GetProjectRoleID.
+func (mr *MockRoleServiceIfaceMockRecorder) GetProjectRoleID(name, projectid interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{name, projectid}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProjectRoleID", reflect.TypeOf((*MockRoleServiceIface)(nil).GetProjectRoleID), varargs...)
+}
+
 // GetRoleByID mocks base method.
 func (m *MockRoleServiceIface) GetRoleByID(id string, opts ...OptionFunc) (*Role, int, error) {
 	m.ctrl.T.Helper()
@@ -190,6 +211,21 @@ func (mr *MockRoleServiceIfaceMockRecorder) ImportRole(p interface{}) *gomock.Ca
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ImportRole", reflect.TypeOf((*MockRoleServiceIface)(nil).ImportRole), p)
 }
 
+// ListProjectRoles mocks base method.
+func (m *MockRoleServiceIface) ListProjectRoles(p *ListProjectRolesParams) (*ListProjectRolesResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ListProjectRoles", p)
+	ret0, _ := ret[0].(*ListProjectRolesResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListProjectRoles indicates an expected call of ListProjectRoles.
+func (mr *MockRoleServiceIfaceMockRecorder) ListProjectRoles(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListProjectRoles", reflect.TypeOf((*MockRoleServiceIface)(nil).ListProjectRoles), p)
+}
+
 // ListRolePermissions mocks base method.
 func (m *MockRoleServiceIface) ListRolePermissions(p *ListRolePermissionsParams) (*ListRolePermissionsResponse, error) {
 	m.ctrl.T.Helper()
@@ -290,6 +326,20 @@ func (mr *MockRoleServiceIfaceMockRecorder) NewImportRoleParams(name, rules inte
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewImportRoleParams", reflect.TypeOf((*MockRoleServiceIface)(nil).NewImportRoleParams), name, rules)
 }
 
+// NewListProjectRolesParams mocks base method.
+func (m *MockRoleServiceIface) NewListProjectRolesParams(projectid string) *ListProjectRolesParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewListProjectRolesParams", projectid)
+	ret0, _ := ret[0].(*ListProjectRolesParams)
+	return ret0
+}
+
+// NewListProjectRolesParams indicates an expected call of NewListProjectRolesParams.
+func (mr *MockRoleServiceIfaceMockRecorder) NewListProjectRolesParams(projectid interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListProjectRolesParams", reflect.TypeOf((*MockRoleServiceIface)(nil).NewListProjectRolesParams), projectid)
+}
+
 // NewListRolePermissionsParams mocks base method.
 func (m *MockRoleServiceIface) NewListRolePermissionsParams() *ListRolePermissionsParams {
 	m.ctrl.T.Helper()
diff --git a/cloudstack/ShutdownService.go b/cloudstack/ShutdownService.go
new file mode 100644
index 0000000..257ec5c
--- /dev/null
+++ b/cloudstack/ShutdownService.go
@@ -0,0 +1,101 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 cloudstack
+
+import (
+	"encoding/json"
+	"net/url"
+)
+
+type ShutdownServiceIface interface {
+	ReadyForShutdown(p *ReadyForShutdownParams) (*ReadyForShutdownResponse, error)
+	NewReadyForShutdownParams() *ReadyForShutdownParams
+}
+
+type ReadyForShutdownParams struct {
+	p map[string]interface{}
+}
+
+func (p *ReadyForShutdownParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["managementserverid"]; found {
+		u.Set("managementserverid", v.(string))
+	}
+	return u
+}
+
+func (p *ReadyForShutdownParams) SetManagementserverid(v UUID) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["managementserverid"] = v
+}
+
+func (p *ReadyForShutdownParams) ResetManagementserverid() {
+	if p.p != nil && p.p["managementserverid"] != nil {
+		delete(p.p, "managementserverid")
+	}
+}
+
+func (p *ReadyForShutdownParams) GetManagementserverid() (UUID, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["managementserverid"].(UUID)
+	return value, ok
+}
+
+// You should always use this function to get a new ReadyForShutdownParams instance,
+// as then you are sure you have configured all required params
+func (s *ShutdownService) NewReadyForShutdownParams() *ReadyForShutdownParams {
+	p := &ReadyForShutdownParams{}
+	p.p = make(map[string]interface{})
+	return p
+}
+
+// Returns the status of CloudStack, whether a shutdown has been triggered and if ready to shutdown
+func (s *ShutdownService) ReadyForShutdown(p *ReadyForShutdownParams) (*ReadyForShutdownResponse, error) {
+	resp, err := s.cs.newRequest("readyForShutdown", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var nested struct {
+		Response ReadyForShutdownResponse `json:"readyforshutdown"`
+	}
+	if err := json.Unmarshal(resp, &nested); err != nil {
+		return nil, err
+	}
+	r := nested.Response
+
+	return &r, nil
+}
+
+type ReadyForShutdownResponse struct {
+	JobID              string `json:"jobid"`
+	Jobstatus          int    `json:"jobstatus"`
+	Managementserverid UUID   `json:"managementserverid"`
+	Pendingjobscount   int64  `json:"pendingjobscount"`
+	Readyforshutdown   bool   `json:"readyforshutdown"`
+	Shutdowntriggered  bool   `json:"shutdowntriggered"`
+}
diff --git a/cloudstack/ShutdownService_mock.go b/cloudstack/ShutdownService_mock.go
new file mode 100644
index 0000000..1cdd779
--- /dev/null
+++ b/cloudstack/ShutdownService_mock.go
@@ -0,0 +1,82 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: ./cloudstack/ShutdownService.go
+
+// Package cloudstack is a generated GoMock package.
+package cloudstack
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockShutdownServiceIface is a mock of ShutdownServiceIface interface.
+type MockShutdownServiceIface struct {
+	ctrl     *gomock.Controller
+	recorder *MockShutdownServiceIfaceMockRecorder
+}
+
+// MockShutdownServiceIfaceMockRecorder is the mock recorder for MockShutdownServiceIface.
+type MockShutdownServiceIfaceMockRecorder struct {
+	mock *MockShutdownServiceIface
+}
+
+// NewMockShutdownServiceIface creates a new mock instance.
+func NewMockShutdownServiceIface(ctrl *gomock.Controller) *MockShutdownServiceIface {
+	mock := &MockShutdownServiceIface{ctrl: ctrl}
+	mock.recorder = &MockShutdownServiceIfaceMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockShutdownServiceIface) EXPECT() *MockShutdownServiceIfaceMockRecorder {
+	return m.recorder
+}
+
+// NewReadyForShutdownParams mocks base method.
+func (m *MockShutdownServiceIface) NewReadyForShutdownParams() *ReadyForShutdownParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewReadyForShutdownParams")
+	ret0, _ := ret[0].(*ReadyForShutdownParams)
+	return ret0
+}
+
+// NewReadyForShutdownParams indicates an expected call of NewReadyForShutdownParams.
+func (mr *MockShutdownServiceIfaceMockRecorder) NewReadyForShutdownParams() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewReadyForShutdownParams", reflect.TypeOf((*MockShutdownServiceIface)(nil).NewReadyForShutdownParams))
+}
+
+// ReadyForShutdown mocks base method.
+func (m *MockShutdownServiceIface) ReadyForShutdown(p *ReadyForShutdownParams) (*ReadyForShutdownResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ReadyForShutdown", p)
+	ret0, _ := ret[0].(*ReadyForShutdownResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ReadyForShutdown indicates an expected call of ReadyForShutdown.
+func (mr *MockShutdownServiceIfaceMockRecorder) ReadyForShutdown(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadyForShutdown", reflect.TypeOf((*MockShutdownServiceIface)(nil).ReadyForShutdown), p)
+}
diff --git a/cloudstack/StoragePoolService.go b/cloudstack/StoragePoolService.go
index dd44985..7d2f647 100644
--- a/cloudstack/StoragePoolService.go
+++ b/cloudstack/StoragePoolService.go
@@ -21,8 +21,10 @@ package cloudstack
 
 import (
 	"encoding/json"
+	"fmt"
 	"net/url"
 	"strconv"
+	"strings"
 )
 
 type StoragePoolServiceIface interface {
@@ -32,6 +34,25 @@ type StoragePoolServiceIface interface {
 	NewEnableStorageMaintenanceParams(id string) *EnableStorageMaintenanceParams
 	ListStorageProviders(p *ListStorageProvidersParams) (*ListStorageProvidersResponse, error)
 	NewListStorageProvidersParams(storagePoolType string) *ListStorageProvidersParams
+	ListObjectStoragePools(p *ListObjectStoragePoolsParams) (*ListObjectStoragePoolsResponse, error)
+	NewListObjectStoragePoolsParams() *ListObjectStoragePoolsParams
+	GetObjectStoragePoolID(name string, opts ...OptionFunc) (string, int, error)
+	GetObjectStoragePoolByName(name string, opts ...OptionFunc) (*ObjectStoragePool, int, error)
+	GetObjectStoragePoolByID(id string, opts ...OptionFunc) (*ObjectStoragePool, int, error)
+	ListStoragePoolObjects(p *ListStoragePoolObjectsParams) (*ListStoragePoolObjectsResponse, error)
+	NewListStoragePoolObjectsParams(id string) *ListStoragePoolObjectsParams
+	GetStoragePoolObjectByID(id string, opts ...OptionFunc) (*StoragePoolObject, int, error)
+	UpdateObjectStoragePool(p *UpdateObjectStoragePoolParams) (*UpdateObjectStoragePoolResponse, error)
+	NewUpdateObjectStoragePoolParams(id string) *UpdateObjectStoragePoolParams
+	AddObjectStoragePool(p *AddObjectStoragePoolParams) (*AddObjectStoragePoolResponse, error)
+	NewAddObjectStoragePoolParams(name string, provider string, url string) *AddObjectStoragePoolParams
+	DeleteObjectStoragePool(p *DeleteObjectStoragePoolParams) (*DeleteObjectStoragePoolResponse, error)
+	NewDeleteObjectStoragePoolParams(id string) *DeleteObjectStoragePoolParams
+	ListStoragePoolsMetrics(p *ListStoragePoolsMetricsParams) (*ListStoragePoolsMetricsResponse, error)
+	NewListStoragePoolsMetricsParams() *ListStoragePoolsMetricsParams
+	GetStoragePoolsMetricID(name string, opts ...OptionFunc) (string, int, error)
+	GetStoragePoolsMetricByName(name string, opts ...OptionFunc) (*StoragePoolsMetric, int, error)
+	GetStoragePoolsMetricByID(id string, opts ...OptionFunc) (*StoragePoolsMetric, int, error)
 }
 
 type CancelStorageMaintenanceParams struct {
@@ -403,3 +424,1364 @@ type StorageProvider struct {
 	Name      string `json:"name"`
 	Type      string `json:"type"`
 }
+
+type ListObjectStoragePoolsParams struct {
+	p map[string]interface{}
+}
+
+func (p *ListObjectStoragePoolsParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	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)
+	}
+	if v, found := p.p["provider"]; found {
+		u.Set("provider", v.(string))
+	}
+	return u
+}
+
+func (p *ListObjectStoragePoolsParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *ListObjectStoragePoolsParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *ListObjectStoragePoolsParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+func (p *ListObjectStoragePoolsParams) SetKeyword(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["keyword"] = v
+}
+
+func (p *ListObjectStoragePoolsParams) ResetKeyword() {
+	if p.p != nil && p.p["keyword"] != nil {
+		delete(p.p, "keyword")
+	}
+}
+
+func (p *ListObjectStoragePoolsParams) GetKeyword() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["keyword"].(string)
+	return value, ok
+}
+
+func (p *ListObjectStoragePoolsParams) SetName(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["name"] = v
+}
+
+func (p *ListObjectStoragePoolsParams) ResetName() {
+	if p.p != nil && p.p["name"] != nil {
+		delete(p.p, "name")
+	}
+}
+
+func (p *ListObjectStoragePoolsParams) GetName() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["name"].(string)
+	return value, ok
+}
+
+func (p *ListObjectStoragePoolsParams) SetPage(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["page"] = v
+}
+
+func (p *ListObjectStoragePoolsParams) ResetPage() {
+	if p.p != nil && p.p["page"] != nil {
+		delete(p.p, "page")
+	}
+}
+
+func (p *ListObjectStoragePoolsParams) GetPage() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["page"].(int)
+	return value, ok
+}
+
+func (p *ListObjectStoragePoolsParams) SetPagesize(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["pagesize"] = v
+}
+
+func (p *ListObjectStoragePoolsParams) ResetPagesize() {
+	if p.p != nil && p.p["pagesize"] != nil {
+		delete(p.p, "pagesize")
+	}
+}
+
+func (p *ListObjectStoragePoolsParams) GetPagesize() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["pagesize"].(int)
+	return value, ok
+}
+
+func (p *ListObjectStoragePoolsParams) SetProvider(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["provider"] = v
+}
+
+func (p *ListObjectStoragePoolsParams) ResetProvider() {
+	if p.p != nil && p.p["provider"] != nil {
+		delete(p.p, "provider")
+	}
+}
+
+func (p *ListObjectStoragePoolsParams) GetProvider() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["provider"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new ListObjectStoragePoolsParams instance,
+// as then you are sure you have configured all required params
+func (s *StoragePoolService) NewListObjectStoragePoolsParams() *ListObjectStoragePoolsParams {
+	p := &ListObjectStoragePoolsParams{}
+	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 *StoragePoolService) GetObjectStoragePoolID(name string, opts ...OptionFunc) (string, int, error) {
+	p := &ListObjectStoragePoolsParams{}
+	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.ListObjectStoragePools(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.ObjectStoragePools[0].Id, l.Count, nil
+	}
+
+	if l.Count > 1 {
+		for _, v := range l.ObjectStoragePools {
+			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)
+}
+
+// This is a courtesy helper function, which in some cases may not work as expected!
+func (s *StoragePoolService) GetObjectStoragePoolByName(name string, opts ...OptionFunc) (*ObjectStoragePool, int, error) {
+	id, count, err := s.GetObjectStoragePoolID(name, opts...)
+	if err != nil {
+		return nil, count, err
+	}
+
+	r, count, err := s.GetObjectStoragePoolByID(id, opts...)
+	if err != nil {
+		return nil, count, err
+	}
+	return r, count, nil
+}
+
+// This is a courtesy helper function, which in some cases may not work as expected!
+func (s *StoragePoolService) GetObjectStoragePoolByID(id string, opts ...OptionFunc) (*ObjectStoragePool, int, error) {
+	p := &ListObjectStoragePoolsParams{}
+	p.p = make(map[string]interface{})
+
+	p.p["id"] = id
+
+	for _, fn := range append(s.cs.options, opts...) {
+		if err := fn(s.cs, p); err != nil {
+			return nil, -1, err
+		}
+	}
+
+	l, err := s.ListObjectStoragePools(p)
+	if err != nil {
+		if strings.Contains(err.Error(), fmt.Sprintf(
+			"Invalid parameter id value=%s due to incorrect long value format, "+
+				"or entity does not exist", id)) {
+			return nil, 0, fmt.Errorf("No match found for %s: %+v", id, l)
+		}
+		return nil, -1, err
+	}
+
+	if l.Count == 0 {
+		return nil, l.Count, fmt.Errorf("No match found for %s: %+v", id, l)
+	}
+
+	if l.Count == 1 {
+		return l.ObjectStoragePools[0], l.Count, nil
+	}
+	return nil, l.Count, fmt.Errorf("There is more then one result for ObjectStoragePool UUID: %s!", id)
+}
+
+// Lists object storage pools.
+func (s *StoragePoolService) ListObjectStoragePools(p *ListObjectStoragePoolsParams) (*ListObjectStoragePoolsResponse, error) {
+	resp, err := s.cs.newRequest("listObjectStoragePools", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r ListObjectStoragePoolsResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type ListObjectStoragePoolsResponse struct {
+	Count              int                  `json:"count"`
+	ObjectStoragePools []*ObjectStoragePool `json:"objectstore"`
+}
+
+type ObjectStoragePool struct {
+	Hasannotations bool   `json:"hasannotations"`
+	Id             string `json:"id"`
+	JobID          string `json:"jobid"`
+	Jobstatus      int    `json:"jobstatus"`
+	Name           string `json:"name"`
+	Providername   string `json:"providername"`
+	Storagetotal   int64  `json:"storagetotal"`
+	Storageused    int64  `json:"storageused"`
+	Url            string `json:"url"`
+}
+
+type ListStoragePoolObjectsParams struct {
+	p map[string]interface{}
+}
+
+func (p *ListStoragePoolObjectsParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	if v, found := p.p["keyword"]; found {
+		u.Set("keyword", 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)
+	}
+	if v, found := p.p["path"]; found {
+		u.Set("path", v.(string))
+	}
+	return u
+}
+
+func (p *ListStoragePoolObjectsParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *ListStoragePoolObjectsParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *ListStoragePoolObjectsParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+func (p *ListStoragePoolObjectsParams) SetKeyword(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["keyword"] = v
+}
+
+func (p *ListStoragePoolObjectsParams) ResetKeyword() {
+	if p.p != nil && p.p["keyword"] != nil {
+		delete(p.p, "keyword")
+	}
+}
+
+func (p *ListStoragePoolObjectsParams) GetKeyword() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["keyword"].(string)
+	return value, ok
+}
+
+func (p *ListStoragePoolObjectsParams) SetPage(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["page"] = v
+}
+
+func (p *ListStoragePoolObjectsParams) ResetPage() {
+	if p.p != nil && p.p["page"] != nil {
+		delete(p.p, "page")
+	}
+}
+
+func (p *ListStoragePoolObjectsParams) GetPage() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["page"].(int)
+	return value, ok
+}
+
+func (p *ListStoragePoolObjectsParams) SetPagesize(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["pagesize"] = v
+}
+
+func (p *ListStoragePoolObjectsParams) ResetPagesize() {
+	if p.p != nil && p.p["pagesize"] != nil {
+		delete(p.p, "pagesize")
+	}
+}
+
+func (p *ListStoragePoolObjectsParams) GetPagesize() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["pagesize"].(int)
+	return value, ok
+}
+
+func (p *ListStoragePoolObjectsParams) SetPath(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["path"] = v
+}
+
+func (p *ListStoragePoolObjectsParams) ResetPath() {
+	if p.p != nil && p.p["path"] != nil {
+		delete(p.p, "path")
+	}
+}
+
+func (p *ListStoragePoolObjectsParams) GetPath() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["path"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new ListStoragePoolObjectsParams instance,
+// as then you are sure you have configured all required params
+func (s *StoragePoolService) NewListStoragePoolObjectsParams(id string) *ListStoragePoolObjectsParams {
+	p := &ListStoragePoolObjectsParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	return p
+}
+
+// This is a courtesy helper function, which in some cases may not work as expected!
+func (s *StoragePoolService) GetStoragePoolObjectByID(id string, opts ...OptionFunc) (*StoragePoolObject, int, error) {
+	p := &ListStoragePoolObjectsParams{}
+	p.p = make(map[string]interface{})
+
+	p.p["id"] = id
+
+	for _, fn := range append(s.cs.options, opts...) {
+		if err := fn(s.cs, p); err != nil {
+			return nil, -1, err
+		}
+	}
+
+	l, err := s.ListStoragePoolObjects(p)
+	if err != nil {
+		if strings.Contains(err.Error(), fmt.Sprintf(
+			"Invalid parameter id value=%s due to incorrect long value format, "+
+				"or entity does not exist", id)) {
+			return nil, 0, fmt.Errorf("No match found for %s: %+v", id, l)
+		}
+		return nil, -1, err
+	}
+
+	if l.Count == 0 {
+		return nil, l.Count, fmt.Errorf("No match found for %s: %+v", id, l)
+	}
+
+	if l.Count == 1 {
+		return l.StoragePoolObjects[0], l.Count, nil
+	}
+	return nil, l.Count, fmt.Errorf("There is more then one result for StoragePoolObject UUID: %s!", id)
+}
+
+// Lists objects at specified path on a storage pool.
+func (s *StoragePoolService) ListStoragePoolObjects(p *ListStoragePoolObjectsParams) (*ListStoragePoolObjectsResponse, error) {
+	resp, err := s.cs.newRequest("listStoragePoolObjects", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r ListStoragePoolObjectsResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type ListStoragePoolObjectsResponse struct {
+	Count              int                  `json:"count"`
+	StoragePoolObjects []*StoragePoolObject `json:"datastoreobject"`
+}
+
+type StoragePoolObject struct {
+	Format      string `json:"format"`
+	Isdirectory bool   `json:"isdirectory"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Lastupdated string `json:"lastupdated"`
+	Name        string `json:"name"`
+	Size        int64  `json:"size"`
+	Snapshotid  string `json:"snapshotid"`
+	Templateid  string `json:"templateid"`
+	Volumeid    string `json:"volumeid"`
+}
+
+type UpdateObjectStoragePoolParams struct {
+	p map[string]interface{}
+}
+
+func (p *UpdateObjectStoragePoolParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	if v, found := p.p["name"]; found {
+		u.Set("name", v.(string))
+	}
+	if v, found := p.p["url"]; found {
+		u.Set("url", v.(string))
+	}
+	return u
+}
+
+func (p *UpdateObjectStoragePoolParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *UpdateObjectStoragePoolParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *UpdateObjectStoragePoolParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+func (p *UpdateObjectStoragePoolParams) SetName(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["name"] = v
+}
+
+func (p *UpdateObjectStoragePoolParams) ResetName() {
+	if p.p != nil && p.p["name"] != nil {
+		delete(p.p, "name")
+	}
+}
+
+func (p *UpdateObjectStoragePoolParams) GetName() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["name"].(string)
+	return value, ok
+}
+
+func (p *UpdateObjectStoragePoolParams) SetUrl(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["url"] = v
+}
+
+func (p *UpdateObjectStoragePoolParams) ResetUrl() {
+	if p.p != nil && p.p["url"] != nil {
+		delete(p.p, "url")
+	}
+}
+
+func (p *UpdateObjectStoragePoolParams) GetUrl() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["url"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new UpdateObjectStoragePoolParams instance,
+// as then you are sure you have configured all required params
+func (s *StoragePoolService) NewUpdateObjectStoragePoolParams(id string) *UpdateObjectStoragePoolParams {
+	p := &UpdateObjectStoragePoolParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	return p
+}
+
+// Updates object storage pool
+func (s *StoragePoolService) UpdateObjectStoragePool(p *UpdateObjectStoragePoolParams) (*UpdateObjectStoragePoolResponse, error) {
+	resp, err := s.cs.newRequest("updateObjectStoragePool", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var nested struct {
+		Response UpdateObjectStoragePoolResponse `json:"objectstore"`
+	}
+	if err := json.Unmarshal(resp, &nested); err != nil {
+		return nil, err
+	}
+	r := nested.Response
+
+	return &r, nil
+}
+
+type UpdateObjectStoragePoolResponse struct {
+	Hasannotations bool   `json:"hasannotations"`
+	Id             string `json:"id"`
+	JobID          string `json:"jobid"`
+	Jobstatus      int    `json:"jobstatus"`
+	Name           string `json:"name"`
+	Providername   string `json:"providername"`
+	Storagetotal   int64  `json:"storagetotal"`
+	Storageused    int64  `json:"storageused"`
+	Url            string `json:"url"`
+}
+
+type AddObjectStoragePoolParams struct {
+	p map[string]interface{}
+}
+
+func (p *AddObjectStoragePoolParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["details"]; found {
+		m := v.(map[string]string)
+		for i, k := range getSortedKeysFromMap(m) {
+			u.Set(fmt.Sprintf("details[%d].key", i), k)
+			u.Set(fmt.Sprintf("details[%d].value", i), m[k])
+		}
+	}
+	if v, found := p.p["name"]; found {
+		u.Set("name", v.(string))
+	}
+	if v, found := p.p["provider"]; found {
+		u.Set("provider", v.(string))
+	}
+	if v, found := p.p["tags"]; found {
+		u.Set("tags", v.(string))
+	}
+	if v, found := p.p["url"]; found {
+		u.Set("url", v.(string))
+	}
+	return u
+}
+
+func (p *AddObjectStoragePoolParams) SetDetails(v map[string]string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["details"] = v
+}
+
+func (p *AddObjectStoragePoolParams) ResetDetails() {
+	if p.p != nil && p.p["details"] != nil {
+		delete(p.p, "details")
+	}
+}
+
+func (p *AddObjectStoragePoolParams) GetDetails() (map[string]string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["details"].(map[string]string)
+	return value, ok
+}
+
+func (p *AddObjectStoragePoolParams) SetName(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["name"] = v
+}
+
+func (p *AddObjectStoragePoolParams) ResetName() {
+	if p.p != nil && p.p["name"] != nil {
+		delete(p.p, "name")
+	}
+}
+
+func (p *AddObjectStoragePoolParams) GetName() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["name"].(string)
+	return value, ok
+}
+
+func (p *AddObjectStoragePoolParams) SetProvider(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["provider"] = v
+}
+
+func (p *AddObjectStoragePoolParams) ResetProvider() {
+	if p.p != nil && p.p["provider"] != nil {
+		delete(p.p, "provider")
+	}
+}
+
+func (p *AddObjectStoragePoolParams) GetProvider() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["provider"].(string)
+	return value, ok
+}
+
+func (p *AddObjectStoragePoolParams) SetTags(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["tags"] = v
+}
+
+func (p *AddObjectStoragePoolParams) ResetTags() {
+	if p.p != nil && p.p["tags"] != nil {
+		delete(p.p, "tags")
+	}
+}
+
+func (p *AddObjectStoragePoolParams) GetTags() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["tags"].(string)
+	return value, ok
+}
+
+func (p *AddObjectStoragePoolParams) SetUrl(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["url"] = v
+}
+
+func (p *AddObjectStoragePoolParams) ResetUrl() {
+	if p.p != nil && p.p["url"] != nil {
+		delete(p.p, "url")
+	}
+}
+
+func (p *AddObjectStoragePoolParams) GetUrl() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["url"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new AddObjectStoragePoolParams instance,
+// as then you are sure you have configured all required params
+func (s *StoragePoolService) NewAddObjectStoragePoolParams(name string, provider string, url string) *AddObjectStoragePoolParams {
+	p := &AddObjectStoragePoolParams{}
+	p.p = make(map[string]interface{})
+	p.p["name"] = name
+	p.p["provider"] = provider
+	p.p["url"] = url
+	return p
+}
+
+// Adds a object storage pool
+func (s *StoragePoolService) AddObjectStoragePool(p *AddObjectStoragePoolParams) (*AddObjectStoragePoolResponse, error) {
+	resp, err := s.cs.newRequest("addObjectStoragePool", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var nested struct {
+		Response AddObjectStoragePoolResponse `json:"objectstore"`
+	}
+	if err := json.Unmarshal(resp, &nested); err != nil {
+		return nil, err
+	}
+	r := nested.Response
+
+	return &r, nil
+}
+
+type AddObjectStoragePoolResponse struct {
+	Hasannotations bool   `json:"hasannotations"`
+	Id             string `json:"id"`
+	JobID          string `json:"jobid"`
+	Jobstatus      int    `json:"jobstatus"`
+	Name           string `json:"name"`
+	Providername   string `json:"providername"`
+	Storagetotal   int64  `json:"storagetotal"`
+	Storageused    int64  `json:"storageused"`
+	Url            string `json:"url"`
+}
+
+type DeleteObjectStoragePoolParams struct {
+	p map[string]interface{}
+}
+
+func (p *DeleteObjectStoragePoolParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	return u
+}
+
+func (p *DeleteObjectStoragePoolParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *DeleteObjectStoragePoolParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *DeleteObjectStoragePoolParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new DeleteObjectStoragePoolParams instance,
+// as then you are sure you have configured all required params
+func (s *StoragePoolService) NewDeleteObjectStoragePoolParams(id string) *DeleteObjectStoragePoolParams {
+	p := &DeleteObjectStoragePoolParams{}
+	p.p = make(map[string]interface{})
+	p.p["id"] = id
+	return p
+}
+
+// Deletes an Object Storage Pool
+func (s *StoragePoolService) DeleteObjectStoragePool(p *DeleteObjectStoragePoolParams) (*DeleteObjectStoragePoolResponse, error) {
+	resp, err := s.cs.newRequest("deleteObjectStoragePool", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r DeleteObjectStoragePoolResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type DeleteObjectStoragePoolResponse struct {
+	Displaytext string `json:"displaytext"`
+	JobID       string `json:"jobid"`
+	Jobstatus   int    `json:"jobstatus"`
+	Success     bool   `json:"success"`
+}
+
+func (r *DeleteObjectStoragePoolResponse) UnmarshalJSON(b []byte) error {
+	var m map[string]interface{}
+	err := json.Unmarshal(b, &m)
+	if err != nil {
+		return err
+	}
+
+	if success, ok := m["success"].(string); ok {
+		m["success"] = success == "true"
+		b, err = json.Marshal(m)
+		if err != nil {
+			return err
+		}
+	}
+
+	if ostypeid, ok := m["ostypeid"].(float64); ok {
+		m["ostypeid"] = strconv.Itoa(int(ostypeid))
+		b, err = json.Marshal(m)
+		if err != nil {
+			return err
+		}
+	}
+
+	type alias DeleteObjectStoragePoolResponse
+	return json.Unmarshal(b, (*alias)(r))
+}
+
+type ListStoragePoolsMetricsParams struct {
+	p map[string]interface{}
+}
+
+func (p *ListStoragePoolsMetricsParams) 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["id"]; found {
+		u.Set("id", v.(string))
+	}
+	if v, found := p.p["ipaddress"]; found {
+		u.Set("ipaddress", v.(string))
+	}
+	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)
+	}
+	if v, found := p.p["path"]; found {
+		u.Set("path", v.(string))
+	}
+	if v, found := p.p["podid"]; found {
+		u.Set("podid", v.(string))
+	}
+	if v, found := p.p["scope"]; found {
+		u.Set("scope", v.(string))
+	}
+	if v, found := p.p["status"]; found {
+		u.Set("status", v.(string))
+	}
+	if v, found := p.p["zoneid"]; found {
+		u.Set("zoneid", v.(string))
+	}
+	return u
+}
+
+func (p *ListStoragePoolsMetricsParams) SetClusterid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["clusterid"] = v
+}
+
+func (p *ListStoragePoolsMetricsParams) ResetClusterid() {
+	if p.p != nil && p.p["clusterid"] != nil {
+		delete(p.p, "clusterid")
+	}
+}
+
+func (p *ListStoragePoolsMetricsParams) GetClusterid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["clusterid"].(string)
+	return value, ok
+}
+
+func (p *ListStoragePoolsMetricsParams) SetHostid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["hostid"] = v
+}
+
+func (p *ListStoragePoolsMetricsParams) ResetHostid() {
+	if p.p != nil && p.p["hostid"] != nil {
+		delete(p.p, "hostid")
+	}
+}
+
+func (p *ListStoragePoolsMetricsParams) GetHostid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["hostid"].(string)
+	return value, ok
+}
+
+func (p *ListStoragePoolsMetricsParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *ListStoragePoolsMetricsParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *ListStoragePoolsMetricsParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+func (p *ListStoragePoolsMetricsParams) SetIpaddress(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["ipaddress"] = v
+}
+
+func (p *ListStoragePoolsMetricsParams) ResetIpaddress() {
+	if p.p != nil && p.p["ipaddress"] != nil {
+		delete(p.p, "ipaddress")
+	}
+}
+
+func (p *ListStoragePoolsMetricsParams) GetIpaddress() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["ipaddress"].(string)
+	return value, ok
+}
+
+func (p *ListStoragePoolsMetricsParams) SetKeyword(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["keyword"] = v
+}
+
+func (p *ListStoragePoolsMetricsParams) ResetKeyword() {
+	if p.p != nil && p.p["keyword"] != nil {
+		delete(p.p, "keyword")
+	}
+}
+
+func (p *ListStoragePoolsMetricsParams) GetKeyword() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["keyword"].(string)
+	return value, ok
+}
+
+func (p *ListStoragePoolsMetricsParams) SetName(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["name"] = v
+}
+
+func (p *ListStoragePoolsMetricsParams) ResetName() {
+	if p.p != nil && p.p["name"] != nil {
+		delete(p.p, "name")
+	}
+}
+
+func (p *ListStoragePoolsMetricsParams) GetName() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["name"].(string)
+	return value, ok
+}
+
+func (p *ListStoragePoolsMetricsParams) SetPage(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["page"] = v
+}
+
+func (p *ListStoragePoolsMetricsParams) ResetPage() {
+	if p.p != nil && p.p["page"] != nil {
+		delete(p.p, "page")
+	}
+}
+
+func (p *ListStoragePoolsMetricsParams) GetPage() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["page"].(int)
+	return value, ok
+}
+
+func (p *ListStoragePoolsMetricsParams) SetPagesize(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["pagesize"] = v
+}
+
+func (p *ListStoragePoolsMetricsParams) ResetPagesize() {
+	if p.p != nil && p.p["pagesize"] != nil {
+		delete(p.p, "pagesize")
+	}
+}
+
+func (p *ListStoragePoolsMetricsParams) GetPagesize() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["pagesize"].(int)
+	return value, ok
+}
+
+func (p *ListStoragePoolsMetricsParams) SetPath(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["path"] = v
+}
+
+func (p *ListStoragePoolsMetricsParams) ResetPath() {
+	if p.p != nil && p.p["path"] != nil {
+		delete(p.p, "path")
+	}
+}
+
+func (p *ListStoragePoolsMetricsParams) GetPath() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["path"].(string)
+	return value, ok
+}
+
+func (p *ListStoragePoolsMetricsParams) SetPodid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["podid"] = v
+}
+
+func (p *ListStoragePoolsMetricsParams) ResetPodid() {
+	if p.p != nil && p.p["podid"] != nil {
+		delete(p.p, "podid")
+	}
+}
+
+func (p *ListStoragePoolsMetricsParams) GetPodid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["podid"].(string)
+	return value, ok
+}
+
+func (p *ListStoragePoolsMetricsParams) SetScope(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["scope"] = v
+}
+
+func (p *ListStoragePoolsMetricsParams) ResetScope() {
+	if p.p != nil && p.p["scope"] != nil {
+		delete(p.p, "scope")
+	}
+}
+
+func (p *ListStoragePoolsMetricsParams) GetScope() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["scope"].(string)
+	return value, ok
+}
+
+func (p *ListStoragePoolsMetricsParams) SetStatus(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["status"] = v
+}
+
+func (p *ListStoragePoolsMetricsParams) ResetStatus() {
+	if p.p != nil && p.p["status"] != nil {
+		delete(p.p, "status")
+	}
+}
+
+func (p *ListStoragePoolsMetricsParams) GetStatus() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["status"].(string)
+	return value, ok
+}
+
+func (p *ListStoragePoolsMetricsParams) SetZoneid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["zoneid"] = v
+}
+
+func (p *ListStoragePoolsMetricsParams) ResetZoneid() {
+	if p.p != nil && p.p["zoneid"] != nil {
+		delete(p.p, "zoneid")
+	}
+}
+
+func (p *ListStoragePoolsMetricsParams) 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 ListStoragePoolsMetricsParams instance,
+// as then you are sure you have configured all required params
+func (s *StoragePoolService) NewListStoragePoolsMetricsParams() *ListStoragePoolsMetricsParams {
+	p := &ListStoragePoolsMetricsParams{}
+	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 *StoragePoolService) GetStoragePoolsMetricID(name string, opts ...OptionFunc) (string, int, error) {
+	p := &ListStoragePoolsMetricsParams{}
+	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.ListStoragePoolsMetrics(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.StoragePoolsMetrics[0].Id, l.Count, nil
+	}
+
+	if l.Count > 1 {
+		for _, v := range l.StoragePoolsMetrics {
+			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)
+}
+
+// This is a courtesy helper function, which in some cases may not work as expected!
+func (s *StoragePoolService) GetStoragePoolsMetricByName(name string, opts ...OptionFunc) (*StoragePoolsMetric, int, error) {
+	id, count, err := s.GetStoragePoolsMetricID(name, opts...)
+	if err != nil {
+		return nil, count, err
+	}
+
+	r, count, err := s.GetStoragePoolsMetricByID(id, opts...)
+	if err != nil {
+		return nil, count, err
+	}
+	return r, count, nil
+}
+
+// This is a courtesy helper function, which in some cases may not work as expected!
+func (s *StoragePoolService) GetStoragePoolsMetricByID(id string, opts ...OptionFunc) (*StoragePoolsMetric, int, error) {
+	p := &ListStoragePoolsMetricsParams{}
+	p.p = make(map[string]interface{})
+
+	p.p["id"] = id
+
+	for _, fn := range append(s.cs.options, opts...) {
+		if err := fn(s.cs, p); err != nil {
+			return nil, -1, err
+		}
+	}
+
+	l, err := s.ListStoragePoolsMetrics(p)
+	if err != nil {
+		if strings.Contains(err.Error(), fmt.Sprintf(
+			"Invalid parameter id value=%s due to incorrect long value format, "+
+				"or entity does not exist", id)) {
+			return nil, 0, fmt.Errorf("No match found for %s: %+v", id, l)
+		}
+		return nil, -1, err
+	}
+
+	if l.Count == 0 {
+		return nil, l.Count, fmt.Errorf("No match found for %s: %+v", id, l)
+	}
+
+	if l.Count == 1 {
+		return l.StoragePoolsMetrics[0], l.Count, nil
+	}
+	return nil, l.Count, fmt.Errorf("There is more then one result for StoragePoolsMetric UUID: %s!", id)
+}
+
+// Lists storage pool metrics
+func (s *StoragePoolService) ListStoragePoolsMetrics(p *ListStoragePoolsMetricsParams) (*ListStoragePoolsMetricsResponse, error) {
+	resp, err := s.cs.newRequest("listStoragePoolsMetrics", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var r ListStoragePoolsMetricsResponse
+	if err := json.Unmarshal(resp, &r); err != nil {
+		return nil, err
+	}
+
+	return &r, nil
+}
+
+type ListStoragePoolsMetricsResponse struct {
+	Count               int                   `json:"count"`
+	StoragePoolsMetrics []*StoragePoolsMetric `json:"storagepool"`
+}
+
+type StoragePoolsMetric struct {
+	Allocatediops                    int64             `json:"allocatediops"`
+	Capacityiops                     int64             `json:"capacityiops"`
+	Clusterid                        string            `json:"clusterid"`
+	Clustername                      string            `json:"clustername"`
+	Created                          string            `json:"created"`
+	Disksizeallocated                int64             `json:"disksizeallocated"`
+	Disksizeallocatedgb              string            `json:"disksizeallocatedgb"`
+	Disksizetotal                    int64             `json:"disksizetotal"`
+	Disksizetotalgb                  string            `json:"disksizetotalgb"`
+	Disksizeunallocatedgb            string            `json:"disksizeunallocatedgb"`
+	Disksizeused                     int64             `json:"disksizeused"`
+	Disksizeusedgb                   string            `json:"disksizeusedgb"`
+	Hasannotations                   bool              `json:"hasannotations"`
+	Hypervisor                       string            `json:"hypervisor"`
+	Id                               string            `json:"id"`
+	Ipaddress                        string            `json:"ipaddress"`
+	Istagarule                       bool              `json:"istagarule"`
+	JobID                            string            `json:"jobid"`
+	Jobstatus                        int               `json:"jobstatus"`
+	Name                             string            `json:"name"`
+	Overprovisionfactor              string            `json:"overprovisionfactor"`
+	Path                             string            `json:"path"`
+	Podid                            string            `json:"podid"`
+	Podname                          string            `json:"podname"`
+	Provider                         string            `json:"provider"`
+	Scope                            string            `json:"scope"`
+	State                            string            `json:"state"`
+	Storageallocateddisablethreshold bool              `json:"storageallocateddisablethreshold"`
+	Storageallocatedthreshold        bool              `json:"storageallocatedthreshold"`
+	Storagecapabilities              map[string]string `json:"storagecapabilities"`
+	Storageusagedisablethreshold     bool              `json:"storageusagedisablethreshold"`
+	Storageusagethreshold            bool              `json:"storageusagethreshold"`
+	Suitableformigration             bool              `json:"suitableformigration"`
+	Tags                             string            `json:"tags"`
+	Type                             string            `json:"type"`
+	Zoneid                           string            `json:"zoneid"`
+	Zonename                         string            `json:"zonename"`
+}
diff --git a/cloudstack/StoragePoolService_mock.go b/cloudstack/StoragePoolService_mock.go
index 607e3cf..6825800 100644
--- a/cloudstack/StoragePoolService_mock.go
+++ b/cloudstack/StoragePoolService_mock.go
@@ -52,6 +52,21 @@ func (m *MockStoragePoolServiceIface) EXPECT() *MockStoragePoolServiceIfaceMockR
 	return m.recorder
 }
 
+// AddObjectStoragePool mocks base method.
+func (m *MockStoragePoolServiceIface) AddObjectStoragePool(p *AddObjectStoragePoolParams) (*AddObjectStoragePoolResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "AddObjectStoragePool", p)
+	ret0, _ := ret[0].(*AddObjectStoragePoolResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// AddObjectStoragePool indicates an expected call of AddObjectStoragePool.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) AddObjectStoragePool(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddObjectStoragePool", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).AddObjectStoragePool), p)
+}
+
 // CancelStorageMaintenance mocks base method.
 func (m *MockStoragePoolServiceIface) CancelStorageMaintenance(p *CancelStorageMaintenanceParams) (*CancelStorageMaintenanceResponse, error) {
 	m.ctrl.T.Helper()
@@ -67,6 +82,21 @@ func (mr *MockStoragePoolServiceIfaceMockRecorder) CancelStorageMaintenance(p in
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CancelStorageMaintenance", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).CancelStorageMaintenance), p)
 }
 
+// DeleteObjectStoragePool mocks base method.
+func (m *MockStoragePoolServiceIface) DeleteObjectStoragePool(p *DeleteObjectStoragePoolParams) (*DeleteObjectStoragePoolResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DeleteObjectStoragePool", p)
+	ret0, _ := ret[0].(*DeleteObjectStoragePoolResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// DeleteObjectStoragePool indicates an expected call of DeleteObjectStoragePool.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) DeleteObjectStoragePool(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteObjectStoragePool", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).DeleteObjectStoragePool), p)
+}
+
 // EnableStorageMaintenance mocks base method.
 func (m *MockStoragePoolServiceIface) EnableStorageMaintenance(p *EnableStorageMaintenanceParams) (*EnableStorageMaintenanceResponse, error) {
 	m.ctrl.T.Helper()
@@ -82,6 +112,198 @@ func (mr *MockStoragePoolServiceIfaceMockRecorder) EnableStorageMaintenance(p in
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnableStorageMaintenance", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).EnableStorageMaintenance), p)
 }
 
+// GetObjectStoragePoolByID mocks base method.
+func (m *MockStoragePoolServiceIface) GetObjectStoragePoolByID(id string, opts ...OptionFunc) (*ObjectStoragePool, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{id}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetObjectStoragePoolByID", varargs...)
+	ret0, _ := ret[0].(*ObjectStoragePool)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetObjectStoragePoolByID indicates an expected call of GetObjectStoragePoolByID.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) GetObjectStoragePoolByID(id interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{id}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObjectStoragePoolByID", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).GetObjectStoragePoolByID), varargs...)
+}
+
+// GetObjectStoragePoolByName mocks base method.
+func (m *MockStoragePoolServiceIface) GetObjectStoragePoolByName(name string, opts ...OptionFunc) (*ObjectStoragePool, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{name}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetObjectStoragePoolByName", varargs...)
+	ret0, _ := ret[0].(*ObjectStoragePool)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetObjectStoragePoolByName indicates an expected call of GetObjectStoragePoolByName.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) GetObjectStoragePoolByName(name interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{name}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObjectStoragePoolByName", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).GetObjectStoragePoolByName), varargs...)
+}
+
+// GetObjectStoragePoolID mocks base method.
+func (m *MockStoragePoolServiceIface) GetObjectStoragePoolID(name string, opts ...OptionFunc) (string, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{name}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetObjectStoragePoolID", varargs...)
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetObjectStoragePoolID indicates an expected call of GetObjectStoragePoolID.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) GetObjectStoragePoolID(name interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{name}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObjectStoragePoolID", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).GetObjectStoragePoolID), varargs...)
+}
+
+// GetStoragePoolObjectByID mocks base method.
+func (m *MockStoragePoolServiceIface) GetStoragePoolObjectByID(id string, opts ...OptionFunc) (*StoragePoolObject, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{id}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetStoragePoolObjectByID", varargs...)
+	ret0, _ := ret[0].(*StoragePoolObject)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetStoragePoolObjectByID indicates an expected call of GetStoragePoolObjectByID.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) GetStoragePoolObjectByID(id interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{id}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStoragePoolObjectByID", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).GetStoragePoolObjectByID), varargs...)
+}
+
+// GetStoragePoolsMetricByID mocks base method.
+func (m *MockStoragePoolServiceIface) GetStoragePoolsMetricByID(id string, opts ...OptionFunc) (*StoragePoolsMetric, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{id}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetStoragePoolsMetricByID", varargs...)
+	ret0, _ := ret[0].(*StoragePoolsMetric)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetStoragePoolsMetricByID indicates an expected call of GetStoragePoolsMetricByID.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) GetStoragePoolsMetricByID(id interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{id}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStoragePoolsMetricByID", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).GetStoragePoolsMetricByID), varargs...)
+}
+
+// GetStoragePoolsMetricByName mocks base method.
+func (m *MockStoragePoolServiceIface) GetStoragePoolsMetricByName(name string, opts ...OptionFunc) (*StoragePoolsMetric, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{name}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetStoragePoolsMetricByName", varargs...)
+	ret0, _ := ret[0].(*StoragePoolsMetric)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetStoragePoolsMetricByName indicates an expected call of GetStoragePoolsMetricByName.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) GetStoragePoolsMetricByName(name interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{name}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStoragePoolsMetricByName", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).GetStoragePoolsMetricByName), varargs...)
+}
+
+// GetStoragePoolsMetricID mocks base method.
+func (m *MockStoragePoolServiceIface) GetStoragePoolsMetricID(name string, opts ...OptionFunc) (string, int, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{name}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "GetStoragePoolsMetricID", varargs...)
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(int)
+	ret2, _ := ret[2].(error)
+	return ret0, ret1, ret2
+}
+
+// GetStoragePoolsMetricID indicates an expected call of GetStoragePoolsMetricID.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) GetStoragePoolsMetricID(name interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{name}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStoragePoolsMetricID", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).GetStoragePoolsMetricID), varargs...)
+}
+
+// ListObjectStoragePools mocks base method.
+func (m *MockStoragePoolServiceIface) ListObjectStoragePools(p *ListObjectStoragePoolsParams) (*ListObjectStoragePoolsResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ListObjectStoragePools", p)
+	ret0, _ := ret[0].(*ListObjectStoragePoolsResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListObjectStoragePools indicates an expected call of ListObjectStoragePools.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) ListObjectStoragePools(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListObjectStoragePools", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).ListObjectStoragePools), p)
+}
+
+// ListStoragePoolObjects mocks base method.
+func (m *MockStoragePoolServiceIface) ListStoragePoolObjects(p *ListStoragePoolObjectsParams) (*ListStoragePoolObjectsResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ListStoragePoolObjects", p)
+	ret0, _ := ret[0].(*ListStoragePoolObjectsResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListStoragePoolObjects indicates an expected call of ListStoragePoolObjects.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) ListStoragePoolObjects(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStoragePoolObjects", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).ListStoragePoolObjects), p)
+}
+
+// ListStoragePoolsMetrics mocks base method.
+func (m *MockStoragePoolServiceIface) ListStoragePoolsMetrics(p *ListStoragePoolsMetricsParams) (*ListStoragePoolsMetricsResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ListStoragePoolsMetrics", p)
+	ret0, _ := ret[0].(*ListStoragePoolsMetricsResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListStoragePoolsMetrics indicates an expected call of ListStoragePoolsMetrics.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) ListStoragePoolsMetrics(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStoragePoolsMetrics", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).ListStoragePoolsMetrics), p)
+}
+
 // ListStorageProviders mocks base method.
 func (m *MockStoragePoolServiceIface) ListStorageProviders(p *ListStorageProvidersParams) (*ListStorageProvidersResponse, error) {
 	m.ctrl.T.Helper()
@@ -97,6 +319,20 @@ func (mr *MockStoragePoolServiceIfaceMockRecorder) ListStorageProviders(p interf
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStorageProviders", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).ListStorageProviders), p)
 }
 
+// NewAddObjectStoragePoolParams mocks base method.
+func (m *MockStoragePoolServiceIface) NewAddObjectStoragePoolParams(name, provider, url string) *AddObjectStoragePoolParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewAddObjectStoragePoolParams", name, provider, url)
+	ret0, _ := ret[0].(*AddObjectStoragePoolParams)
+	return ret0
+}
+
+// NewAddObjectStoragePoolParams indicates an expected call of NewAddObjectStoragePoolParams.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) NewAddObjectStoragePoolParams(name, provider, url interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewAddObjectStoragePoolParams", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).NewAddObjectStoragePoolParams), name, provider, url)
+}
+
 // NewCancelStorageMaintenanceParams mocks base method.
 func (m *MockStoragePoolServiceIface) NewCancelStorageMaintenanceParams(id string) *CancelStorageMaintenanceParams {
 	m.ctrl.T.Helper()
@@ -111,6 +347,20 @@ func (mr *MockStoragePoolServiceIfaceMockRecorder) NewCancelStorageMaintenancePa
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewCancelStorageMaintenanceParams", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).NewCancelStorageMaintenanceParams), id)
 }
 
+// NewDeleteObjectStoragePoolParams mocks base method.
+func (m *MockStoragePoolServiceIface) NewDeleteObjectStoragePoolParams(id string) *DeleteObjectStoragePoolParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewDeleteObjectStoragePoolParams", id)
+	ret0, _ := ret[0].(*DeleteObjectStoragePoolParams)
+	return ret0
+}
+
+// NewDeleteObjectStoragePoolParams indicates an expected call of NewDeleteObjectStoragePoolParams.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) NewDeleteObjectStoragePoolParams(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewDeleteObjectStoragePoolParams", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).NewDeleteObjectStoragePoolParams), id)
+}
+
 // NewEnableStorageMaintenanceParams mocks base method.
 func (m *MockStoragePoolServiceIface) NewEnableStorageMaintenanceParams(id string) *EnableStorageMaintenanceParams {
 	m.ctrl.T.Helper()
@@ -125,6 +375,48 @@ func (mr *MockStoragePoolServiceIfaceMockRecorder) NewEnableStorageMaintenancePa
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewEnableStorageMaintenanceParams", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).NewEnableStorageMaintenanceParams), id)
 }
 
+// NewListObjectStoragePoolsParams mocks base method.
+func (m *MockStoragePoolServiceIface) NewListObjectStoragePoolsParams() *ListObjectStoragePoolsParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewListObjectStoragePoolsParams")
+	ret0, _ := ret[0].(*ListObjectStoragePoolsParams)
+	return ret0
+}
+
+// NewListObjectStoragePoolsParams indicates an expected call of NewListObjectStoragePoolsParams.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) NewListObjectStoragePoolsParams() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListObjectStoragePoolsParams", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).NewListObjectStoragePoolsParams))
+}
+
+// NewListStoragePoolObjectsParams mocks base method.
+func (m *MockStoragePoolServiceIface) NewListStoragePoolObjectsParams(id string) *ListStoragePoolObjectsParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewListStoragePoolObjectsParams", id)
+	ret0, _ := ret[0].(*ListStoragePoolObjectsParams)
+	return ret0
+}
+
+// NewListStoragePoolObjectsParams indicates an expected call of NewListStoragePoolObjectsParams.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) NewListStoragePoolObjectsParams(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListStoragePoolObjectsParams", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).NewListStoragePoolObjectsParams), id)
+}
+
+// NewListStoragePoolsMetricsParams mocks base method.
+func (m *MockStoragePoolServiceIface) NewListStoragePoolsMetricsParams() *ListStoragePoolsMetricsParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewListStoragePoolsMetricsParams")
+	ret0, _ := ret[0].(*ListStoragePoolsMetricsParams)
+	return ret0
+}
+
+// NewListStoragePoolsMetricsParams indicates an expected call of NewListStoragePoolsMetricsParams.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) NewListStoragePoolsMetricsParams() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListStoragePoolsMetricsParams", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).NewListStoragePoolsMetricsParams))
+}
+
 // NewListStorageProvidersParams mocks base method.
 func (m *MockStoragePoolServiceIface) NewListStorageProvidersParams(storagePoolType string) *ListStorageProvidersParams {
 	m.ctrl.T.Helper()
@@ -138,3 +430,32 @@ func (mr *MockStoragePoolServiceIfaceMockRecorder) NewListStorageProvidersParams
 	mr.mock.ctrl.T.Helper()
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListStorageProvidersParams", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).NewListStorageProvidersParams), storagePoolType)
 }
+
+// NewUpdateObjectStoragePoolParams mocks base method.
+func (m *MockStoragePoolServiceIface) NewUpdateObjectStoragePoolParams(id string) *UpdateObjectStoragePoolParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewUpdateObjectStoragePoolParams", id)
+	ret0, _ := ret[0].(*UpdateObjectStoragePoolParams)
+	return ret0
+}
+
+// NewUpdateObjectStoragePoolParams indicates an expected call of NewUpdateObjectStoragePoolParams.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) NewUpdateObjectStoragePoolParams(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewUpdateObjectStoragePoolParams", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).NewUpdateObjectStoragePoolParams), id)
+}
+
+// UpdateObjectStoragePool mocks base method.
+func (m *MockStoragePoolServiceIface) UpdateObjectStoragePool(p *UpdateObjectStoragePoolParams) (*UpdateObjectStoragePoolResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "UpdateObjectStoragePool", p)
+	ret0, _ := ret[0].(*UpdateObjectStoragePoolResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// UpdateObjectStoragePool indicates an expected call of UpdateObjectStoragePool.
+func (mr *MockStoragePoolServiceIfaceMockRecorder) UpdateObjectStoragePool(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateObjectStoragePool", reflect.TypeOf((*MockStoragePoolServiceIface)(nil).UpdateObjectStoragePool), p)
+}
diff --git a/cloudstack/TemplateService.go b/cloudstack/TemplateService.go
index dd4edf2..677b28f 100644
--- a/cloudstack/TemplateService.go
+++ b/cloudstack/TemplateService.go
@@ -61,6 +61,8 @@ type TemplateServiceIface interface {
 	GetTemplateDirectDownloadCertificateByID(id string, opts ...OptionFunc) (*TemplateDirectDownloadCertificate, int, error)
 	ProvisionTemplateDirectDownloadCertificate(p *ProvisionTemplateDirectDownloadCertificateParams) (*ProvisionTemplateDirectDownloadCertificateResponse, error)
 	NewProvisionTemplateDirectDownloadCertificateParams(hostid string, id string) *ProvisionTemplateDirectDownloadCertificateParams
+	LinkUserDataToTemplate(p *LinkUserDataToTemplateParams) (*LinkUserDataToTemplateResponse, error)
+	NewLinkUserDataToTemplateParams() *LinkUserDataToTemplateParams
 }
 
 type CopyTemplateParams struct {
@@ -4946,3 +4948,221 @@ type ProvisionTemplateDirectDownloadCertificateResponse struct {
 	Jobstatus int    `json:"jobstatus"`
 	Status    string `json:"status"`
 }
+
+type LinkUserDataToTemplateParams struct {
+	p map[string]interface{}
+}
+
+func (p *LinkUserDataToTemplateParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["isoid"]; found {
+		u.Set("isoid", v.(string))
+	}
+	if v, found := p.p["templateid"]; found {
+		u.Set("templateid", v.(string))
+	}
+	if v, found := p.p["userdataid"]; found {
+		u.Set("userdataid", v.(string))
+	}
+	if v, found := p.p["userdatapolicy"]; found {
+		u.Set("userdatapolicy", v.(string))
+	}
+	return u
+}
+
+func (p *LinkUserDataToTemplateParams) SetIsoid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["isoid"] = v
+}
+
+func (p *LinkUserDataToTemplateParams) ResetIsoid() {
+	if p.p != nil && p.p["isoid"] != nil {
+		delete(p.p, "isoid")
+	}
+}
+
+func (p *LinkUserDataToTemplateParams) GetIsoid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["isoid"].(string)
+	return value, ok
+}
+
+func (p *LinkUserDataToTemplateParams) SetTemplateid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["templateid"] = v
+}
+
+func (p *LinkUserDataToTemplateParams) ResetTemplateid() {
+	if p.p != nil && p.p["templateid"] != nil {
+		delete(p.p, "templateid")
+	}
+}
+
+func (p *LinkUserDataToTemplateParams) GetTemplateid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["templateid"].(string)
+	return value, ok
+}
+
+func (p *LinkUserDataToTemplateParams) SetUserdataid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["userdataid"] = v
+}
+
+func (p *LinkUserDataToTemplateParams) ResetUserdataid() {
+	if p.p != nil && p.p["userdataid"] != nil {
+		delete(p.p, "userdataid")
+	}
+}
+
+func (p *LinkUserDataToTemplateParams) GetUserdataid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["userdataid"].(string)
+	return value, ok
+}
+
+func (p *LinkUserDataToTemplateParams) SetUserdatapolicy(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["userdatapolicy"] = v
+}
+
+func (p *LinkUserDataToTemplateParams) ResetUserdatapolicy() {
+	if p.p != nil && p.p["userdatapolicy"] != nil {
+		delete(p.p, "userdatapolicy")
+	}
+}
+
+func (p *LinkUserDataToTemplateParams) GetUserdatapolicy() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["userdatapolicy"].(string)
+	return value, ok
+}
+
+// You should always use this function to get a new LinkUserDataToTemplateParams instance,
+// as then you are sure you have configured all required params
+func (s *TemplateService) NewLinkUserDataToTemplateParams() *LinkUserDataToTemplateParams {
+	p := &LinkUserDataToTemplateParams{}
+	p.p = make(map[string]interface{})
+	return p
+}
+
+// Link or unlink a userdata to a template.
+func (s *TemplateService) LinkUserDataToTemplate(p *LinkUserDataToTemplateParams) (*LinkUserDataToTemplateResponse, error) {
+	resp, err := s.cs.newRequest("linkUserDataToTemplate", p.toURLValues())
+	if err != nil {
+		return nil, err
+	}
+
+	var nested struct {
+		Response LinkUserDataToTemplateResponse `json:"template"`
+	}
+	if err := json.Unmarshal(resp, &nested); err != nil {
+		return nil, err
+	}
+	r := nested.Response
+
+	return &r, nil
+}
+
+type LinkUserDataToTemplateResponse struct {
+	Account               string              `json:"account"`
+	Accountid             string              `json:"accountid"`
+	Bits                  int                 `json:"bits"`
+	Bootable              bool                `json:"bootable"`
+	Checksum              string              `json:"checksum"`
+	Childtemplates        []interface{}       `json:"childtemplates"`
+	Created               string              `json:"created"`
+	CrossZones            bool                `json:"crossZones"`
+	Deployasis            bool                `json:"deployasis"`
+	Deployasisdetails     map[string]string   `json:"deployasisdetails"`
+	Details               map[string]string   `json:"details"`
+	Directdownload        bool                `json:"directdownload"`
+	Displaytext           string              `json:"displaytext"`
+	Domain                string              `json:"domain"`
+	Domainid              string              `json:"domainid"`
+	Downloaddetails       []map[string]string `json:"downloaddetails"`
+	Format                string              `json:"format"`
+	Hasannotations        bool                `json:"hasannotations"`
+	Hostid                string              `json:"hostid"`
+	Hostname              string              `json:"hostname"`
+	Hypervisor            string              `json:"hypervisor"`
+	Icon                  interface{}         `json:"icon"`
+	Id                    string              `json:"id"`
+	Isdynamicallyscalable bool                `json:"isdynamicallyscalable"`
+	Isextractable         bool                `json:"isextractable"`
+	Isfeatured            bool                `json:"isfeatured"`
+	Ispublic              bool                `json:"ispublic"`
+	Isready               bool                `json:"isready"`
+	JobID                 string              `json:"jobid"`
+	Jobstatus             int                 `json:"jobstatus"`
+	Name                  string              `json:"name"`
+	Ostypeid              string              `json:"ostypeid"`
+	Ostypename            string              `json:"ostypename"`
+	Parenttemplateid      string              `json:"parenttemplateid"`
+	Passwordenabled       bool                `json:"passwordenabled"`
+	Physicalsize          int64               `json:"physicalsize"`
+	Project               string              `json:"project"`
+	Projectid             string              `json:"projectid"`
+	Removed               string              `json:"removed"`
+	Requireshvm           bool                `json:"requireshvm"`
+	Size                  int64               `json:"size"`
+	Sourcetemplateid      string              `json:"sourcetemplateid"`
+	Sshkeyenabled         bool                `json:"sshkeyenabled"`
+	Status                string              `json:"status"`
+	Tags                  []Tags              `json:"tags"`
+	Templatetag           string              `json:"templatetag"`
+	Templatetype          string              `json:"templatetype"`
+	Url                   string              `json:"url"`
+	Userdataid            string              `json:"userdataid"`
+	Userdataname          string              `json:"userdataname"`
+	Userdataparams        string              `json:"userdataparams"`
+	Userdatapolicy        string              `json:"userdatapolicy"`
+	Zoneid                string              `json:"zoneid"`
+	Zonename              string              `json:"zonename"`
+}
+
+func (r *LinkUserDataToTemplateResponse) UnmarshalJSON(b []byte) error {
+	var m map[string]interface{}
+	err := json.Unmarshal(b, &m)
+	if err != nil {
+		return err
+	}
+
+	if success, ok := m["success"].(string); ok {
+		m["success"] = success == "true"
+		b, err = json.Marshal(m)
+		if err != nil {
+			return err
+		}
+	}
+
+	if ostypeid, ok := m["ostypeid"].(float64); ok {
+		m["ostypeid"] = strconv.Itoa(int(ostypeid))
+		b, err = json.Marshal(m)
+		if err != nil {
+			return err
+		}
+	}
+
+	type alias LinkUserDataToTemplateResponse
+	return json.Unmarshal(b, (*alias)(r))
+}
diff --git a/cloudstack/TemplateService_mock.go b/cloudstack/TemplateService_mock.go
index 01cadf7..a6d2b2a 100644
--- a/cloudstack/TemplateService_mock.go
+++ b/cloudstack/TemplateService_mock.go
@@ -232,6 +232,21 @@ func (mr *MockTemplateServiceIfaceMockRecorder) GetUploadParamsForTemplate(p int
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUploadParamsForTemplate", reflect.TypeOf((*MockTemplateServiceIface)(nil).GetUploadParamsForTemplate), p)
 }
 
+// LinkUserDataToTemplate mocks base method.
+func (m *MockTemplateServiceIface) LinkUserDataToTemplate(p *LinkUserDataToTemplateParams) (*LinkUserDataToTemplateResponse, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "LinkUserDataToTemplate", p)
+	ret0, _ := ret[0].(*LinkUserDataToTemplateResponse)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// LinkUserDataToTemplate indicates an expected call of LinkUserDataToTemplate.
+func (mr *MockTemplateServiceIfaceMockRecorder) LinkUserDataToTemplate(p interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkUserDataToTemplate", reflect.TypeOf((*MockTemplateServiceIface)(nil).LinkUserDataToTemplate), p)
+}
+
 // ListTemplateDirectDownloadCertificates mocks base method.
 func (m *MockTemplateServiceIface) ListTemplateDirectDownloadCertificates(p *ListTemplateDirectDownloadCertificatesParams) (*ListTemplateDirectDownloadCertificatesResponse, error) {
 	m.ctrl.T.Helper()
@@ -347,6 +362,20 @@ func (mr *MockTemplateServiceIfaceMockRecorder) NewGetUploadParamsForTemplatePar
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewGetUploadParamsForTemplateParams", reflect.TypeOf((*MockTemplateServiceIface)(nil).NewGetUploadParamsForTemplateParams), displaytext, format, hypervisor, name, zoneid)
 }
 
+// NewLinkUserDataToTemplateParams mocks base method.
+func (m *MockTemplateServiceIface) NewLinkUserDataToTemplateParams() *LinkUserDataToTemplateParams {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewLinkUserDataToTemplateParams")
+	ret0, _ := ret[0].(*LinkUserDataToTemplateParams)
+	return ret0
+}
+
+// NewLinkUserDataToTemplateParams indicates an expected call of NewLinkUserDataToTemplateParams.
+func (mr *MockTemplateServiceIfaceMockRecorder) NewLinkUserDataToTemplateParams() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewLinkUserDataToTemplateParams", reflect.TypeOf((*MockTemplateServiceIface)(nil).NewLinkUserDataToTemplateParams))
+}
+
 // NewListTemplateDirectDownloadCertificatesParams mocks base method.
 func (m *MockTemplateServiceIface) NewListTemplateDirectDownloadCertificatesParams() *ListTemplateDirectDownloadCertificatesParams {
 	m.ctrl.T.Helper()
diff --git a/cloudstack/UserService.go b/cloudstack/UserService.go
index b6fd82e..afaa6e3 100644
--- a/cloudstack/UserService.go
+++ b/cloudstack/UserService.go
@@ -51,6 +51,19 @@ type UserServiceIface interface {
 	NewRegisterUserKeysParams(id string) *RegisterUserKeysParams
 	UpdateUser(p *UpdateUserParams) (*UpdateUserResponse, error)
 	NewUpdateUserParams(id string) *UpdateUserParams
+	ListUserData(p *ListUserDataParams) (*ListUserDataResponse, error)
+	NewListUserDataParams() *ListUserDataParams
+	GetUserDataID(name string, opts ...OptionFunc) (string, int, error)
+	GetUserDataByName(name string, opts ...OptionFunc) (*UserData, int, error)
+	GetUserDataByID(id string, opts ...OptionFunc) (*UserData, int, error)
+	DeleteUserData(p *DeleteUserDataParams) (*DeleteUserDataResponse, error)
+	NewDeleteUserDataParams(id string) *DeleteUserDataParams
+	RegisterUserData(p *RegisterUserDataParams) (*RegisterUserDataResponse, error)
+	NewRegisterUserDataParams(name string, userdata string) *RegisterUserDataParams
+	MoveUser(p *MoveUserParams) (*MoveUserResponse, error)
+	NewMoveUserParams(id string) *MoveUserParams
+	SetupUserTwoFactorAuthentication(p *SetupUserTwoFactorAuthenticationParams) (*SetupUserTwoFactorAuthenticationResponse, error)
+	NewSetupUserTwoFactorAuthenticationParams() *SetupUserTwoFactorAuthenticationParams
 }
 
 type CreateUserParams struct {
@@ -1759,3 +1772,1044 @@ type UpdateUserResponse struct {
 	Username            string      `json:"username"`
 	Usersource          string      `json:"usersource"`
 }
+
+type ListUserDataParams struct {
+	p map[string]interface{}
+}
+
+func (p *ListUserDataParams) toURLValues() url.Values {
+	u := url.Values{}
+	if p.p == nil {
+		return u
+	}
+	if v, found := p.p["account"]; found {
+		u.Set("account", v.(string))
+	}
+	if v, found := p.p["domainid"]; found {
+		u.Set("domainid", v.(string))
+	}
+	if v, found := p.p["id"]; found {
+		u.Set("id", v.(string))
+	}
+	if v, found := p.p["isrecursive"]; found {
+		vv := strconv.FormatBool(v.(bool))
+		u.Set("isrecursive", vv)
+	}
+	if v, found := p.p["keyword"]; found {
+		u.Set("keyword", v.(string))
+	}
+	if v, found := p.p["listall"]; found {
+		vv := strconv.FormatBool(v.(bool))
+		u.Set("listall", vv)
+	}
+	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)
+	}
+	if v, found := p.p["projectid"]; found {
+		u.Set("projectid", v.(string))
+	}
+	return u
+}
+
+func (p *ListUserDataParams) SetAccount(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["account"] = v
+}
+
+func (p *ListUserDataParams) ResetAccount() {
+	if p.p != nil && p.p["account"] != nil {
+		delete(p.p, "account")
+	}
+}
+
+func (p *ListUserDataParams) GetAccount() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["account"].(string)
+	return value, ok
+}
+
+func (p *ListUserDataParams) SetDomainid(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["domainid"] = v
+}
+
+func (p *ListUserDataParams) ResetDomainid() {
+	if p.p != nil && p.p["domainid"] != nil {
+		delete(p.p, "domainid")
+	}
+}
+
+func (p *ListUserDataParams) GetDomainid() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["domainid"].(string)
+	return value, ok
+}
+
+func (p *ListUserDataParams) SetId(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["id"] = v
+}
+
+func (p *ListUserDataParams) ResetId() {
+	if p.p != nil && p.p["id"] != nil {
+		delete(p.p, "id")
+	}
+}
+
+func (p *ListUserDataParams) GetId() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["id"].(string)
+	return value, ok
+}
+
+func (p *ListUserDataParams) SetIsrecursive(v bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["isrecursive"] = v
+}
+
+func (p *ListUserDataParams) ResetIsrecursive() {
+	if p.p != nil && p.p["isrecursive"] != nil {
+		delete(p.p, "isrecursive")
+	}
+}
+
+func (p *ListUserDataParams) GetIsrecursive() (bool, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["isrecursive"].(bool)
+	return value, ok
+}
+
+func (p *ListUserDataParams) SetKeyword(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["keyword"] = v
+}
+
+func (p *ListUserDataParams) ResetKeyword() {
+	if p.p != nil && p.p["keyword"] != nil {
+		delete(p.p, "keyword")
+	}
+}
+
+func (p *ListUserDataParams) GetKeyword() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["keyword"].(string)
+	return value, ok
+}
+
+func (p *ListUserDataParams) SetListall(v bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["listall"] = v
+}
+
+func (p *ListUserDataParams) ResetListall() {
+	if p.p != nil && p.p["listall"] != nil {
+		delete(p.p, "listall")
+	}
+}
+
+func (p *ListUserDataParams) GetListall() (bool, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["listall"].(bool)
+	return value, ok
+}
+
+func (p *ListUserDataParams) SetName(v string) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["name"] = v
+}
+
+func (p *ListUserDataParams) ResetName() {
+	if p.p != nil && p.p["name"] != nil {
+		delete(p.p, "name")
+	}
+}
+
+func (p *ListUserDataParams) GetName() (string, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["name"].(string)
+	return value, ok
+}
+
+func (p *ListUserDataParams) SetPage(v int) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	p.p["page"] = v
+}
+
+func (p *ListUserDataParams) ResetPage() {
+	if p.p != nil && p.p["page"] != nil {
+		delete(p.p, "page")
+	}
+}
+
+func (p *ListUserDataParams) GetPage() (int, bool) {
+	if p.p == nil {
+		p.p = make(map[string]interface{})
+	}
+	value, ok := p.p["page"].(int)
+	return value, ok
+}
... 7813 lines suppressed ...