Commit 9a8cb435 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #51795 from dims/bug-fix-51755

Automatic merge from submit-queue (batch tested with PRs 51984, 51351, 51873, 51795, 51634) Bug Fix - Adding an allowed address pair wipes port security groups **What this PR does / why we need it**: Fix for cloud routes enabled instances will have their security groups removed when the allowed address pair is added to the instance's port. Upstream bug report is in: https://github.com/gophercloud/gophercloud/issues/509 Upstream bug fix is in: https://github.com/gophercloud/gophercloud/pull/510 **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes # Fixes #51755 **Special notes for your reviewer**: Just an fix in vendored code. minimal changes needed in OpenStack cloud provider **Release note**: ```release-note NONE ```
parents b6a0bb1a 74a3d89a
...@@ -1604,127 +1604,127 @@ ...@@ -1604,127 +1604,127 @@
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud", "ImportPath": "github.com/gophercloud/gophercloud",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack", "ImportPath": "github.com/gophercloud/gophercloud/openstack",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions", "ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/apiversions",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes", "ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes", "ImportPath": "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/common/extensions", "ImportPath": "github.com/gophercloud/gophercloud/openstack/common/extensions",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces", "ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach", "ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/flavors", "ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/flavors",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/images", "ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/images",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/servers", "ImportPath": "github.com/gophercloud/gophercloud/openstack/compute/v2/servers",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants", "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens", "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts", "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/extensions/trusts",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens", "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions", "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips", "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers", "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/routers",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/members", "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/members",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/monitors", "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/monitors",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/pools", "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/pools",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/vips", "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/vips",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners", "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers", "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors", "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools", "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups", "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules", "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/ports", "ImportPath": "github.com/gophercloud/gophercloud/openstack/networking/v2/ports",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/utils", "ImportPath": "github.com/gophercloud/gophercloud/openstack/utils",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/pagination", "ImportPath": "github.com/gophercloud/gophercloud/pagination",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gorilla/context", "ImportPath": "github.com/gorilla/context",
......
...@@ -994,7 +994,7 @@ func (lbaas *LbaasV2) EnsureLoadBalancer(clusterName string, apiService *v1.Serv ...@@ -994,7 +994,7 @@ func (lbaas *LbaasV2) EnsureLoadBalancer(clusterName string, apiService *v1.Serv
} }
portID := loadbalancer.VipPortID portID := loadbalancer.VipPortID
update_opts := neutronports.UpdateOpts{SecurityGroups: []string{lbSecGroup.ID}} update_opts := neutronports.UpdateOpts{SecurityGroups: &[]string{lbSecGroup.ID}}
res := neutronports.Update(lbaas.network, portID, update_opts) res := neutronports.Update(lbaas.network, portID, update_opts)
if res.Err != nil { if res.Err != nil {
glog.Errorf("Error occured updating port: %s", portID) glog.Errorf("Error occured updating port: %s", portID)
......
...@@ -121,7 +121,7 @@ func updateAllowedAddressPairs(network *gophercloud.ServiceClient, port *neutron ...@@ -121,7 +121,7 @@ func updateAllowedAddressPairs(network *gophercloud.ServiceClient, port *neutron
origPairs := port.AllowedAddressPairs // shallow copy origPairs := port.AllowedAddressPairs // shallow copy
_, err := neutronports.Update(network, port.ID, neutronports.UpdateOpts{ _, err := neutronports.Update(network, port.ID, neutronports.UpdateOpts{
AllowedAddressPairs: newPairs, AllowedAddressPairs: &newPairs,
}).Extract() }).Extract()
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -130,7 +130,7 @@ func updateAllowedAddressPairs(network *gophercloud.ServiceClient, port *neutron ...@@ -130,7 +130,7 @@ func updateAllowedAddressPairs(network *gophercloud.ServiceClient, port *neutron
unwinder := func() { unwinder := func() {
glog.V(4).Info("Reverting allowed-address-pairs change to port ", port.ID) glog.V(4).Info("Reverting allowed-address-pairs change to port ", port.ID)
_, err := neutronports.Update(network, port.ID, neutronports.UpdateOpts{ _, err := neutronports.Update(network, port.ID, neutronports.UpdateOpts{
AllowedAddressPairs: origPairs, AllowedAddressPairs: &origPairs,
}).Extract() }).Extract()
if err != nil { if err != nil {
glog.Warning("Unable to reset allowed-address-pairs during error unwind: ", err) glog.Warning("Unable to reset allowed-address-pairs during error unwind: ", err)
......
...@@ -404,31 +404,31 @@ ...@@ -404,31 +404,31 @@
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud", "ImportPath": "github.com/gophercloud/gophercloud",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack", "ImportPath": "github.com/gophercloud/gophercloud/openstack",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants", "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens", "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens", "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/utils", "ImportPath": "github.com/gophercloud/gophercloud/openstack/utils",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/pagination", "ImportPath": "github.com/gophercloud/gophercloud/pagination",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gregjones/httpcache", "ImportPath": "github.com/gregjones/httpcache",
......
...@@ -176,31 +176,31 @@ ...@@ -176,31 +176,31 @@
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud", "ImportPath": "github.com/gophercloud/gophercloud",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack", "ImportPath": "github.com/gophercloud/gophercloud/openstack",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants", "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens", "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens", "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/utils", "ImportPath": "github.com/gophercloud/gophercloud/openstack/utils",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/pagination", "ImportPath": "github.com/gophercloud/gophercloud/pagination",
"Rev": "c0406a133c4a74a838baf0ddff3c2fab21155fba" "Rev": "2bf16b94fdd9b01557c4d076e567fe5cbbe5a961"
}, },
{ {
"ImportPath": "github.com/gregjones/httpcache", "ImportPath": "github.com/gregjones/httpcache",
......
...@@ -9,12 +9,32 @@ ProviderClient representing an active session on that provider. ...@@ -9,12 +9,32 @@ ProviderClient representing an active session on that provider.
Its fields are the union of those recognized by each identity implementation and Its fields are the union of those recognized by each identity implementation and
provider. provider.
An example of manually providing authentication information:
opts := gophercloud.AuthOptions{
IdentityEndpoint: "https://openstack.example.com:5000/v2.0",
Username: "{username}",
Password: "{password}",
TenantID: "{tenant_id}",
}
provider, err := openstack.AuthenticatedClient(opts)
An example of using AuthOptionsFromEnv(), where the environment variables can
be read from a file, such as a standard openrc file:
opts, err := openstack.AuthOptionsFromEnv()
provider, err := openstack.AuthenticatedClient(opts)
*/ */
type AuthOptions struct { type AuthOptions struct {
// IdentityEndpoint specifies the HTTP endpoint that is required to work with // IdentityEndpoint specifies the HTTP endpoint that is required to work with
// the Identity API of the appropriate version. While it's ultimately needed by // the Identity API of the appropriate version. While it's ultimately needed by
// all of the identity services, it will often be populated by a provider-level // all of the identity services, it will often be populated by a provider-level
// function. // function.
//
// The IdentityEndpoint is typically referred to as the "auth_url" or
// "OS_AUTH_URL" in the information provided by the cloud operator.
IdentityEndpoint string `json:"-"` IdentityEndpoint string `json:"-"`
// Username is required if using Identity V2 API. Consult with your provider's // Username is required if using Identity V2 API. Consult with your provider's
...@@ -39,7 +59,7 @@ type AuthOptions struct { ...@@ -39,7 +59,7 @@ type AuthOptions struct {
// If DomainID or DomainName are provided, they will also apply to TenantName. // If DomainID or DomainName are provided, they will also apply to TenantName.
// It is not currently possible to authenticate with Username and a Domain // It is not currently possible to authenticate with Username and a Domain
// and scope to a Project in a different Domain by using TenantName. To // and scope to a Project in a different Domain by using TenantName. To
// accomplish that, the ProjectID will need to be provided to the TenantID // accomplish that, the ProjectID will need to be provided as the TenantID
// option. // option.
TenantID string `json:"tenantId,omitempty"` TenantID string `json:"tenantId,omitempty"`
TenantName string `json:"tenantName,omitempty"` TenantName string `json:"tenantName,omitempty"`
...@@ -50,10 +70,12 @@ type AuthOptions struct { ...@@ -50,10 +70,12 @@ type AuthOptions struct {
// false, it will not cache these settings, but re-authentication will not be // false, it will not cache these settings, but re-authentication will not be
// possible. This setting defaults to false. // possible. This setting defaults to false.
// //
// NOTE: The reauth function will try to re-authenticate endlessly if left unchecked. // NOTE: The reauth function will try to re-authenticate endlessly if left
// The way to limit the number of attempts is to provide a custom HTTP client to the provider client // unchecked. The way to limit the number of attempts is to provide a custom
// and provide a transport that implements the RoundTripper interface and stores the number of failed retries. // HTTP client to the provider client and provide a transport that implements
// For an example of this, see here: https://github.com/rackspace/rack/blob/1.0.0/auth/clients.go#L311 // the RoundTripper interface and stores the number of failed retries. For an
// example of this, see here:
// https://github.com/rackspace/rack/blob/1.0.0/auth/clients.go#L311
AllowReauth bool `json:"-"` AllowReauth bool `json:"-"`
// TokenID allows users to authenticate (possibly as another user) with an // TokenID allows users to authenticate (possibly as another user) with an
...@@ -316,7 +338,12 @@ func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) { ...@@ -316,7 +338,12 @@ func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) {
}, },
}, nil }, nil
} else if scope.DomainName != "" { } else if scope.DomainName != "" {
return nil, ErrScopeDomainName{} // DomainName
return map[string]interface{}{
"domain": map[string]interface{}{
"name": &scope.DomainName,
},
}, nil
} }
return nil, nil return nil, nil
......
...@@ -3,11 +3,17 @@ Package gophercloud provides a multi-vendor interface to OpenStack-compatible ...@@ -3,11 +3,17 @@ Package gophercloud provides a multi-vendor interface to OpenStack-compatible
clouds. The library has a three-level hierarchy: providers, services, and clouds. The library has a three-level hierarchy: providers, services, and
resources. resources.
Provider structs represent the service providers that offer and manage a Authenticating with Providers
collection of services. The IdentityEndpoint is typically refered to as
"auth_url" in information provided by the cloud operator. Additionally, Provider structs represent the cloud providers that offer and manage a
the cloud may refer to TenantID or TenantName as project_id and project_name. collection of services. You will generally want to create one Provider
These are defined like so: client per OpenStack cloud.
Use your OpenStack credentials to create a Provider client. The
IdentityEndpoint is typically refered to as "auth_url" or "OS_AUTH_URL" in
information provided by the cloud operator. Additionally, the cloud may refer to
TenantID or TenantName as project_id and project_name. Credentials are
specified like so:
opts := gophercloud.AuthOptions{ opts := gophercloud.AuthOptions{
IdentityEndpoint: "https://openstack.example.com:5000/v2.0", IdentityEndpoint: "https://openstack.example.com:5000/v2.0",
...@@ -18,6 +24,16 @@ These are defined like so: ...@@ -18,6 +24,16 @@ These are defined like so:
provider, err := openstack.AuthenticatedClient(opts) provider, err := openstack.AuthenticatedClient(opts)
You may also use the openstack.AuthOptionsFromEnv() helper function. This
function reads in standard environment variables frequently found in an
OpenStack `openrc` file. Again note that Gophercloud currently uses "tenant"
instead of "project".
opts, err := openstack.AuthOptionsFromEnv()
provider, err := openstack.AuthenticatedClient(opts)
Service Clients
Service structs are specific to a provider and handle all of the logic and Service structs are specific to a provider and handle all of the logic and
operations for a particular OpenStack service. Examples of services include: operations for a particular OpenStack service. Examples of services include:
Compute, Object Storage, Block Storage. In order to define one, you need to Compute, Object Storage, Block Storage. In order to define one, you need to
...@@ -27,6 +43,8 @@ pass in the parent provider, like so: ...@@ -27,6 +43,8 @@ pass in the parent provider, like so:
client := openstack.NewComputeV2(provider, opts) client := openstack.NewComputeV2(provider, opts)
Resources
Resource structs are the domain models that services make use of in order Resource structs are the domain models that services make use of in order
to work with and represent the state of API resources: to work with and represent the state of API resources:
...@@ -62,6 +80,12 @@ of results: ...@@ -62,6 +80,12 @@ of results:
return true, nil return true, nil
}) })
If you want to obtain the entire collection of pages without doing any
intermediary processing on each page, you can use the AllPages method:
allPages, err := servers.List(client, nil).AllPages()
allServers, err := servers.ExtractServers(allPages)
This top-level package contains utility functions and data types that are used This top-level package contains utility functions and data types that are used
throughout the provider and service packages. Of particular note for end users throughout the provider and service packages. Of particular note for end users
are the AuthOptions and EndpointOpts structs. are the AuthOptions and EndpointOpts structs.
......
...@@ -27,7 +27,7 @@ const ( ...@@ -27,7 +27,7 @@ const (
// unambiguously identify one, and only one, endpoint within the catalog. // unambiguously identify one, and only one, endpoint within the catalog.
// //
// Usually, these are passed to service client factory functions in a provider // Usually, these are passed to service client factory functions in a provider
// package, like "rackspace.NewComputeV2()". // package, like "openstack.NewComputeV2()".
type EndpointOpts struct { type EndpointOpts struct {
// Type [required] is the service type for the client (e.g., "compute", // Type [required] is the service type for the client (e.g., "compute",
// "object-store"). Generally, this will be supplied by the service client // "object-store"). Generally, this will be supplied by the service client
......
...@@ -393,13 +393,6 @@ func (e ErrScopeProjectIDAlone) Error() string { ...@@ -393,13 +393,6 @@ func (e ErrScopeProjectIDAlone) Error() string {
return "ProjectID must be supplied alone in a Scope" return "ProjectID must be supplied alone in a Scope"
} }
// ErrScopeDomainName indicates that a DomainName was provided alone in a Scope.
type ErrScopeDomainName struct{ BaseError }
func (e ErrScopeDomainName) Error() string {
return "DomainName must be supplied with a ProjectName or ProjectID in a Scope"
}
// ErrScopeEmpty indicates that no credentials were provided in a Scope. // ErrScopeEmpty indicates that no credentials were provided in a Scope.
type ErrScopeEmpty struct{ BaseError } type ErrScopeEmpty struct{ BaseError }
......
...@@ -5,6 +5,7 @@ go_library( ...@@ -5,6 +5,7 @@ go_library(
srcs = [ srcs = [
"auth_env.go", "auth_env.go",
"client.go", "client.go",
"doc.go",
"endpoint_location.go", "endpoint_location.go",
"errors.go", "errors.go",
], ],
......
...@@ -8,10 +8,22 @@ import ( ...@@ -8,10 +8,22 @@ import (
var nilOptions = gophercloud.AuthOptions{} var nilOptions = gophercloud.AuthOptions{}
// AuthOptionsFromEnv fills out an identity.AuthOptions structure with the settings found on the various OpenStack /*
// OS_* environment variables. The following variables provide sources of truth: OS_AUTH_URL, OS_USERNAME, AuthOptionsFromEnv fills out an identity.AuthOptions structure with the
// OS_PASSWORD, OS_TENANT_ID, and OS_TENANT_NAME. Of these, OS_USERNAME, OS_PASSWORD, and OS_AUTH_URL must settings found on the various OpenStack OS_* environment variables.
// have settings, or an error will result. OS_TENANT_ID and OS_TENANT_NAME are optional.
The following variables provide sources of truth: OS_AUTH_URL, OS_USERNAME,
OS_PASSWORD, OS_TENANT_ID, and OS_TENANT_NAME.
Of these, OS_USERNAME, OS_PASSWORD, and OS_AUTH_URL must have settings,
or an error will result. OS_TENANT_ID and OS_TENANT_NAME are optional.
To use this function, first set the OS_* environment variables (for example,
by sourcing an `openrc` file), then:
opts, err := openstack.AuthOptionsFromEnv()
provider, err := openstack.AuthenticatedClient(opts)
*/
func AuthOptionsFromEnv() (gophercloud.AuthOptions, error) { func AuthOptionsFromEnv() (gophercloud.AuthOptions, error) {
authURL := os.Getenv("OS_AUTH_URL") authURL := os.Getenv("OS_AUTH_URL")
username := os.Getenv("OS_USERNAME") username := os.Getenv("OS_USERNAME")
......
...@@ -16,10 +16,20 @@ const ( ...@@ -16,10 +16,20 @@ const (
v30 = "v3.0" v30 = "v3.0"
) )
// NewClient prepares an unauthenticated ProviderClient instance. /*
// Most users will probably prefer using the AuthenticatedClient function instead. NewClient prepares an unauthenticated ProviderClient instance.
// This is useful if you wish to explicitly control the version of the identity service that's used for authentication explicitly, Most users will probably prefer using the AuthenticatedClient function
// for example. instead.
This is useful if you wish to explicitly control the version of the identity
service that's used for authentication explicitly, for example.
A basic example of using this would be:
ao, err := openstack.AuthOptionsFromEnv()
provider, err := openstack.NewClient(ao.IdentityEndpoint)
client, err := openstack.NewIdentityV3(provider, gophercloud.EndpointOpts{})
*/
func NewClient(endpoint string) (*gophercloud.ProviderClient, error) { func NewClient(endpoint string) (*gophercloud.ProviderClient, error) {
u, err := url.Parse(endpoint) u, err := url.Parse(endpoint)
if err != nil { if err != nil {
...@@ -45,10 +55,26 @@ func NewClient(endpoint string) (*gophercloud.ProviderClient, error) { ...@@ -45,10 +55,26 @@ func NewClient(endpoint string) (*gophercloud.ProviderClient, error) {
}, nil }, nil
} }
// AuthenticatedClient logs in to an OpenStack cloud found at the identity endpoint specified by options, acquires a token, and /*
// returns a Client instance that's ready to operate. AuthenticatedClient logs in to an OpenStack cloud found at the identity endpoint
// It first queries the root identity endpoint to determine which versions of the identity service are supported, then chooses specified by the options, acquires a token, and returns a Provider Client
// the most recent identity service available to proceed. instance that's ready to operate.
If the full path to a versioned identity endpoint was specified (example:
http://example.com:5000/v3), that path will be used as the endpoint to query.
If a versionless endpoint was specified (example: http://example.com:5000/),
the endpoint will be queried to determine which versions of the identity service
are available, then chooses the most recent or most supported version.
Example:
ao, err := openstack.AuthOptionsFromEnv()
provider, err := openstack.AuthenticatedClient(ao)
client, err := openstack.NewNetworkV2(client, gophercloud.EndpointOpts{
Region: os.Getenv("OS_REGION_NAME"),
})
*/
func AuthenticatedClient(options gophercloud.AuthOptions) (*gophercloud.ProviderClient, error) { func AuthenticatedClient(options gophercloud.AuthOptions) (*gophercloud.ProviderClient, error) {
client, err := NewClient(options.IdentityEndpoint) client, err := NewClient(options.IdentityEndpoint)
if err != nil { if err != nil {
...@@ -62,7 +88,8 @@ func AuthenticatedClient(options gophercloud.AuthOptions) (*gophercloud.Provider ...@@ -62,7 +88,8 @@ func AuthenticatedClient(options gophercloud.AuthOptions) (*gophercloud.Provider
return client, nil return client, nil
} }
// Authenticate or re-authenticate against the most recent identity service supported at the provided endpoint. // Authenticate or re-authenticate against the most recent identity service
// supported at the provided endpoint.
func Authenticate(client *gophercloud.ProviderClient, options gophercloud.AuthOptions) error { func Authenticate(client *gophercloud.ProviderClient, options gophercloud.AuthOptions) error {
versions := []*utils.Version{ versions := []*utils.Version{
{ID: v20, Priority: 20, Suffix: "/v2.0/"}, {ID: v20, Priority: 20, Suffix: "/v2.0/"},
...@@ -179,7 +206,8 @@ func v3auth(client *gophercloud.ProviderClient, endpoint string, opts tokens3.Au ...@@ -179,7 +206,8 @@ func v3auth(client *gophercloud.ProviderClient, endpoint string, opts tokens3.Au
return nil return nil
} }
// NewIdentityV2 creates a ServiceClient that may be used to interact with the v2 identity service. // NewIdentityV2 creates a ServiceClient that may be used to interact with the
// v2 identity service.
func NewIdentityV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { func NewIdentityV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
endpoint := client.IdentityBase + "v2.0/" endpoint := client.IdentityBase + "v2.0/"
clientType := "identity" clientType := "identity"
...@@ -199,7 +227,8 @@ func NewIdentityV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOp ...@@ -199,7 +227,8 @@ func NewIdentityV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOp
}, nil }, nil
} }
// NewIdentityV3 creates a ServiceClient that may be used to access the v3 identity service. // NewIdentityV3 creates a ServiceClient that may be used to access the v3
// identity service.
func NewIdentityV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { func NewIdentityV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
endpoint := client.IdentityBase + "v3/" endpoint := client.IdentityBase + "v3/"
clientType := "identity" clientType := "identity"
...@@ -232,34 +261,40 @@ func initClientOpts(client *gophercloud.ProviderClient, eo gophercloud.EndpointO ...@@ -232,34 +261,40 @@ func initClientOpts(client *gophercloud.ProviderClient, eo gophercloud.EndpointO
return sc, nil return sc, nil
} }
// NewObjectStorageV1 creates a ServiceClient that may be used with the v1 object storage package. // NewObjectStorageV1 creates a ServiceClient that may be used with the v1
// object storage package.
func NewObjectStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { func NewObjectStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
return initClientOpts(client, eo, "object-store") return initClientOpts(client, eo, "object-store")
} }
// NewComputeV2 creates a ServiceClient that may be used with the v2 compute package. // NewComputeV2 creates a ServiceClient that may be used with the v2 compute
// package.
func NewComputeV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { func NewComputeV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
return initClientOpts(client, eo, "compute") return initClientOpts(client, eo, "compute")
} }
// NewNetworkV2 creates a ServiceClient that may be used with the v2 network package. // NewNetworkV2 creates a ServiceClient that may be used with the v2 network
// package.
func NewNetworkV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { func NewNetworkV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
sc, err := initClientOpts(client, eo, "network") sc, err := initClientOpts(client, eo, "network")
sc.ResourceBase = sc.Endpoint + "v2.0/" sc.ResourceBase = sc.Endpoint + "v2.0/"
return sc, err return sc, err
} }
// NewBlockStorageV1 creates a ServiceClient that may be used to access the v1 block storage service. // NewBlockStorageV1 creates a ServiceClient that may be used to access the v1
// block storage service.
func NewBlockStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { func NewBlockStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
return initClientOpts(client, eo, "volume") return initClientOpts(client, eo, "volume")
} }
// NewBlockStorageV2 creates a ServiceClient that may be used to access the v2 block storage service. // NewBlockStorageV2 creates a ServiceClient that may be used to access the v2
// block storage service.
func NewBlockStorageV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { func NewBlockStorageV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
return initClientOpts(client, eo, "volumev2") return initClientOpts(client, eo, "volumev2")
} }
// NewSharedFileSystemV2 creates a ServiceClient that may be used to access the v2 shared file system service. // NewSharedFileSystemV2 creates a ServiceClient that may be used to access the
// v2 shared file system service.
func NewSharedFileSystemV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { func NewSharedFileSystemV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
return initClientOpts(client, eo, "sharev2") return initClientOpts(client, eo, "sharev2")
} }
...@@ -270,7 +305,8 @@ func NewCDNV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) ( ...@@ -270,7 +305,8 @@ func NewCDNV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (
return initClientOpts(client, eo, "cdn") return initClientOpts(client, eo, "cdn")
} }
// NewOrchestrationV1 creates a ServiceClient that may be used to access the v1 orchestration service. // NewOrchestrationV1 creates a ServiceClient that may be used to access the v1
// orchestration service.
func NewOrchestrationV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { func NewOrchestrationV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
return initClientOpts(client, eo, "orchestration") return initClientOpts(client, eo, "orchestration")
} }
...@@ -280,14 +316,16 @@ func NewDBV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (* ...@@ -280,14 +316,16 @@ func NewDBV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*
return initClientOpts(client, eo, "database") return initClientOpts(client, eo, "database")
} }
// NewDNSV2 creates a ServiceClient that may be used to access the v2 DNS service. // NewDNSV2 creates a ServiceClient that may be used to access the v2 DNS
// service.
func NewDNSV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { func NewDNSV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
sc, err := initClientOpts(client, eo, "dns") sc, err := initClientOpts(client, eo, "dns")
sc.ResourceBase = sc.Endpoint + "v2/" sc.ResourceBase = sc.Endpoint + "v2/"
return sc, err return sc, err
} }
// NewImageServiceV2 creates a ServiceClient that may be used to access the v2 image service. // NewImageServiceV2 creates a ServiceClient that may be used to access the v2
// image service.
func NewImageServiceV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { func NewImageServiceV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
sc, err := initClientOpts(client, eo, "image") sc, err := initClientOpts(client, eo, "image")
sc.ResourceBase = sc.Endpoint + "v2/" sc.ResourceBase = sc.Endpoint + "v2/"
......
...@@ -4,7 +4,6 @@ go_library( ...@@ -4,7 +4,6 @@ go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"doc.go", "doc.go",
"errors.go",
"requests.go", "requests.go",
"results.go", "results.go",
"urls.go", "urls.go",
......
// Package extensions provides information and interaction with the different extensions available /*
// for an OpenStack service. Package extensions provides information and interaction with the different
// extensions available for an OpenStack service.
// The purpose of OpenStack API extensions is to:
// The purpose of OpenStack API extensions is to:
// - Introduce new features in the API without requiring a version change.
// - Introduce vendor-specific niche functionality. - Introduce new features in the API without requiring a version change.
// - Act as a proving ground for experimental functionalities that might be included in a future - Introduce vendor-specific niche functionality.
// version of the API. - Act as a proving ground for experimental functionalities that might be
// included in a future version of the API.
// Extensions usually have tags that prevent conflicts with other extensions that define attributes
// or resources with the same names, and with core resources and attributes. Extensions usually have tags that prevent conflicts with other extensions that
// Because an extension might not be supported by all plug-ins, its availability varies with deployments define attributes or resources with the same names, and with core resources and
// and the specific plug-in. attributes. Because an extension might not be supported by all plug-ins, its
availability varies with deployments and the specific plug-in.
The results of this package vary depending on the type of Service Client used.
In the following examples, note how the only difference is the creation of the
Service Client.
Example of Retrieving Compute Extensions
ao, err := openstack.AuthOptionsFromEnv()
provider, err := openstack.AuthenticatedClient(ao)
computeClient, err := openstack.NewComputeV2(provider, gophercloud.EndpointOpts{
Region: os.Getenv("OS_REGION_NAME"),
})
allPages, err := extensions.List(computeClient).Allpages()
allExtensions, err := extensions.ExtractExtensions(allPages)
for _, extension := range allExtensions{
fmt.Println("%+v\n", extension)
}
Example of Retrieving Network Extensions
ao, err := openstack.AuthOptionsFromEnv()
provider, err := openstack.AuthenticatedClient(ao)
networkClient, err := openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{
Region: os.Getenv("OS_REGION_NAME"),
})
allPages, err := extensions.List(networkClient).Allpages()
allExtensions, err := extensions.ExtractExtensions(allPages)
for _, extension := range allExtensions{
fmt.Println("%+v\n", extension)
}
*/
package extensions package extensions
...@@ -41,8 +41,8 @@ func (r ExtensionPage) IsEmpty() (bool, error) { ...@@ -41,8 +41,8 @@ func (r ExtensionPage) IsEmpty() (bool, error) {
return len(is) == 0, err return len(is) == 0, err
} }
// ExtractExtensions accepts a Page struct, specifically an ExtensionPage struct, and extracts the // ExtractExtensions accepts a Page struct, specifically an ExtensionPage
// elements into a slice of Extension structs. // struct, and extracts the elements into a slice of Extension structs.
// In other words, a generic collection is mapped into a relevant slice. // In other words, a generic collection is mapped into a relevant slice.
func ExtractExtensions(r pagination.Page) ([]Extension, error) { func ExtractExtensions(r pagination.Page) ([]Extension, error) {
var s struct { var s struct {
......
// Package attachinterfaces provides the ability to manage network interfaces through /*
// nova-network Package attachinterfaces provides the ability to retrieve and manage network
interfaces through Nova.
Example of Listing a Server's Interfaces
serverID := "b07e7a3b-d951-4efc-a4f9-ac9f001afb7f"
allPages, err := attachinterfaces.List(computeClient, serverID).AllPages()
if err != nil {
panic(err)
}
allInterfaces, err := attachinterfaces.ExtractInterfaces(allPages)
if err != nil {
panic(err)
}
for _, interface := range allInterfaces {
fmt.Printf("%+v\n", interface)
}
*/
package attachinterfaces package attachinterfaces
...@@ -5,7 +5,7 @@ import ( ...@@ -5,7 +5,7 @@ import (
"github.com/gophercloud/gophercloud/pagination" "github.com/gophercloud/gophercloud/pagination"
) )
// List makes a request against the nova API to list the servers interfaces. // List makes a request against the nova API to list the server's interfaces.
func List(client *gophercloud.ServiceClient, serverID string) pagination.Pager { func List(client *gophercloud.ServiceClient, serverID string) pagination.Pager {
return pagination.NewPager(client, listInterfaceURL(client, serverID), func(r pagination.PageResult) pagination.Page { return pagination.NewPager(client, listInterfaceURL(client, serverID), func(r pagination.PageResult) pagination.Page {
return InterfacePage{pagination.SinglePageBase(r)} return InterfacePage{pagination.SinglePageBase(r)}
......
...@@ -10,7 +10,7 @@ type FixedIP struct { ...@@ -10,7 +10,7 @@ type FixedIP struct {
IPAddress string `json:"ip_address"` IPAddress string `json:"ip_address"`
} }
// Interface represents a network interface on an instance. // Interface represents a network interface on a server.
type Interface struct { type Interface struct {
PortState string `json:"port_state"` PortState string `json:"port_state"`
FixedIPs []FixedIP `json:"fixed_ips"` FixedIPs []FixedIP `json:"fixed_ips"`
...@@ -19,9 +19,12 @@ type Interface struct { ...@@ -19,9 +19,12 @@ type Interface struct {
MACAddr string `json:"mac_addr"` MACAddr string `json:"mac_addr"`
} }
// InterfacePage abstracts the raw results of making a List() request against the API. // InterfacePage abstracts the raw results of making a List() request against
// As OpenStack extensions may freely alter the response bodies of structures returned // the API.
// to the client, you may only safely access the data provided through the ExtractInterfaces call. //
// As OpenStack extensions may freely alter the response bodies of structures
// returned to the client, you may only safely access the data provided through
// the ExtractInterfaces call.
type InterfacePage struct { type InterfacePage struct {
pagination.SinglePageBase pagination.SinglePageBase
} }
...@@ -33,7 +36,7 @@ func (r InterfacePage) IsEmpty() (bool, error) { ...@@ -33,7 +36,7 @@ func (r InterfacePage) IsEmpty() (bool, error) {
} }
// ExtractInterfaces interprets the results of a single page from a List() call, // ExtractInterfaces interprets the results of a single page from a List() call,
// producing a map of interfaces. // producing a slice of Interface structs.
func ExtractInterfaces(r pagination.Page) ([]Interface, error) { func ExtractInterfaces(r pagination.Page) ([]Interface, error) {
var s struct { var s struct {
Interfaces []Interface `json:"interfaceAttachments"` Interfaces []Interface `json:"interfaceAttachments"`
......
// Package volumeattach provides the ability to attach and detach volumes /*
// to instances Package volumeattach provides the ability to attach and detach volumes
from servers.
Example to Attach a Volume
serverID := "7ac8686c-de71-4acb-9600-ec18b1a1ed6d"
volumeID := "87463836-f0e2-4029-abf6-20c8892a3103"
createOpts := volumeattach.CreateOpts{
Device: "/dev/vdc",
VolumeID: volumeID,
}
result, err := volumeattach.Create(computeClient, serverID, createOpts).Extract()
if err != nil {
panic(err)
}
Example to Detach a Volume
serverID := "7ac8686c-de71-4acb-9600-ec18b1a1ed6d"
attachmentID := "ed081613-1c9b-4231-aa5e-ebfd4d87f983"
err := volumeattach.Delete(computeClient, serverID, attachmentID).ExtractErr()
if err != nil {
panic(err)
}
*/
package volumeattach package volumeattach
...@@ -5,24 +5,26 @@ import ( ...@@ -5,24 +5,26 @@ import (
"github.com/gophercloud/gophercloud/pagination" "github.com/gophercloud/gophercloud/pagination"
) )
// List returns a Pager that allows you to iterate over a collection of VolumeAttachments. // List returns a Pager that allows you to iterate over a collection of
// VolumeAttachments.
func List(client *gophercloud.ServiceClient, serverID string) pagination.Pager { func List(client *gophercloud.ServiceClient, serverID string) pagination.Pager {
return pagination.NewPager(client, listURL(client, serverID), func(r pagination.PageResult) pagination.Page { return pagination.NewPager(client, listURL(client, serverID), func(r pagination.PageResult) pagination.Page {
return VolumeAttachmentPage{pagination.SinglePageBase(r)} return VolumeAttachmentPage{pagination.SinglePageBase(r)}
}) })
} }
// CreateOptsBuilder describes struct types that can be accepted by the Create call. Notable, the // CreateOptsBuilder allows extensions to add parameters to the Create request.
// CreateOpts struct in this package does.
type CreateOptsBuilder interface { type CreateOptsBuilder interface {
ToVolumeAttachmentCreateMap() (map[string]interface{}, error) ToVolumeAttachmentCreateMap() (map[string]interface{}, error)
} }
// CreateOpts specifies volume attachment creation or import parameters. // CreateOpts specifies volume attachment creation or import parameters.
type CreateOpts struct { type CreateOpts struct {
// Device is the device that the volume will attach to the instance as. Omit for "auto" // Device is the device that the volume will attach to the instance as.
// Omit for "auto".
Device string `json:"device,omitempty"` Device string `json:"device,omitempty"`
// VolumeID is the ID of the volume to attach to the instance
// VolumeID is the ID of the volume to attach to the instance.
VolumeID string `json:"volumeId" required:"true"` VolumeID string `json:"volumeId" required:"true"`
} }
...@@ -31,7 +33,7 @@ func (opts CreateOpts) ToVolumeAttachmentCreateMap() (map[string]interface{}, er ...@@ -31,7 +33,7 @@ func (opts CreateOpts) ToVolumeAttachmentCreateMap() (map[string]interface{}, er
return gophercloud.BuildRequestBody(opts, "volumeAttachment") return gophercloud.BuildRequestBody(opts, "volumeAttachment")
} }
// Create requests the creation of a new volume attachment on the server // Create requests the creation of a new volume attachment on the server.
func Create(client *gophercloud.ServiceClient, serverID string, opts CreateOptsBuilder) (r CreateResult) { func Create(client *gophercloud.ServiceClient, serverID string, opts CreateOptsBuilder) (r CreateResult) {
b, err := opts.ToVolumeAttachmentCreateMap() b, err := opts.ToVolumeAttachmentCreateMap()
if err != nil { if err != nil {
...@@ -50,7 +52,8 @@ func Get(client *gophercloud.ServiceClient, serverID, attachmentID string) (r Ge ...@@ -50,7 +52,8 @@ func Get(client *gophercloud.ServiceClient, serverID, attachmentID string) (r Ge
return return
} }
// Delete requests the deletion of a previous stored VolumeAttachment from the server. // Delete requests the deletion of a previous stored VolumeAttachment from
// the server.
func Delete(client *gophercloud.ServiceClient, serverID, attachmentID string) (r DeleteResult) { func Delete(client *gophercloud.ServiceClient, serverID, attachmentID string) (r DeleteResult) {
_, r.Err = client.Delete(deleteURL(client, serverID, attachmentID), nil) _, r.Err = client.Delete(deleteURL(client, serverID, attachmentID), nil)
return return
......
...@@ -5,35 +5,36 @@ import ( ...@@ -5,35 +5,36 @@ import (
"github.com/gophercloud/gophercloud/pagination" "github.com/gophercloud/gophercloud/pagination"
) )
// VolumeAttachment controls the attachment of a volume to an instance. // VolumeAttachment contains attachment information between a volume
// and server.
type VolumeAttachment struct { type VolumeAttachment struct {
// ID is a unique id of the attachment // ID is a unique id of the attachment.
ID string `json:"id"` ID string `json:"id"`
// Device is what device the volume is attached as // Device is what device the volume is attached as.
Device string `json:"device"` Device string `json:"device"`
// VolumeID is the ID of the attached volume // VolumeID is the ID of the attached volume.
VolumeID string `json:"volumeId"` VolumeID string `json:"volumeId"`
// ServerID is the ID of the instance that has the volume attached // ServerID is the ID of the instance that has the volume attached.
ServerID string `json:"serverId"` ServerID string `json:"serverId"`
} }
// VolumeAttachmentPage stores a single, only page of VolumeAttachments // VolumeAttachmentPage stores a single page all of VolumeAttachment
// results from a List call. // results from a List call.
type VolumeAttachmentPage struct { type VolumeAttachmentPage struct {
pagination.SinglePageBase pagination.SinglePageBase
} }
// IsEmpty determines whether or not a VolumeAttachmentsPage is empty. // IsEmpty determines whether or not a VolumeAttachmentPage is empty.
func (page VolumeAttachmentPage) IsEmpty() (bool, error) { func (page VolumeAttachmentPage) IsEmpty() (bool, error) {
va, err := ExtractVolumeAttachments(page) va, err := ExtractVolumeAttachments(page)
return len(va) == 0, err return len(va) == 0, err
} }
// ExtractVolumeAttachments interprets a page of results as a slice of // ExtractVolumeAttachments interprets a page of results as a slice of
// VolumeAttachments. // VolumeAttachment.
func ExtractVolumeAttachments(r pagination.Page) ([]VolumeAttachment, error) { func ExtractVolumeAttachments(r pagination.Page) ([]VolumeAttachment, error) {
var s struct { var s struct {
VolumeAttachments []VolumeAttachment `json:"volumeAttachments"` VolumeAttachments []VolumeAttachment `json:"volumeAttachments"`
...@@ -57,20 +58,20 @@ func (r VolumeAttachmentResult) Extract() (*VolumeAttachment, error) { ...@@ -57,20 +58,20 @@ func (r VolumeAttachmentResult) Extract() (*VolumeAttachment, error) {
return s.VolumeAttachment, err return s.VolumeAttachment, err
} }
// CreateResult is the response from a Create operation. Call its Extract method to interpret it // CreateResult is the response from a Create operation. Call its Extract method
// as a VolumeAttachment. // to interpret it as a VolumeAttachment.
type CreateResult struct { type CreateResult struct {
VolumeAttachmentResult VolumeAttachmentResult
} }
// GetResult is the response from a Get operation. Call its Extract method to interpret it // GetResult is the response from a Get operation. Call its Extract method to
// as a VolumeAttachment. // interpret it as a VolumeAttachment.
type GetResult struct { type GetResult struct {
VolumeAttachmentResult VolumeAttachmentResult
} }
// DeleteResult is the response from a Delete operation. Call its Extract method to determine if // DeleteResult is the response from a Delete operation. Call its ExtractErr
// the call succeeded or failed. // method to determine if the call succeeded or failed.
type DeleteResult struct { type DeleteResult struct {
gophercloud.ErrResult gophercloud.ErrResult
} }
// Package flavors provides information and interaction with the flavor API /*
// resource in the OpenStack Compute service. Package flavors provides information and interaction with the flavor API
// in the OpenStack Compute service.
// A flavor is an available hardware configuration for a server. Each flavor
// has a unique combination of disk space, memory capacity and priority for CPU A flavor is an available hardware configuration for a server. Each flavor
// time. has a unique combination of disk space, memory capacity and priority for CPU
time.
Example to List Flavors
listOpts := flavors.ListOpts{
AccessType: flavors.PublicAccess,
}
allPages, err := flavors.ListDetail(computeClient, listOpts).AllPages()
if err != nil {
panic(err)
}
allFlavors, err := flavors.ExtractFlavors(allPages)
if err != nil {
panic(err)
}
for _, flavor := range allFlavors {
fmt.Printf("%+v\n", flavor)
}
Example to Create a Flavor
createOpts := flavors.CreateOpts{
ID: "1",
Name: "m1.tiny",
Disk: gophercloud.IntToPointer(1),
RAM: 512,
VCPUs: 1,
RxTxFactor: 1.0,
}
flavor, err := flavors.Create(computeClient, createOpts).Extract()
if err != nil {
panic(err)
}
*/
package flavors package flavors
...@@ -11,33 +11,45 @@ type ListOptsBuilder interface { ...@@ -11,33 +11,45 @@ type ListOptsBuilder interface {
ToFlavorListQuery() (string, error) ToFlavorListQuery() (string, error)
} }
// AccessType maps to OpenStack's Flavor.is_public field. Although the is_public field is boolean, the /*
// request options are ternary, which is why AccessType is a string. The following values are AccessType maps to OpenStack's Flavor.is_public field. Although the is_public
// allowed: field is boolean, the request options are ternary, which is why AccessType is
// a string. The following values are allowed:
// PublicAccess (the default): Returns public flavors and private flavors associated with that project.
// PrivateAccess (admin only): Returns private flavors, across all projects. The AccessType arguement is optional, and if it is not supplied, OpenStack
// AllAccess (admin only): Returns public and private flavors across all projects. returns the PublicAccess flavors.
// */
// The AccessType arguement is optional, and if it is not supplied, OpenStack returns the PublicAccess
// flavors.
type AccessType string type AccessType string
const ( const (
PublicAccess AccessType = "true" // PublicAccess returns public flavors and private flavors associated with
// that project.
PublicAccess AccessType = "true"
// PrivateAccess (admin only) returns private flavors, across all projects.
PrivateAccess AccessType = "false" PrivateAccess AccessType = "false"
AllAccess AccessType = "None"
// AllAccess (admin only) returns public and private flavors across all
// projects.
AllAccess AccessType = "None"
) )
// ListOpts helps control the results returned by the List() function. /*
// For example, a flavor with a minDisk field of 10 will not be returned if you specify MinDisk set to 20. ListOpts filters the results returned by the List() function.
// Typically, software will use the last ID of the previous call to List to set the Marker for the current call. For example, a flavor with a minDisk field of 10 will not be returned if you
specify MinDisk set to 20.
Typically, software will use the last ID of the previous call to List to set
the Marker for the current call.
*/
type ListOpts struct { type ListOpts struct {
// ChangesSince, if provided, instructs List to return only those things which have changed since the timestamp provided. // ChangesSince, if provided, instructs List to return only those things which
// have changed since the timestamp provided.
ChangesSince string `q:"changes-since"` ChangesSince string `q:"changes-since"`
// MinDisk and MinRAM, if provided, elides flavors which do not meet your criteria. // MinDisk and MinRAM, if provided, elides flavors which do not meet your
// criteria.
MinDisk int `q:"minDisk"` MinDisk int `q:"minDisk"`
MinRAM int `q:"minRam"` MinRAM int `q:"minRam"`
...@@ -45,11 +57,12 @@ type ListOpts struct { ...@@ -45,11 +57,12 @@ type ListOpts struct {
// Marker instructs List where to start listing from. // Marker instructs List where to start listing from.
Marker string `q:"marker"` Marker string `q:"marker"`
// Limit instructs List to refrain from sending excessively large lists of flavors. // Limit instructs List to refrain from sending excessively large lists of
// flavors.
Limit int `q:"limit"` Limit int `q:"limit"`
// AccessType, if provided, instructs List which set of flavors to return. If IsPublic not provided, // AccessType, if provided, instructs List which set of flavors to return.
// flavors for the current project are returned. // If IsPublic not provided, flavors for the current project are returned.
AccessType AccessType `q:"is_public"` AccessType AccessType `q:"is_public"`
} }
...@@ -60,8 +73,8 @@ func (opts ListOpts) ToFlavorListQuery() (string, error) { ...@@ -60,8 +73,8 @@ func (opts ListOpts) ToFlavorListQuery() (string, error) {
} }
// ListDetail instructs OpenStack to provide a list of flavors. // ListDetail instructs OpenStack to provide a list of flavors.
// You may provide criteria by which List curtails its results for easier processing. // You may provide criteria by which List curtails its results for easier
// See ListOpts for more details. // processing.
func ListDetail(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { func ListDetail(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
url := listURL(client) url := listURL(client)
if opts != nil { if opts != nil {
...@@ -80,31 +93,42 @@ type CreateOptsBuilder interface { ...@@ -80,31 +93,42 @@ type CreateOptsBuilder interface {
ToFlavorCreateMap() (map[string]interface{}, error) ToFlavorCreateMap() (map[string]interface{}, error)
} }
// CreateOpts is passed to Create to create a flavor // CreateOpts specifies parameters used for creating a flavor.
// Source:
// https://github.com/openstack/nova/blob/stable/newton/nova/api/openstack/compute/schemas/flavor_manage.py#L20
type CreateOpts struct { type CreateOpts struct {
// Name is the name of the flavor.
Name string `json:"name" required:"true"` Name string `json:"name" required:"true"`
// memory size, in MBs
RAM int `json:"ram" required:"true"` // RAM is the memory of the flavor, measured in MB.
RAM int `json:"ram" required:"true"`
// VCPUs is the number of vcpus for the flavor.
VCPUs int `json:"vcpus" required:"true"` VCPUs int `json:"vcpus" required:"true"`
// disk size, in GBs
Disk *int `json:"disk" required:"true"` // Disk the amount of root disk space, measured in GB.
ID string `json:"id,omitempty"` Disk *int `json:"disk" required:"true"`
// non-zero, positive
Swap *int `json:"swap,omitempty"` // ID is a unique ID for the flavor.
ID string `json:"id,omitempty"`
// Swap is the amount of swap space for the flavor, measured in MB.
Swap *int `json:"swap,omitempty"`
// RxTxFactor alters the network bandwidth of a flavor.
RxTxFactor float64 `json:"rxtx_factor,omitempty"` RxTxFactor float64 `json:"rxtx_factor,omitempty"`
IsPublic *bool `json:"os-flavor-access:is_public,omitempty"`
// ephemeral disk size, in GBs, non-zero, positive // IsPublic flags a flavor as being available to all projects or not.
IsPublic *bool `json:"os-flavor-access:is_public,omitempty"`
// Ephemeral is the amount of ephemeral disk space, measured in GB.
Ephemeral *int `json:"OS-FLV-EXT-DATA:ephemeral,omitempty"` Ephemeral *int `json:"OS-FLV-EXT-DATA:ephemeral,omitempty"`
} }
// ToFlavorCreateMap satisfies the CreateOptsBuilder interface // ToFlavorCreateMap constructs a request body from CreateOpts.
func (opts *CreateOpts) ToFlavorCreateMap() (map[string]interface{}, error) { func (opts CreateOpts) ToFlavorCreateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "flavor") return gophercloud.BuildRequestBody(opts, "flavor")
} }
// Create a flavor // Create requests the creation of a new flavor.
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
b, err := opts.ToFlavorCreateMap() b, err := opts.ToFlavorCreateMap()
if err != nil { if err != nil {
...@@ -117,14 +141,21 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r Create ...@@ -117,14 +141,21 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r Create
return return
} }
// Get instructs OpenStack to provide details on a single flavor, identified by its ID. // Get retrieves details of a single flavor. Use ExtractFlavor to convert its
// Use ExtractFlavor to convert its result into a Flavor. // result into a Flavor.
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) { func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
_, r.Err = client.Get(getURL(client, id), &r.Body, nil) _, r.Err = client.Get(getURL(client, id), &r.Body, nil)
return return
} }
// IDFromName is a convienience function that returns a flavor's ID given its name. // Delete deletes the specified flavor ID.
func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
_, r.Err = client.Delete(deleteURL(client, id), nil)
return
}
// IDFromName is a convienience function that returns a flavor's ID given its
// name.
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) { func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
count := 0 count := 0
id := "" id := ""
......
...@@ -16,12 +16,20 @@ type CreateResult struct { ...@@ -16,12 +16,20 @@ type CreateResult struct {
commonResult commonResult
} }
// GetResult temporarily holds the response from a Get call. // GetResult is the response of a Get operations. Call its Extract method to
// interpret it as a Flavor.
type GetResult struct { type GetResult struct {
commonResult commonResult
} }
// Extract provides access to the individual Flavor returned by the Get and Create functions. // DeleteResult is the result from a Delete operation. Call its ExtractErr
// method to determine if the call succeeded or failed.
type DeleteResult struct {
gophercloud.ErrResult
}
// Extract provides access to the individual Flavor returned by the Get and
// Create functions.
func (r commonResult) Extract() (*Flavor, error) { func (r commonResult) Extract() (*Flavor, error) {
var s struct { var s struct {
Flavor *Flavor `json:"flavor"` Flavor *Flavor `json:"flavor"`
...@@ -30,22 +38,30 @@ func (r commonResult) Extract() (*Flavor, error) { ...@@ -30,22 +38,30 @@ func (r commonResult) Extract() (*Flavor, error) {
return s.Flavor, err return s.Flavor, err
} }
// Flavor records represent (virtual) hardware configurations for server resources in a region. // Flavor represent (virtual) hardware configurations for server resources
// in a region.
type Flavor struct { type Flavor struct {
// The Id field contains the flavor's unique identifier. // ID is the flavor's unique ID.
// For example, this identifier will be useful when specifying which hardware configuration to use for a new server instance.
ID string `json:"id"` ID string `json:"id"`
// The Disk and RA< fields provide a measure of storage space offered by the flavor, in GB and MB, respectively.
// Disk is the amount of root disk, measured in GB.
Disk int `json:"disk"` Disk int `json:"disk"`
RAM int `json:"ram"`
// The Name field provides a human-readable moniker for the flavor. // RAM is the amount of memory, measured in MB.
Name string `json:"name"` RAM int `json:"ram"`
// Name is the name of the flavor.
Name string `json:"name"`
// RxTxFactor describes bandwidth alterations of the flavor.
RxTxFactor float64 `json:"rxtx_factor"` RxTxFactor float64 `json:"rxtx_factor"`
// Swap indicates how much space is reserved for swap.
// If not provided, this field will be set to 0. // Swap is the amount of swap space, measured in MB.
Swap int `json:"swap"` Swap int `json:"swap"`
// VCPUs indicates how many (virtual) CPUs are available for this flavor. // VCPUs indicates how many (virtual) CPUs are available for this flavor.
VCPUs int `json:"vcpus"` VCPUs int `json:"vcpus"`
// IsPublic indicates whether the flavor is public. // IsPublic indicates whether the flavor is public.
IsPublic bool `json:"is_public"` IsPublic bool `json:"is_public"`
} }
...@@ -82,18 +98,19 @@ func (r *Flavor) UnmarshalJSON(b []byte) error { ...@@ -82,18 +98,19 @@ func (r *Flavor) UnmarshalJSON(b []byte) error {
return nil return nil
} }
// FlavorPage contains a single page of the response from a List call. // FlavorPage contains a single page of all flavors from a ListDetails call.
type FlavorPage struct { type FlavorPage struct {
pagination.LinkedPageBase pagination.LinkedPageBase
} }
// IsEmpty determines if a page contains any results. // IsEmpty determines if a FlavorPage contains any results.
func (page FlavorPage) IsEmpty() (bool, error) { func (page FlavorPage) IsEmpty() (bool, error) {
flavors, err := ExtractFlavors(page) flavors, err := ExtractFlavors(page)
return len(flavors) == 0, err return len(flavors) == 0, err
} }
// NextPageURL uses the response's embedded link reference to navigate to the next page of results. // NextPageURL uses the response's embedded link reference to navigate to the
// next page of results.
func (page FlavorPage) NextPageURL() (string, error) { func (page FlavorPage) NextPageURL() (string, error) {
var s struct { var s struct {
Links []gophercloud.Link `json:"flavors_links"` Links []gophercloud.Link `json:"flavors_links"`
...@@ -105,7 +122,8 @@ func (page FlavorPage) NextPageURL() (string, error) { ...@@ -105,7 +122,8 @@ func (page FlavorPage) NextPageURL() (string, error) {
return gophercloud.ExtractNextURL(s.Links) return gophercloud.ExtractNextURL(s.Links)
} }
// ExtractFlavors provides access to the list of flavors in a page acquired from the List operation. // ExtractFlavors provides access to the list of flavors in a page acquired
// from the ListDetail operation.
func ExtractFlavors(r pagination.Page) ([]Flavor, error) { func ExtractFlavors(r pagination.Page) ([]Flavor, error) {
var s struct { var s struct {
Flavors []Flavor `json:"flavors"` Flavors []Flavor `json:"flavors"`
......
...@@ -15,3 +15,7 @@ func listURL(client *gophercloud.ServiceClient) string { ...@@ -15,3 +15,7 @@ func listURL(client *gophercloud.ServiceClient) string {
func createURL(client *gophercloud.ServiceClient) string { func createURL(client *gophercloud.ServiceClient) string {
return client.ServiceURL("flavors") return client.ServiceURL("flavors")
} }
func deleteURL(client *gophercloud.ServiceClient, id string) string {
return client.ServiceURL("flavors", id)
}
// Package images provides information and interaction with the image API /*
// resource in the OpenStack Compute service. Package images provides information and interaction with the images through
// the OpenStack Compute service.
// An image is a collection of files used to create or rebuild a server.
// Operators provide a number of pre-built OS images by default. You may also This API is deprecated and will be removed from a future version of the Nova
// create custom images from cloud servers you have launched. API service.
An image is a collection of files used to create or rebuild a server.
Operators provide a number of pre-built OS images by default. You may also
create custom images from cloud servers you have launched.
Example to List Images
listOpts := images.ListOpts{
Limit: 2,
}
allPages, err := images.ListDetail(computeClient, listOpts).AllPages()
if err != nil {
panic(err)
}
allImages, err := images.ExtractImages(allPages)
if err != nil {
panic(err)
}
for _, image := range allImages {
fmt.Printf("%+v\n", image)
}
*/
package images package images
...@@ -6,26 +6,33 @@ import ( ...@@ -6,26 +6,33 @@ import (
) )
// ListOptsBuilder allows extensions to add additional parameters to the // ListOptsBuilder allows extensions to add additional parameters to the
// List request. // ListDetail request.
type ListOptsBuilder interface { type ListOptsBuilder interface {
ToImageListQuery() (string, error) ToImageListQuery() (string, error)
} }
// ListOpts contain options for limiting the number of Images returned from a call to ListDetail. // ListOpts contain options filtering Images returned from a call to ListDetail.
type ListOpts struct { type ListOpts struct {
// When the image last changed status (in date-time format). // ChangesSince filters Images based on the last changed status (in date-time
// format).
ChangesSince string `q:"changes-since"` ChangesSince string `q:"changes-since"`
// The number of Images to return.
// Limit limits the number of Images to return.
Limit int `q:"limit"` Limit int `q:"limit"`
// UUID of the Image at which to set a marker.
// Mark is an Image UUID at which to set a marker.
Marker string `q:"marker"` Marker string `q:"marker"`
// The name of the Image.
// Name is the name of the Image.
Name string `q:"name"` Name string `q:"name"`
// The name of the Server (in URL format).
// Server is the name of the Server (in URL format).
Server string `q:"server"` Server string `q:"server"`
// The current status of the Image.
// Status is the current status of the Image.
Status string `q:"status"` Status string `q:"status"`
// The value of the type of image (e.g. BASE, SERVER, ALL)
// Type is the type of image (e.g. BASE, SERVER, ALL).
Type string `q:"type"` Type string `q:"type"`
} }
...@@ -50,8 +57,7 @@ func ListDetail(client *gophercloud.ServiceClient, opts ListOptsBuilder) paginat ...@@ -50,8 +57,7 @@ func ListDetail(client *gophercloud.ServiceClient, opts ListOptsBuilder) paginat
}) })
} }
// Get acquires additional detail about a specific image by ID. // Get returns data about a specific image by its ID.
// Use ExtractImage() to interpret the result as an openstack Image.
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) { func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
_, r.Err = client.Get(getURL(client, id), &r.Body, nil) _, r.Err = client.Get(getURL(client, id), &r.Body, nil)
return return
...@@ -63,7 +69,8 @@ func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) { ...@@ -63,7 +69,8 @@ func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
return return
} }
// IDFromName is a convienience function that returns an image's ID given its name. // IDFromName is a convienience function that returns an image's ID given its
// name.
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) { func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
count := 0 count := 0
id := "" id := ""
......
...@@ -5,12 +5,14 @@ import ( ...@@ -5,12 +5,14 @@ import (
"github.com/gophercloud/gophercloud/pagination" "github.com/gophercloud/gophercloud/pagination"
) )
// GetResult temporarily stores a Get response. // GetResult is the response from a Get operation. Call its Extract method to
// interpret it as an Image.
type GetResult struct { type GetResult struct {
gophercloud.Result gophercloud.Result
} }
// DeleteResult represents the result of an image.Delete operation. // DeleteResult is the result from a Delete operation. Call its ExtractErr
// method to determine if the call succeeded or failed.
type DeleteResult struct { type DeleteResult struct {
gophercloud.ErrResult gophercloud.ErrResult
} }
...@@ -24,44 +26,53 @@ func (r GetResult) Extract() (*Image, error) { ...@@ -24,44 +26,53 @@ func (r GetResult) Extract() (*Image, error) {
return s.Image, err return s.Image, err
} }
// Image is used for JSON (un)marshalling. // Image represents an Image returned by the Compute API.
// It provides a description of an OS image.
type Image struct { type Image struct {
// ID contains the image's unique identifier. // ID is the unique ID of an image.
ID string ID string
// Created is the date when the image was created.
Created string Created string
// MinDisk and MinRAM specify the minimum resources a server must provide to be able to install the image. // MinDisk is the minimum amount of disk a flavor must have to be able
// to create a server based on the image, measured in GB.
MinDisk int MinDisk int
MinRAM int
// MinRAM is the minimum amount of RAM a flavor must have to be able
// to create a server based on the image, measured in MB.
MinRAM int
// Name provides a human-readable moniker for the OS image. // Name provides a human-readable moniker for the OS image.
Name string Name string
// The Progress and Status fields indicate image-creation status. // The Progress and Status fields indicate image-creation status.
// Any usable image will have 100% progress.
Progress int Progress int
Status string
// Status is the current status of the image.
Status string
// Update is the date when the image was updated.
Updated string Updated string
// Metadata provides free-form key/value pairs that further describe the
// image.
Metadata map[string]interface{} Metadata map[string]interface{}
} }
// ImagePage contains a single page of results from a List operation. // ImagePage contains a single page of all Images returne from a ListDetail
// Use ExtractImages to convert it into a slice of usable structs. // operation. Use ExtractImages to convert it into a slice of usable structs.
type ImagePage struct { type ImagePage struct {
pagination.LinkedPageBase pagination.LinkedPageBase
} }
// IsEmpty returns true if a page contains no Image results. // IsEmpty returns true if an ImagePage contains no Image results.
func (page ImagePage) IsEmpty() (bool, error) { func (page ImagePage) IsEmpty() (bool, error) {
images, err := ExtractImages(page) images, err := ExtractImages(page)
return len(images) == 0, err return len(images) == 0, err
} }
// NextPageURL uses the response's embedded link reference to navigate to the next page of results. // NextPageURL uses the response's embedded link reference to navigate to the
// next page of results.
func (page ImagePage) NextPageURL() (string, error) { func (page ImagePage) NextPageURL() (string, error) {
var s struct { var s struct {
Links []gophercloud.Link `json:"images_links"` Links []gophercloud.Link `json:"images_links"`
...@@ -73,7 +84,8 @@ func (page ImagePage) NextPageURL() (string, error) { ...@@ -73,7 +84,8 @@ func (page ImagePage) NextPageURL() (string, error) {
return gophercloud.ExtractNextURL(s.Links) return gophercloud.ExtractNextURL(s.Links)
} }
// ExtractImages converts a page of List results into a slice of usable Image structs. // ExtractImages converts a page of List results into a slice of usable Image
// structs.
func ExtractImages(r pagination.Page) ([]Image, error) { func ExtractImages(r pagination.Page) ([]Image, error) {
var s struct { var s struct {
Images []Image `json:"images"` Images []Image `json:"images"`
......
// Package servers provides information and interaction with the server API /*
// resource in the OpenStack Compute service. Package servers provides information and interaction with the server API
// resource in the OpenStack Compute service.
// A server is a virtual machine instance in the compute system. In order for
// one to be provisioned, a valid flavor and image are required. A server is a virtual machine instance in the compute system. In order for
one to be provisioned, a valid flavor and image are required.
Example to List Servers
listOpts := servers.ListOpts{
AllTenants: true,
}
allPages, err := servers.List(computeClient, listOpts).AllPages()
if err != nil {
panic(err)
}
allServers, err := servers.ExtractServers(allPages)
if err != nil {
panic(err)
}
for _, server := range allServers {
fmt.Printf("%+v\n", server)
}
Example to Create a Server
createOpts := servers.CreateOpts{
Name: "server_name",
ImageRef: "image-uuid",
FlavorRef: "flavor-uuid",
}
server, err := servers.Create(computeClient, createOpts).Extract()
if err != nil {
panic(err)
}
Example to Delete a Server
serverID := "d9072956-1560-487c-97f2-18bdf65ec749"
err := servers.Delete(computeClient, serverID).ExtractErr()
if err != nil {
panic(err)
}
Example to Force Delete a Server
serverID := "d9072956-1560-487c-97f2-18bdf65ec749"
err := servers.ForceDelete(computeClient, serverID).ExtractErr()
if err != nil {
panic(err)
}
Example to Reboot a Server
rebootOpts := servers.RebootOpts{
Type: servers.SoftReboot,
}
serverID := "d9072956-1560-487c-97f2-18bdf65ec749"
err := servers.Reboot(computeClient, serverID, rebootOpts).ExtractErr()
if err != nil {
panic(err)
}
Example to Rebuild a Server
rebuildOpts := servers.RebuildOpts{
Name: "new_name",
ImageID: "image-uuid",
}
serverID := "d9072956-1560-487c-97f2-18bdf65ec749"
server, err := servers.Rebuilt(computeClient, serverID, rebuildOpts).Extract()
if err != nil {
panic(err)
}
Example to Resize a Server
resizeOpts := servers.ResizeOpts{
FlavorRef: "flavor-uuid",
}
serverID := "d9072956-1560-487c-97f2-18bdf65ec749"
err := servers.Resize(computeClient, serverID, resizeOpts).ExtractErr()
if err != nil {
panic(err)
}
err = servers.ConfirmResize(computeClient, serverID).ExtractErr()
if err != nil {
panic(err)
}
Example to Snapshot a Server
snapshotOpts := servers.CreateImageOpts{
Name: "snapshot_name",
}
serverID := "d9072956-1560-487c-97f2-18bdf65ec749"
image, err := servers.CreateImage(computeClient, serverID, snapshotOpts).ExtractImageID()
if err != nil {
panic(err)
}
*/
package servers package servers
...@@ -2,8 +2,9 @@ package servers ...@@ -2,8 +2,9 @@ package servers
import "github.com/gophercloud/gophercloud" import "github.com/gophercloud/gophercloud"
// WaitForStatus will continually poll a server until it successfully transitions to a specified // WaitForStatus will continually poll a server until it successfully
// status. It will do this for at most the number of seconds specified. // transitions to a specified status. It will do this for at most the number
// of seconds specified.
func WaitForStatus(c *gophercloud.ServiceClient, id, status string, secs int) error { func WaitForStatus(c *gophercloud.ServiceClient, id, status string, secs int) error {
return gophercloud.WaitFor(secs, func() (bool, error) { return gophercloud.WaitFor(secs, func() (bool, error) {
current, err := Get(c, id).Extract() current, err := Get(c, id).Extract()
......
/*
Package openstack contains resources for the individual OpenStack projects
supported in Gophercloud. It also includes functions to authenticate to an
OpenStack cloud and for provisioning various service-level clients.
Example of Creating a Service Client
ao, err := openstack.AuthOptionsFromEnv()
provider, err := openstack.AuthenticatedClient(ao)
client, err := openstack.NewNetworkV2(client, gophercloud.EndpointOpts{
Region: os.Getenv("OS_REGION_NAME"),
})
*/
package openstack
...@@ -6,12 +6,16 @@ import ( ...@@ -6,12 +6,16 @@ import (
tokens3 "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens" tokens3 "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
) )
// V2EndpointURL discovers the endpoint URL for a specific service from a ServiceCatalog acquired /*
// during the v2 identity service. The specified EndpointOpts are used to identify a unique, V2EndpointURL discovers the endpoint URL for a specific service from a
// unambiguous endpoint to return. It's an error both when multiple endpoints match the provided ServiceCatalog acquired during the v2 identity service.
// criteria and when none do. The minimum that can be specified is a Type, but you will also often
// need to specify a Name and/or a Region depending on what's available on your OpenStack The specified EndpointOpts are used to identify a unique, unambiguous endpoint
// deployment. to return. It's an error both when multiple endpoints match the provided
criteria and when none do. The minimum that can be specified is a Type, but you
will also often need to specify a Name and/or a Region depending on what's
available on your OpenStack deployment.
*/
func V2EndpointURL(catalog *tokens2.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) { func V2EndpointURL(catalog *tokens2.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) {
// Extract Endpoints from the catalog entries that match the requested Type, Name if provided, and Region if provided. // Extract Endpoints from the catalog entries that match the requested Type, Name if provided, and Region if provided.
var endpoints = make([]tokens2.Endpoint, 0, 1) var endpoints = make([]tokens2.Endpoint, 0, 1)
...@@ -54,12 +58,16 @@ func V2EndpointURL(catalog *tokens2.ServiceCatalog, opts gophercloud.EndpointOpt ...@@ -54,12 +58,16 @@ func V2EndpointURL(catalog *tokens2.ServiceCatalog, opts gophercloud.EndpointOpt
return "", err return "", err
} }
// V3EndpointURL discovers the endpoint URL for a specific service from a Catalog acquired /*
// during the v3 identity service. The specified EndpointOpts are used to identify a unique, V3EndpointURL discovers the endpoint URL for a specific service from a Catalog
// unambiguous endpoint to return. It's an error both when multiple endpoints match the provided acquired during the v3 identity service.
// criteria and when none do. The minimum that can be specified is a Type, but you will also often
// need to specify a Name and/or a Region depending on what's available on your OpenStack The specified EndpointOpts are used to identify a unique, unambiguous endpoint
// deployment. to return. It's an error both when multiple endpoints match the provided
criteria and when none do. The minimum that can be specified is a Type, but you
will also often need to specify a Name and/or a Region depending on what's
available on your OpenStack deployment.
*/
func V3EndpointURL(catalog *tokens3.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) { func V3EndpointURL(catalog *tokens3.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) {
// Extract Endpoints from the catalog entries that match the requested Type, Interface, // Extract Endpoints from the catalog entries that match the requested Type, Interface,
// Name if provided, and Region if provided. // Name if provided, and Region if provided.
......
// Package tenants provides information and interaction with the /*
// tenants API resource for the OpenStack Identity service. Package tenants provides information and interaction with the
// tenants API resource for the OpenStack Identity service.
// See http://developer.openstack.org/api-ref-identity-v2.html#identity-auth-v2
// and http://developer.openstack.org/api-ref-identity-v2.html#admin-tenants See http://developer.openstack.org/api-ref-identity-v2.html#identity-auth-v2
// for more information. and http://developer.openstack.org/api-ref-identity-v2.html#admin-tenants
for more information.
Example to List Tenants
listOpts := tenants.ListOpts{
Limit: 2,
}
allPages, err := tenants.List(identityClient, listOpts).AllPages()
if err != nil {
panic(err)
}
allTenants, err := tenants.ExtractTenants(allPages)
if err != nil {
panic(err)
}
for _, tenant := range allTenants {
fmt.Printf("%+v\n", tenant)
}
Example to Create a Tenant
createOpts := tenants.CreateOpts{
Name: "tenant_name",
Description: "this is a tenant",
Enabled: gophercloud.Enabled,
}
tenant, err := tenants.Create(identityClient, createOpts).Extract()
if err != nil {
panic(err)
}
Example to Update a Tenant
tenantID := "e6db6ed6277c461a853458589063b295"
updateOpts := tenants.UpdateOpts{
Description: "this is a new description",
Enabled: gophercloud.Disabled,
}
tenant, err := tenants.Update(identityClient, tenantID, updateOpts).Extract()
if err != nil {
panic(err)
}
Example to Delete a Tenant
tenantID := "e6db6ed6277c461a853458589063b295"
err := tenants.Delete(identitYClient, tenantID).ExtractErr()
if err != nil {
panic(err)
}
*/
package tenants package tenants
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
type ListOpts struct { type ListOpts struct {
// Marker is the ID of the last Tenant on the previous page. // Marker is the ID of the last Tenant on the previous page.
Marker string `q:"marker"` Marker string `q:"marker"`
// Limit specifies the page size. // Limit specifies the page size.
Limit int `q:"limit"` Limit int `q:"limit"`
} }
...@@ -32,18 +33,22 @@ func List(client *gophercloud.ServiceClient, opts *ListOpts) pagination.Pager { ...@@ -32,18 +33,22 @@ func List(client *gophercloud.ServiceClient, opts *ListOpts) pagination.Pager {
type CreateOpts struct { type CreateOpts struct {
// Name is the name of the tenant. // Name is the name of the tenant.
Name string `json:"name" required:"true"` Name string `json:"name" required:"true"`
// Description is the description of the tenant. // Description is the description of the tenant.
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
// Enabled sets the tenant status to enabled or disabled. // Enabled sets the tenant status to enabled or disabled.
Enabled *bool `json:"enabled,omitempty"` Enabled *bool `json:"enabled,omitempty"`
} }
// CreateOptsBuilder describes struct types that can be accepted by the Create call. // CreateOptsBuilder enables extensions to add additional parameters to the
// Create request.
type CreateOptsBuilder interface { type CreateOptsBuilder interface {
ToTenantCreateMap() (map[string]interface{}, error) ToTenantCreateMap() (map[string]interface{}, error)
} }
// ToTenantCreateMap assembles a request body based on the contents of a CreateOpts. // ToTenantCreateMap assembles a request body based on the contents of
// a CreateOpts.
func (opts CreateOpts) ToTenantCreateMap() (map[string]interface{}, error) { func (opts CreateOpts) ToTenantCreateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "tenant") return gophercloud.BuildRequestBody(opts, "tenant")
} }
...@@ -67,17 +72,21 @@ func Get(client *gophercloud.ServiceClient, id string) (r GetResult) { ...@@ -67,17 +72,21 @@ func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
return return
} }
// UpdateOptsBuilder allows extensions to add additional attributes to the Update request. // UpdateOptsBuilder allows extensions to add additional parameters to the
// Update request.
type UpdateOptsBuilder interface { type UpdateOptsBuilder interface {
ToTenantUpdateMap() (map[string]interface{}, error) ToTenantUpdateMap() (map[string]interface{}, error)
} }
// UpdateOpts specifies the base attributes that may be updated on an existing server. // UpdateOpts specifies the base attributes that may be updated on an existing
// tenant.
type UpdateOpts struct { type UpdateOpts struct {
// Name is the name of the tenant. // Name is the name of the tenant.
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
// Description is the description of the tenant. // Description is the description of the tenant.
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
// Enabled sets the tenant status to enabled or disabled. // Enabled sets the tenant status to enabled or disabled.
Enabled *bool `json:"enabled,omitempty"` Enabled *bool `json:"enabled,omitempty"`
} }
...@@ -100,7 +109,7 @@ func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder ...@@ -100,7 +109,7 @@ func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder
return return
} }
// Delete is the operation responsible for permanently deleting an API tenant. // Delete is the operation responsible for permanently deleting a tenant.
func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) { func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
_, r.Err = client.Delete(deleteURL(client, id), nil) _, r.Err = client.Delete(deleteURL(client, id), nil)
return return
......
...@@ -43,7 +43,8 @@ func (r TenantPage) NextPageURL() (string, error) { ...@@ -43,7 +43,8 @@ func (r TenantPage) NextPageURL() (string, error) {
return gophercloud.ExtractNextURL(s.Links) return gophercloud.ExtractNextURL(s.Links)
} }
// ExtractTenants returns a slice of Tenants contained in a single page of results. // ExtractTenants returns a slice of Tenants contained in a single page of
// results.
func ExtractTenants(r pagination.Page) ([]Tenant, error) { func ExtractTenants(r pagination.Page) ([]Tenant, error) {
var s struct { var s struct {
Tenants []Tenant `json:"tenants"` Tenants []Tenant `json:"tenants"`
...@@ -56,7 +57,7 @@ type tenantResult struct { ...@@ -56,7 +57,7 @@ type tenantResult struct {
gophercloud.Result gophercloud.Result
} }
// Extract interprets any tenantResults as a tenant. // Extract interprets any tenantResults as a Tenant.
func (r tenantResult) Extract() (*Tenant, error) { func (r tenantResult) Extract() (*Tenant, error) {
var s struct { var s struct {
Tenant *Tenant `json:"tenant"` Tenant *Tenant `json:"tenant"`
...@@ -65,22 +66,26 @@ func (r tenantResult) Extract() (*Tenant, error) { ...@@ -65,22 +66,26 @@ func (r tenantResult) Extract() (*Tenant, error) {
return s.Tenant, err return s.Tenant, err
} }
// GetResult temporarily contains the response from the Get call. // GetResult is the response from a Get request. Call its Extract method to
// interpret it as a Tenant.
type GetResult struct { type GetResult struct {
tenantResult tenantResult
} }
// CreateResult temporarily contains the reponse from the Create call. // CreateResult is the response from a Create request. Call its Extract method
// to interpret it as a Tenant.
type CreateResult struct { type CreateResult struct {
tenantResult tenantResult
} }
// DeleteResult temporarily contains the response from the Delete call. // DeleteResult is the response from a Get request. Call its ExtractErr method
// to determine if the call succeeded or failed.
type DeleteResult struct { type DeleteResult struct {
gophercloud.ErrResult gophercloud.ErrResult
} }
// UpdateResult temporarily contains the response from the Update call. // UpdateResult is the response from a Update request. Call its Extract method
// to interpret it as a Tenant.
type UpdateResult struct { type UpdateResult struct {
tenantResult tenantResult
} }
// Package tokens provides information and interaction with the token API /*
// resource for the OpenStack Identity service. Package tokens provides information and interaction with the token API
// For more information, see: resource for the OpenStack Identity service.
// http://developer.openstack.org/api-ref-identity-v2.html#identity-auth-v2
For more information, see:
http://developer.openstack.org/api-ref-identity-v2.html#identity-auth-v2
Example to Create an Unscoped Token from a Password
authOpts := gophercloud.AuthOptions{
Username: "user",
Password: "pass"
}
token, err := tokens.Create(identityClient, authOpts).ExtractToken()
if err != nil {
panic(err)
}
Example to Create a Token from a Tenant ID and Password
authOpts := gophercloud.AuthOptions{
Username: "user",
Password: "password",
TenantID: "fc394f2ab2df4114bde39905f800dc57"
}
token, err := tokens.Create(identityClient, authOpts).ExtractToken()
if err != nil {
panic(err)
}
Example to Create a Token from a Tenant Name and Password
authOpts := gophercloud.AuthOptions{
Username: "user",
Password: "password",
TenantName: "tenantname"
}
token, err := tokens.Create(identityClient, authOpts).ExtractToken()
if err != nil {
panic(err)
}
*/
package tokens package tokens
...@@ -2,17 +2,21 @@ package tokens ...@@ -2,17 +2,21 @@ package tokens
import "github.com/gophercloud/gophercloud" import "github.com/gophercloud/gophercloud"
// PasswordCredentialsV2 represents the required options to authenticate
// with a username and password.
type PasswordCredentialsV2 struct { type PasswordCredentialsV2 struct {
Username string `json:"username" required:"true"` Username string `json:"username" required:"true"`
Password string `json:"password" required:"true"` Password string `json:"password" required:"true"`
} }
// TokenCredentialsV2 represents the required options to authenticate
// with a token.
type TokenCredentialsV2 struct { type TokenCredentialsV2 struct {
ID string `json:"id,omitempty" required:"true"` ID string `json:"id,omitempty" required:"true"`
} }
// AuthOptionsV2 wraps a gophercloud AuthOptions in order to adhere to the AuthOptionsBuilder // AuthOptionsV2 wraps a gophercloud AuthOptions in order to adhere to the
// interface. // AuthOptionsBuilder interface.
type AuthOptionsV2 struct { type AuthOptionsV2 struct {
PasswordCredentials *PasswordCredentialsV2 `json:"passwordCredentials,omitempty" xor:"TokenCredentials"` PasswordCredentials *PasswordCredentialsV2 `json:"passwordCredentials,omitempty" xor:"TokenCredentials"`
...@@ -23,15 +27,16 @@ type AuthOptionsV2 struct { ...@@ -23,15 +27,16 @@ type AuthOptionsV2 struct {
TenantID string `json:"tenantId,omitempty"` TenantID string `json:"tenantId,omitempty"`
TenantName string `json:"tenantName,omitempty"` TenantName string `json:"tenantName,omitempty"`
// TokenCredentials allows users to authenticate (possibly as another user) with an // TokenCredentials allows users to authenticate (possibly as another user)
// authentication token ID. // with an authentication token ID.
TokenCredentials *TokenCredentialsV2 `json:"token,omitempty" xor:"PasswordCredentials"` TokenCredentials *TokenCredentialsV2 `json:"token,omitempty" xor:"PasswordCredentials"`
} }
// AuthOptionsBuilder describes any argument that may be passed to the Create call. // AuthOptionsBuilder allows extensions to add additional parameters to the
// token create request.
type AuthOptionsBuilder interface { type AuthOptionsBuilder interface {
// ToTokenCreateMap assembles the Create request body, returning an error if parameters are // ToTokenCreateMap assembles the Create request body, returning an error
// missing or inconsistent. // if parameters are missing or inconsistent.
ToTokenV2CreateMap() (map[string]interface{}, error) ToTokenV2CreateMap() (map[string]interface{}, error)
} }
...@@ -47,8 +52,7 @@ type AuthOptions struct { ...@@ -47,8 +52,7 @@ type AuthOptions struct {
TokenID string TokenID string
} }
// ToTokenV2CreateMap allows AuthOptions to satisfy the AuthOptionsBuilder // ToTokenV2CreateMap builds a token request body from the given AuthOptions.
// interface in the v2 tokens package
func (opts AuthOptions) ToTokenV2CreateMap() (map[string]interface{}, error) { func (opts AuthOptions) ToTokenV2CreateMap() (map[string]interface{}, error) {
v2Opts := AuthOptionsV2{ v2Opts := AuthOptionsV2{
TenantID: opts.TenantID, TenantID: opts.TenantID,
...@@ -74,9 +78,9 @@ func (opts AuthOptions) ToTokenV2CreateMap() (map[string]interface{}, error) { ...@@ -74,9 +78,9 @@ func (opts AuthOptions) ToTokenV2CreateMap() (map[string]interface{}, error) {
} }
// Create authenticates to the identity service and attempts to acquire a Token. // Create authenticates to the identity service and attempts to acquire a Token.
// If successful, the CreateResult // Generally, rather than interact with this call directly, end users should
// Generally, rather than interact with this call directly, end users should call openstack.AuthenticatedClient(), // call openstack.AuthenticatedClient(), which abstracts all of the gory details
// which abstracts all of the gory details about navigating service catalogs and such. // about navigating service catalogs and such.
func Create(client *gophercloud.ServiceClient, auth AuthOptionsBuilder) (r CreateResult) { func Create(client *gophercloud.ServiceClient, auth AuthOptionsBuilder) (r CreateResult) {
b, err := auth.ToTokenV2CreateMap() b, err := auth.ToTokenV2CreateMap()
if err != nil { if err != nil {
......
...@@ -7,20 +7,24 @@ import ( ...@@ -7,20 +7,24 @@ import (
"github.com/gophercloud/gophercloud/openstack/identity/v2/tenants" "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants"
) )
// Token provides only the most basic information related to an authentication token. // Token provides only the most basic information related to an authentication
// token.
type Token struct { type Token struct {
// ID provides the primary means of identifying a user to the OpenStack API. // ID provides the primary means of identifying a user to the OpenStack API.
// OpenStack defines this field as an opaque value, so do not depend on its content. // OpenStack defines this field as an opaque value, so do not depend on its
// It is safe, however, to compare for equality. // content. It is safe, however, to compare for equality.
ID string ID string
// ExpiresAt provides a timestamp in ISO 8601 format, indicating when the authentication token becomes invalid. // ExpiresAt provides a timestamp in ISO 8601 format, indicating when the
// After this point in time, future API requests made using this authentication token will respond with errors. // authentication token becomes invalid. After this point in time, future
// Either the caller will need to reauthenticate manually, or more preferably, the caller should exploit automatic re-authentication. // API requests made using this authentication token will respond with
// errors. Either the caller will need to reauthenticate manually, or more
// preferably, the caller should exploit automatic re-authentication.
// See the AuthOptions structure for more details. // See the AuthOptions structure for more details.
ExpiresAt time.Time ExpiresAt time.Time
// Tenant provides information about the tenant to which this token grants access. // Tenant provides information about the tenant to which this token grants
// access.
Tenant tenants.Tenant Tenant tenants.Tenant
} }
...@@ -38,13 +42,17 @@ type User struct { ...@@ -38,13 +42,17 @@ type User struct {
} }
// Endpoint represents a single API endpoint offered by a service. // Endpoint represents a single API endpoint offered by a service.
// It provides the public and internal URLs, if supported, along with a region specifier, again if provided. // It provides the public and internal URLs, if supported, along with a region
// specifier, again if provided.
//
// The significance of the Region field will depend upon your provider. // The significance of the Region field will depend upon your provider.
// //
// In addition, the interface offered by the service will have version information associated with it // In addition, the interface offered by the service will have version
// through the VersionId, VersionInfo, and VersionList fields, if provided or supported. // information associated with it through the VersionId, VersionInfo, and
// VersionList fields, if provided or supported.
// //
// In all cases, fields which aren't supported by the provider and service combined will assume a zero-value (""). // In all cases, fields which aren't supported by the provider and service
// combined will assume a zero-value ("").
type Endpoint struct { type Endpoint struct {
TenantID string `json:"tenantId"` TenantID string `json:"tenantId"`
PublicURL string `json:"publicURL"` PublicURL string `json:"publicURL"`
...@@ -56,38 +64,44 @@ type Endpoint struct { ...@@ -56,38 +64,44 @@ type Endpoint struct {
VersionList string `json:"versionList"` VersionList string `json:"versionList"`
} }
// CatalogEntry provides a type-safe interface to an Identity API V2 service catalog listing. // CatalogEntry provides a type-safe interface to an Identity API V2 service
// Each class of service, such as cloud DNS or block storage services, will have a single // catalog listing.
// CatalogEntry representing it. //
// Each class of service, such as cloud DNS or block storage services, will have
// a single CatalogEntry representing it.
// //
// Note: when looking for the desired service, try, whenever possible, to key off the type field. // Note: when looking for the desired service, try, whenever possible, to key
// Otherwise, you'll tie the representation of the service to a specific provider. // off the type field. Otherwise, you'll tie the representation of the service
// to a specific provider.
type CatalogEntry struct { type CatalogEntry struct {
// Name will contain the provider-specified name for the service. // Name will contain the provider-specified name for the service.
Name string `json:"name"` Name string `json:"name"`
// Type will contain a type string if OpenStack defines a type for the service. // Type will contain a type string if OpenStack defines a type for the
// Otherwise, for provider-specific services, the provider may assign their own type strings. // service. Otherwise, for provider-specific services, the provider may assign
// their own type strings.
Type string `json:"type"` Type string `json:"type"`
// Endpoints will let the caller iterate over all the different endpoints that may exist for // Endpoints will let the caller iterate over all the different endpoints that
// the service. // may exist for the service.
Endpoints []Endpoint `json:"endpoints"` Endpoints []Endpoint `json:"endpoints"`
} }
// ServiceCatalog provides a view into the service catalog from a previous, successful authentication. // ServiceCatalog provides a view into the service catalog from a previous,
// successful authentication.
type ServiceCatalog struct { type ServiceCatalog struct {
Entries []CatalogEntry Entries []CatalogEntry
} }
// CreateResult defers the interpretation of a created token. // CreateResult is the response from a Create request. Use ExtractToken() to
// Use ExtractToken() to interpret it as a Token, or ExtractServiceCatalog() to interpret it as a service catalog. // interpret it as a Token, or ExtractServiceCatalog() to interpret it as a
// service catalog.
type CreateResult struct { type CreateResult struct {
gophercloud.Result gophercloud.Result
} }
// GetResult is the deferred response from a Get call, which is the same with a Created token. // GetResult is the deferred response from a Get call, which is the same with a
// Use ExtractUser() to interpret it as a User. // Created token. Use ExtractUser() to interpret it as a User.
type GetResult struct { type GetResult struct {
CreateResult CreateResult
} }
...@@ -121,7 +135,8 @@ func (r CreateResult) ExtractToken() (*Token, error) { ...@@ -121,7 +135,8 @@ func (r CreateResult) ExtractToken() (*Token, error) {
}, nil }, nil
} }
// ExtractServiceCatalog returns the ServiceCatalog that was generated along with the user's Token. // ExtractServiceCatalog returns the ServiceCatalog that was generated along
// with the user's Token.
func (r CreateResult) ExtractServiceCatalog() (*ServiceCatalog, error) { func (r CreateResult) ExtractServiceCatalog() (*ServiceCatalog, error) {
var s struct { var s struct {
Access struct { Access struct {
......
...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") ...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"doc.go",
"requests.go", "requests.go",
"results.go", "results.go",
], ],
......
/*
Package trusts enables management of OpenStack Identity Trusts.
Example to Create a Token with Username, Password, and Trust ID
var trustToken struct {
tokens.Token
trusts.TokenExt
}
authOptions := tokens.AuthOptions{
UserID: "username",
Password: "password",
}
createOpts := trusts.AuthOptsExt{
AuthOptionsBuilder: authOptions,
TrustID: "de0945a",
}
err := tokens.Create(identityClient, createOpts).ExtractInto(&trustToken)
if err != nil {
panic(err)
}
*/
package trusts
...@@ -2,15 +2,20 @@ package trusts ...@@ -2,15 +2,20 @@ package trusts
import "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens" import "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
// AuthOptsExt extends the base Identity v3 tokens AuthOpts with a TrustID.
type AuthOptsExt struct { type AuthOptsExt struct {
tokens.AuthOptionsBuilder tokens.AuthOptionsBuilder
// TrustID is the ID of the trust.
TrustID string `json:"id"` TrustID string `json:"id"`
} }
// ToTokenV3CreateMap builds a create request body from the AuthOpts.
func (opts AuthOptsExt) ToTokenV3CreateMap(scope map[string]interface{}) (map[string]interface{}, error) { func (opts AuthOptsExt) ToTokenV3CreateMap(scope map[string]interface{}) (map[string]interface{}, error) {
return opts.AuthOptionsBuilder.ToTokenV3CreateMap(scope) return opts.AuthOptionsBuilder.ToTokenV3CreateMap(scope)
} }
// ToTokenV3ScopeMap builds a scope from AuthOpts.
func (opts AuthOptsExt) ToTokenV3ScopeMap() (map[string]interface{}, error) { func (opts AuthOptsExt) ToTokenV3ScopeMap() (map[string]interface{}, error) {
b, err := opts.AuthOptionsBuilder.ToTokenV3ScopeMap() b, err := opts.AuthOptionsBuilder.ToTokenV3ScopeMap()
if err != nil { if err != nil {
......
package trusts package trusts
// TrusteeUser represents the trusted user ID of a trust.
type TrusteeUser struct { type TrusteeUser struct {
ID string `json:"id"` ID string `json:"id"`
} }
// TrustorUser represents the trusting user ID of a trust.
type TrustorUser struct { type TrustorUser struct {
ID string `json:"id"` ID string `json:"id"`
} }
// Trust represents a delegated authorization request between two
// identities.
type Trust struct { type Trust struct {
ID string `json:"id"` ID string `json:"id"`
Impersonation bool `json:"impersonation"` Impersonation bool `json:"impersonation"`
...@@ -17,6 +21,7 @@ type Trust struct { ...@@ -17,6 +21,7 @@ type Trust struct {
RedelegationCount int `json:"redelegation_count"` RedelegationCount int `json:"redelegation_count"`
} }
// TokenExt represents an extension of the base token result.
type TokenExt struct { type TokenExt struct {
Trust Trust `json:"OS-TRUST:trust"` Trust Trust `json:"OS-TRUST:trust"`
} }
// Package tokens provides information and interaction with the token API /*
// resource for the OpenStack Identity service. Package tokens provides information and interaction with the token API
// resource for the OpenStack Identity service.
// For more information, see:
// http://developer.openstack.org/api-ref-identity-v3.html#tokens-v3 For more information, see:
http://developer.openstack.org/api-ref-identity-v3.html#tokens-v3
Example to Create a Token From a Username and Password
authOptions := tokens.AuthOptions{
UserID: "username",
Password: "password",
}
token, err := tokens.Create(identityClient, authOptions).ExtractToken()
if err != nil {
panic(err)
}
Example to Create a Token From a Username, Password, and Domain
authOptions := tokens.AuthOptions{
UserID: "username",
Password: "password",
DomainID: "default",
}
token, err := tokens.Create(identityClient, authOptions).ExtractToken()
if err != nil {
panic(err)
}
authOptions = tokens.AuthOptions{
UserID: "username",
Password: "password",
DomainName: "default",
}
token, err = tokens.Create(identityClient, authOptions).ExtractToken()
if err != nil {
panic(err)
}
Example to Create a Token From a Token
authOptions := tokens.AuthOptions{
TokenID: "token_id",
}
token, err := tokens.Create(identityClient, authOptions).ExtractToken()
if err != nil {
panic(err)
}
Example to Create a Token from a Username and Password with Project ID Scope
scope := tokens.Scope{
ProjectID: "0fe36e73809d46aeae6705c39077b1b3",
}
authOptions := tokens.AuthOptions{
Scope: &scope,
UserID: "username",
Password: "password",
}
token, err = tokens.Create(identityClient, authOptions).ExtractToken()
if err != nil {
panic(err)
}
Example to Create a Token from a Username and Password with Domain ID Scope
scope := tokens.Scope{
DomainID: "default",
}
authOptions := tokens.AuthOptions{
Scope: &scope,
UserID: "username",
Password: "password",
}
token, err = tokens.Create(identityClient, authOptions).ExtractToken()
if err != nil {
panic(err)
}
Example to Create a Token from a Username and Password with Project Name Scope
scope := tokens.Scope{
ProjectName: "project_name",
DomainID: "default",
}
authOptions := tokens.AuthOptions{
Scope: &scope,
UserID: "username",
Password: "password",
}
token, err = tokens.Create(identityClient, authOptions).ExtractToken()
if err != nil {
panic(err)
}
*/
package tokens package tokens
...@@ -10,20 +10,22 @@ type Scope struct { ...@@ -10,20 +10,22 @@ type Scope struct {
DomainName string DomainName string
} }
// AuthOptionsBuilder describes any argument that may be passed to the Create call. // AuthOptionsBuilder provides the ability for extensions to add additional
// parameters to AuthOptions. Extensions must satisfy all required methods.
type AuthOptionsBuilder interface { type AuthOptionsBuilder interface {
// ToTokenV3CreateMap assembles the Create request body, returning an error if parameters are // ToTokenV3CreateMap assembles the Create request body, returning an error
// missing or inconsistent. // if parameters are missing or inconsistent.
ToTokenV3CreateMap(map[string]interface{}) (map[string]interface{}, error) ToTokenV3CreateMap(map[string]interface{}) (map[string]interface{}, error)
ToTokenV3ScopeMap() (map[string]interface{}, error) ToTokenV3ScopeMap() (map[string]interface{}, error)
CanReauth() bool CanReauth() bool
} }
// AuthOptions represents options for authenticating a user.
type AuthOptions struct { type AuthOptions struct {
// IdentityEndpoint specifies the HTTP endpoint that is required to work with // IdentityEndpoint specifies the HTTP endpoint that is required to work with
// the Identity API of the appropriate version. While it's ultimately needed by // the Identity API of the appropriate version. While it's ultimately needed
// all of the identity services, it will often be populated by a provider-level // by all of the identity services, it will often be populated by a
// function. // provider-level function.
IdentityEndpoint string `json:"-"` IdentityEndpoint string `json:"-"`
// Username is required if using Identity V2 API. Consult with your provider's // Username is required if using Identity V2 API. Consult with your provider's
...@@ -39,11 +41,11 @@ type AuthOptions struct { ...@@ -39,11 +41,11 @@ type AuthOptions struct {
DomainID string `json:"-"` DomainID string `json:"-"`
DomainName string `json:"name,omitempty"` DomainName string `json:"name,omitempty"`
// AllowReauth should be set to true if you grant permission for Gophercloud to // AllowReauth should be set to true if you grant permission for Gophercloud
// cache your credentials in memory, and to allow Gophercloud to attempt to // to cache your credentials in memory, and to allow Gophercloud to attempt
// re-authenticate automatically if/when your token expires. If you set it to // to re-authenticate automatically if/when your token expires. If you set
// false, it will not cache these settings, but re-authentication will not be // it to false, it will not cache these settings, but re-authentication will
// possible. This setting defaults to false. // not be possible. This setting defaults to false.
AllowReauth bool `json:"-"` AllowReauth bool `json:"-"`
// TokenID allows users to authenticate (possibly as another user) with an // TokenID allows users to authenticate (possibly as another user) with an
...@@ -53,6 +55,7 @@ type AuthOptions struct { ...@@ -53,6 +55,7 @@ type AuthOptions struct {
Scope Scope `json:"-"` Scope Scope `json:"-"`
} }
// ToTokenV3CreateMap builds a request body from AuthOptions.
func (opts *AuthOptions) ToTokenV3CreateMap(scope map[string]interface{}) (map[string]interface{}, error) { func (opts *AuthOptions) ToTokenV3CreateMap(scope map[string]interface{}) (map[string]interface{}, error) {
gophercloudAuthOpts := gophercloud.AuthOptions{ gophercloudAuthOpts := gophercloud.AuthOptions{
Username: opts.Username, Username: opts.Username,
...@@ -67,6 +70,7 @@ func (opts *AuthOptions) ToTokenV3CreateMap(scope map[string]interface{}) (map[s ...@@ -67,6 +70,7 @@ func (opts *AuthOptions) ToTokenV3CreateMap(scope map[string]interface{}) (map[s
return gophercloudAuthOpts.ToTokenV3CreateMap(scope) return gophercloudAuthOpts.ToTokenV3CreateMap(scope)
} }
// ToTokenV3CreateMap builds a scope request body from AuthOptions.
func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) { func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) {
if opts.Scope.ProjectName != "" { if opts.Scope.ProjectName != "" {
// ProjectName provided: either DomainID or DomainName must also be supplied. // ProjectName provided: either DomainID or DomainName must also be supplied.
...@@ -125,7 +129,12 @@ func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) { ...@@ -125,7 +129,12 @@ func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) {
}, },
}, nil }, nil
} else if opts.Scope.DomainName != "" { } else if opts.Scope.DomainName != "" {
return nil, gophercloud.ErrScopeDomainName{} // DomainName
return map[string]interface{}{
"domain": map[string]interface{}{
"name": &opts.Scope.DomainName,
},
}, nil
} }
return nil, nil return nil, nil
...@@ -141,7 +150,8 @@ func subjectTokenHeaders(c *gophercloud.ServiceClient, subjectToken string) map[ ...@@ -141,7 +150,8 @@ func subjectTokenHeaders(c *gophercloud.ServiceClient, subjectToken string) map[
} }
} }
// Create authenticates and either generates a new token, or changes the Scope of an existing token. // Create authenticates and either generates a new token, or changes the Scope
// of an existing token.
func Create(c *gophercloud.ServiceClient, opts AuthOptionsBuilder) (r CreateResult) { func Create(c *gophercloud.ServiceClient, opts AuthOptionsBuilder) (r CreateResult) {
scope, err := opts.ToTokenV3ScopeMap() scope, err := opts.ToTokenV3ScopeMap()
if err != nil { if err != nil {
......
...@@ -17,37 +17,45 @@ type Endpoint struct { ...@@ -17,37 +17,45 @@ type Endpoint struct {
URL string `json:"url"` URL string `json:"url"`
} }
// CatalogEntry provides a type-safe interface to an Identity API V3 service catalog listing. // CatalogEntry provides a type-safe interface to an Identity API V3 service
// Each class of service, such as cloud DNS or block storage services, could have multiple // catalog listing. Each class of service, such as cloud DNS or block storage
// CatalogEntry representing it (one by interface type, e.g public, admin or internal). // services, could have multiple CatalogEntry representing it (one by interface
// type, e.g public, admin or internal).
// //
// Note: when looking for the desired service, try, whenever possible, to key off the type field. // Note: when looking for the desired service, try, whenever possible, to key
// Otherwise, you'll tie the representation of the service to a specific provider. // off the type field. Otherwise, you'll tie the representation of the service
// to a specific provider.
type CatalogEntry struct { type CatalogEntry struct {
// Service ID // Service ID
ID string `json:"id"` ID string `json:"id"`
// Name will contain the provider-specified name for the service. // Name will contain the provider-specified name for the service.
Name string `json:"name"` Name string `json:"name"`
// Type will contain a type string if OpenStack defines a type for the service.
// Otherwise, for provider-specific services, the provider may assign their own type strings. // Type will contain a type string if OpenStack defines a type for the
// service. Otherwise, for provider-specific services, the provider may
// assign their own type strings.
Type string `json:"type"` Type string `json:"type"`
// Endpoints will let the caller iterate over all the different endpoints that may exist for
// the service. // Endpoints will let the caller iterate over all the different endpoints that
// may exist for the service.
Endpoints []Endpoint `json:"endpoints"` Endpoints []Endpoint `json:"endpoints"`
} }
// ServiceCatalog provides a view into the service catalog from a previous, successful authentication. // ServiceCatalog provides a view into the service catalog from a previous,
// successful authentication.
type ServiceCatalog struct { type ServiceCatalog struct {
Entries []CatalogEntry `json:"catalog"` Entries []CatalogEntry `json:"catalog"`
} }
// Domain provides information about the domain to which this token grants access. // Domain provides information about the domain to which this token grants
// access.
type Domain struct { type Domain struct {
ID string `json:"id"` ID string `json:"id"`
Name string `json:"name"` Name string `json:"name"`
} }
// User represents a user resource that exists on the API. // User represents a user resource that exists in the Identity Service.
type User struct { type User struct {
Domain Domain `json:"domain"` Domain Domain `json:"domain"`
ID string `json:"id"` ID string `json:"id"`
...@@ -67,7 +75,8 @@ type Project struct { ...@@ -67,7 +75,8 @@ type Project struct {
Name string `json:"name"` Name string `json:"name"`
} }
// commonResult is the deferred result of a Create or a Get call. // commonResult is the response from a request. A commonResult has various
// methods which can be used to extract different details about the result.
type commonResult struct { type commonResult struct {
gophercloud.Result gophercloud.Result
} }
...@@ -92,7 +101,8 @@ func (r commonResult) ExtractToken() (*Token, error) { ...@@ -92,7 +101,8 @@ func (r commonResult) ExtractToken() (*Token, error) {
return &s, err return &s, err
} }
// ExtractServiceCatalog returns the ServiceCatalog that was generated along with the user's Token. // ExtractServiceCatalog returns the ServiceCatalog that was generated along
// with the user's Token.
func (r commonResult) ExtractServiceCatalog() (*ServiceCatalog, error) { func (r commonResult) ExtractServiceCatalog() (*ServiceCatalog, error) {
var s ServiceCatalog var s ServiceCatalog
err := r.ExtractInto(&s) err := r.ExtractInto(&s)
...@@ -126,27 +136,31 @@ func (r commonResult) ExtractProject() (*Project, error) { ...@@ -126,27 +136,31 @@ func (r commonResult) ExtractProject() (*Project, error) {
return s.Project, err return s.Project, err
} }
// CreateResult defers the interpretation of a created token. // CreateResult is the response from a Create request. Use ExtractToken()
// Use ExtractToken() to interpret it as a Token, or ExtractServiceCatalog() to interpret it as a service catalog. // to interpret it as a Token, or ExtractServiceCatalog() to interpret it
// as a service catalog.
type CreateResult struct { type CreateResult struct {
commonResult commonResult
} }
// GetResult is the deferred response from a Get call. // GetResult is the response from a Get request. Use ExtractToken()
// to interpret it as a Token, or ExtractServiceCatalog() to interpret it
// as a service catalog.
type GetResult struct { type GetResult struct {
commonResult commonResult
} }
// RevokeResult is the deferred response from a Revoke call. // RevokeResult is response from a Revoke request.
type RevokeResult struct { type RevokeResult struct {
commonResult commonResult
} }
// Token is a string that grants a user access to a controlled set of services in an OpenStack provider. // Token is a string that grants a user access to a controlled set of services
// Each Token is valid for a set length of time. // in an OpenStack provider. Each Token is valid for a set length of time.
type Token struct { type Token struct {
// ID is the issued token. // ID is the issued token.
ID string `json:"id"` ID string `json:"id"`
// ExpiresAt is the timestamp at which this token will no longer be accepted. // ExpiresAt is the timestamp at which this token will no longer be accepted.
ExpiresAt time.Time `json:"expires_at"` ExpiresAt time.Time `json:"expires_at"`
} }
......
...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") ...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"doc.go",
"requests.go", "requests.go",
"results.go", "results.go",
"urls.go", "urls.go",
......
/*
package floatingips enables management and retrieval of Floating IPs from the
OpenStack Networking service.
Example to List Floating IPs
listOpts := floatingips.ListOpts{
FloatingNetworkID: "a6917946-38ab-4ffd-a55a-26c0980ce5ee",
}
allPages, err := floatingips.List(networkClient, listOpts).AllPages()
if err != nil {
panic(err)
}
allFIPs, err := floatingips.ExtractFloatingIPs(allPages)
if err != nil {
panic(err)
}
for _, fip := range allFIPs {
fmt.Printf("%+v\n", fip)
}
Example to Create a Floating IP
createOpts := floatingips.CreateOpts{
FloatingNetworkID: "a6917946-38ab-4ffd-a55a-26c0980ce5ee",
}
fip, err := floatingips.Create(networkingClient, createOpts).Extract()
if err != nil {
panic(err)
}
Example to Update a Floating IP
fipID := "2f245a7b-796b-4f26-9cf9-9e82d248fda7"
portID := "76d0a61b-b8e5-490c-9892-4cf674f2bec8"
updateOpts := floatingips.UpdateOpts{
PortID: &portID,
}
fip, err := floatingips.Update(networkingClient, fipID, updateOpts).Extract()
if err != nil {
panic(err)
}
Example to Disassociate a Floating IP with a Port
fipID := "2f245a7b-796b-4f26-9cf9-9e82d248fda7"
updateOpts := floatingips.UpdateOpts{
PortID: nil,
}
fip, err := floatingips.Update(networkingClient, fipID, updateOpts).Extract()
if err != nil {
panic(err)
}
Example to Delete a Floating IP
fipID := "2f245a7b-796b-4f26-9cf9-9e82d248fda7"
err := floatingips.Delete(networkClient, fipID).ExtractErr()
if err != nil {
panic(err)
}
*/
package floatingips
...@@ -39,8 +39,8 @@ func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager { ...@@ -39,8 +39,8 @@ func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
}) })
} }
// CreateOptsBuilder is the interface type must satisfy to be used as Create // CreateOptsBuilder allows extensions to add additional parameters to the
// options. // Create request.
type CreateOptsBuilder interface { type CreateOptsBuilder interface {
ToFloatingIPCreateMap() (map[string]interface{}, error) ToFloatingIPCreateMap() (map[string]interface{}, error)
} }
...@@ -79,10 +79,10 @@ func (opts CreateOpts) ToFloatingIPCreateMap() (map[string]interface{}, error) { ...@@ -79,10 +79,10 @@ func (opts CreateOpts) ToFloatingIPCreateMap() (map[string]interface{}, error) {
// return 404 error code. // return 404 error code.
// //
// You must also configure an IP address for the port associated with the PortID // You must also configure an IP address for the port associated with the PortID
// you have provided - this is what the FixedIP refers to: an IP fixed to a port. // you have provided - this is what the FixedIP refers to: an IP fixed to a
// Because a port might be associated with multiple IP addresses, you can use // port. Because a port might be associated with multiple IP addresses, you can
// the FixedIP field to associate a particular IP address rather than have the // use the FixedIP field to associate a particular IP address rather than have
// API assume for you. If you specify an IP address that is not valid, the // the API assume for you. If you specify an IP address that is not valid, the
// operation will fail and return a 400 error code. If the PortID and FixedIP // operation will fail and return a 400 error code. If the PortID and FixedIP
// are already associated with another resource, the operation will fail and // are already associated with another resource, the operation will fail and
// returns a 409 error code. // returns a 409 error code.
...@@ -102,8 +102,8 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { ...@@ -102,8 +102,8 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
return return
} }
// UpdateOptsBuilder is the interface type must satisfy to be used as Update // UpdateOptsBuilder allows extensions to add additional parameters to the
// options. // Update request.
type UpdateOptsBuilder interface { type UpdateOptsBuilder interface {
ToFloatingIPUpdateMap() (map[string]interface{}, error) ToFloatingIPUpdateMap() (map[string]interface{}, error)
} }
......
...@@ -12,30 +12,32 @@ import ( ...@@ -12,30 +12,32 @@ import (
// floating IPs can only be defined on networks where the `router:external' // floating IPs can only be defined on networks where the `router:external'
// attribute (provided by the external network extension) is set to True. // attribute (provided by the external network extension) is set to True.
type FloatingIP struct { type FloatingIP struct {
// Unique identifier for the floating IP instance. // ID is the unique identifier for the floating IP instance.
ID string `json:"id"` ID string `json:"id"`
// UUID of the external network where the floating IP is to be created. // FloatingNetworkID is the UUID of the external network where the floating
// IP is to be created.
FloatingNetworkID string `json:"floating_network_id"` FloatingNetworkID string `json:"floating_network_id"`
// Address of the floating IP on the external network. // FloatingIP is the address of the floating IP on the external network.
FloatingIP string `json:"floating_ip_address"` FloatingIP string `json:"floating_ip_address"`
// UUID of the port on an internal network that is associated with the floating IP. // PortID is the UUID of the port on an internal network that is associated
// with the floating IP.
PortID string `json:"port_id"` PortID string `json:"port_id"`
// The specific IP address of the internal port which should be associated // FixedIP is the specific IP address of the internal port which should be
// with the floating IP. // associated with the floating IP.
FixedIP string `json:"fixed_ip_address"` FixedIP string `json:"fixed_ip_address"`
// Owner of the floating IP. Only admin users can specify a tenant identifier // TenantID is the Owner of the floating IP. Only admin users can specify a
// other than its own. // tenant identifier other than its own.
TenantID string `json:"tenant_id"` TenantID string `json:"tenant_id"`
// The condition of the API resource. // Status is the condition of the API resource.
Status string `json:"status"` Status string `json:"status"`
//The ID of the router used for this Floating-IP // RouterID is the ID of the router used for this floating IP.
RouterID string `json:"router_id"` RouterID string `json:"router_id"`
} }
...@@ -43,7 +45,7 @@ type commonResult struct { ...@@ -43,7 +45,7 @@ type commonResult struct {
gophercloud.Result gophercloud.Result
} }
// Extract a result and extracts a FloatingIP resource. // Extract will extract a FloatingIP resource from a result.
func (r commonResult) Extract() (*FloatingIP, error) { func (r commonResult) Extract() (*FloatingIP, error) {
var s struct { var s struct {
FloatingIP *FloatingIP `json:"floatingip"` FloatingIP *FloatingIP `json:"floatingip"`
...@@ -52,22 +54,26 @@ func (r commonResult) Extract() (*FloatingIP, error) { ...@@ -52,22 +54,26 @@ func (r commonResult) Extract() (*FloatingIP, error) {
return s.FloatingIP, err return s.FloatingIP, err
} }
// CreateResult represents the result of a create operation. // CreateResult represents the result of a create operation. Call its Extract
// method to interpret it as a FloatingIP.
type CreateResult struct { type CreateResult struct {
commonResult commonResult
} }
// GetResult represents the result of a get operation. // GetResult represents the result of a get operation. Call its Extract
// method to interpret it as a FloatingIP.
type GetResult struct { type GetResult struct {
commonResult commonResult
} }
// UpdateResult represents the result of an update operation. // UpdateResult represents the result of an update operation. Call its Extract
// method to interpret it as a FloatingIP.
type UpdateResult struct { type UpdateResult struct {
commonResult commonResult
} }
// DeleteResult represents the result of an update operation. // DeleteResult represents the result of an update operation. Call its
// ExtractErr method to determine if the request succeeded or failed.
type DeleteResult struct { type DeleteResult struct {
gophercloud.ErrResult gophercloud.ErrResult
} }
...@@ -78,9 +84,9 @@ type FloatingIPPage struct { ...@@ -78,9 +84,9 @@ type FloatingIPPage struct {
pagination.LinkedPageBase pagination.LinkedPageBase
} }
// NextPageURL is invoked when a paginated collection of floating IPs has reached // NextPageURL is invoked when a paginated collection of floating IPs has
// the end of a page and the pager seeks to traverse over a new one. In order // reached the end of a page and the pager seeks to traverse over a new one.
// to do this, it needs to construct the next page's URL. // In order to do this, it needs to construct the next page's URL.
func (r FloatingIPPage) NextPageURL() (string, error) { func (r FloatingIPPage) NextPageURL() (string, error) {
var s struct { var s struct {
Links []gophercloud.Link `json:"floatingips_links"` Links []gophercloud.Link `json:"floatingips_links"`
...@@ -92,15 +98,15 @@ func (r FloatingIPPage) NextPageURL() (string, error) { ...@@ -92,15 +98,15 @@ func (r FloatingIPPage) NextPageURL() (string, error) {
return gophercloud.ExtractNextURL(s.Links) return gophercloud.ExtractNextURL(s.Links)
} }
// IsEmpty checks whether a NetworkPage struct is empty. // IsEmpty checks whether a FloatingIPPage struct is empty.
func (r FloatingIPPage) IsEmpty() (bool, error) { func (r FloatingIPPage) IsEmpty() (bool, error) {
is, err := ExtractFloatingIPs(r) is, err := ExtractFloatingIPs(r)
return len(is) == 0, err return len(is) == 0, err
} }
// ExtractFloatingIPs accepts a Page struct, specifically a FloatingIPPage struct, // ExtractFloatingIPs accepts a Page struct, specifically a FloatingIPPage
// and extracts the elements into a slice of FloatingIP structs. In other words, // struct, and extracts the elements into a slice of FloatingIP structs. In
// a generic collection is mapped into a relevant slice. // other words, a generic collection is mapped into a relevant slice.
func ExtractFloatingIPs(r pagination.Page) ([]FloatingIP, error) { func ExtractFloatingIPs(r pagination.Page) ([]FloatingIP, error) {
var s struct { var s struct {
FloatingIPs []FloatingIP `json:"floatingips"` FloatingIPs []FloatingIP `json:"floatingips"`
......
...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") ...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"doc.go",
"requests.go", "requests.go",
"results.go", "results.go",
"urls.go", "urls.go",
......
/*
Package routers enables management and retrieval of Routers from the OpenStack
Networking service.
Example to List Routers
listOpts := routers.ListOpts{}
allPages, err := routers.List(networkClient, listOpts).AllPages()
if err != nil {
panic(err)
}
allRouters, err := routers.ExtractRouters(allPages)
if err != nil {
panic(err)
}
for _, router := range allRoutes {
fmt.Printf("%+v\n", router)
}
Example to Create a Router
iTrue := true
gwi := routers.GatewayInfo{
NetworkID: "8ca37218-28ff-41cb-9b10-039601ea7e6b",
}
createOpts := routers.CreateOpts{
Name: "router_1",
AdminStateUp: &iTrue,
GatewayInfo: &gwi,
}
router, err := routers.Create(networkClient, createOpts).Extract()
if err != nil {
panic(err)
}
Example to Update a Router
routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
routes := []routers.Route{{
DestinationCIDR: "40.0.1.0/24",
NextHop: "10.1.0.10",
}}
updateOpts := routers.UpdateOpts{
Name: "new_name",
Routes: routes,
}
router, err := routers.Update(networkClient, routerID, updateOpts).Extract()
if err != nil {
panic(err)
}
Example to Remove all Routes from a Router
routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
routes := []routers.Route{}
updateOpts := routers.UpdateOpts{
Routes: routes,
}
router, err := routers.Update(networkClient, routerID, updateOpts).Extract()
if err != nil {
panic(err)
}
Example to Delete a Router
routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
err := routers.Delete(networkClient, routerID).ExtractErr()
if err != nil {
panic(err)
}
Example to Add an Interface to a Router
routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
intOpts := routers.AddInterfaceOpts{
SubnetID: "a2f1f29d-571b-4533-907f-5803ab96ead1",
}
interface, err := routers.AddInterface(networkClient, routerID, intOpts).Extract()
if err != nil {
panic(err)
}
Example to Remove an Interface from a Router
routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
intOpts := routers.RemoveInterfaceOpts{
SubnetID: "a2f1f29d-571b-4533-907f-5803ab96ead1",
}
interface, err := routers.RemoveInterface(networkClient, routerID, intOpts).Extract()
if err != nil {
panic(err)
}
*/
package routers
...@@ -40,10 +40,8 @@ func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager { ...@@ -40,10 +40,8 @@ func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
}) })
} }
// CreateOptsBuilder is the interface options structs have to satisfy in order // CreateOptsBuilder allows extensions to add additional parameters to the
// to be used in the main Create operation in this package. Since many // Create request.
// extensions decorate or modify the common logic, it is useful for them to
// satisfy a basic interface in order for them to be used.
type CreateOptsBuilder interface { type CreateOptsBuilder interface {
ToRouterCreateMap() (map[string]interface{}, error) ToRouterCreateMap() (map[string]interface{}, error)
} }
...@@ -58,6 +56,7 @@ type CreateOpts struct { ...@@ -58,6 +56,7 @@ type CreateOpts struct {
GatewayInfo *GatewayInfo `json:"external_gateway_info,omitempty"` GatewayInfo *GatewayInfo `json:"external_gateway_info,omitempty"`
} }
// ToRouterCreateMap builds a create request body from CreateOpts.
func (opts CreateOpts) ToRouterCreateMap() (map[string]interface{}, error) { func (opts CreateOpts) ToRouterCreateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "router") return gophercloud.BuildRequestBody(opts, "router")
} }
...@@ -86,6 +85,8 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { ...@@ -86,6 +85,8 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
return return
} }
// UpdateOptsBuilder allows extensions to add additional parameters to the
// Update request.
type UpdateOptsBuilder interface { type UpdateOptsBuilder interface {
ToRouterUpdateMap() (map[string]interface{}, error) ToRouterUpdateMap() (map[string]interface{}, error)
} }
...@@ -99,6 +100,7 @@ type UpdateOpts struct { ...@@ -99,6 +100,7 @@ type UpdateOpts struct {
Routes []Route `json:"routes"` Routes []Route `json:"routes"`
} }
// ToRouterUpdateMap builds an update body based on UpdateOpts.
func (opts UpdateOpts) ToRouterUpdateMap() (map[string]interface{}, error) { func (opts UpdateOpts) ToRouterUpdateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "router") return gophercloud.BuildRequestBody(opts, "router")
} }
...@@ -126,21 +128,19 @@ func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) { ...@@ -126,21 +128,19 @@ func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
return return
} }
// AddInterfaceOptsBuilder is what types must satisfy to be used as AddInterface // AddInterfaceOptsBuilder allows extensions to add additional parameters to
// options. // the AddInterface request.
type AddInterfaceOptsBuilder interface { type AddInterfaceOptsBuilder interface {
ToRouterAddInterfaceMap() (map[string]interface{}, error) ToRouterAddInterfaceMap() (map[string]interface{}, error)
} }
// AddInterfaceOpts allow you to work with operations that either add // AddInterfaceOpts represents the options for adding an interface to a router.
// an internal interface from a router.
type AddInterfaceOpts struct { type AddInterfaceOpts struct {
SubnetID string `json:"subnet_id,omitempty" xor:"PortID"` SubnetID string `json:"subnet_id,omitempty" xor:"PortID"`
PortID string `json:"port_id,omitempty" xor:"SubnetID"` PortID string `json:"port_id,omitempty" xor:"SubnetID"`
} }
// ToRouterAddInterfaceMap allows InterfaceOpts to satisfy the InterfaceOptsBuilder // ToRouterAddInterfaceMap builds a request body from AddInterfaceOpts.
// interface
func (opts AddInterfaceOpts) ToRouterAddInterfaceMap() (map[string]interface{}, error) { func (opts AddInterfaceOpts) ToRouterAddInterfaceMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "") return gophercloud.BuildRequestBody(opts, "")
} }
...@@ -178,21 +178,21 @@ func AddInterface(c *gophercloud.ServiceClient, id string, opts AddInterfaceOpts ...@@ -178,21 +178,21 @@ func AddInterface(c *gophercloud.ServiceClient, id string, opts AddInterfaceOpts
return return
} }
// RemoveInterfaceOptsBuilder is what types must satisfy to be used as RemoveInterface // RemoveInterfaceOptsBuilder allows extensions to add additional parameters to
// options. // the RemoveInterface request.
type RemoveInterfaceOptsBuilder interface { type RemoveInterfaceOptsBuilder interface {
ToRouterRemoveInterfaceMap() (map[string]interface{}, error) ToRouterRemoveInterfaceMap() (map[string]interface{}, error)
} }
// RemoveInterfaceOpts allow you to work with operations that either add or remote // RemoveInterfaceOpts represents options for removing an interface from
// an internal interface from a router. // a router.
type RemoveInterfaceOpts struct { type RemoveInterfaceOpts struct {
SubnetID string `json:"subnet_id,omitempty" or:"PortID"` SubnetID string `json:"subnet_id,omitempty" or:"PortID"`
PortID string `json:"port_id,omitempty" or:"SubnetID"` PortID string `json:"port_id,omitempty" or:"SubnetID"`
} }
// ToRouterRemoveInterfaceMap allows RemoveInterfaceOpts to satisfy the RemoveInterfaceOptsBuilder // ToRouterRemoveInterfaceMap builds a request body based on
// interface // RemoveInterfaceOpts.
func (opts RemoveInterfaceOpts) ToRouterRemoveInterfaceMap() (map[string]interface{}, error) { func (opts RemoveInterfaceOpts) ToRouterRemoveInterfaceMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "") return gophercloud.BuildRequestBody(opts, "")
} }
......
...@@ -26,28 +26,30 @@ type Route struct { ...@@ -26,28 +26,30 @@ type Route struct {
// whenever a router is associated with a subnet, a port for that router // whenever a router is associated with a subnet, a port for that router
// interface is added to the subnet's network. // interface is added to the subnet's network.
type Router struct { type Router struct {
// Indicates whether or not a router is currently operational. // Status indicates whether or not a router is currently operational.
Status string `json:"status"` Status string `json:"status"`
// Information on external gateway for the router. // GateayInfo provides information on external gateway for the router.
GatewayInfo GatewayInfo `json:"external_gateway_info"` GatewayInfo GatewayInfo `json:"external_gateway_info"`
// Administrative state of the router. // AdminStateUp is the administrative state of the router.
AdminStateUp bool `json:"admin_state_up"` AdminStateUp bool `json:"admin_state_up"`
// Whether router is disitrubted or not.. // Distributed is whether router is disitrubted or not.
Distributed bool `json:"distributed"` Distributed bool `json:"distributed"`
// Human readable name for the router. Does not have to be unique. // Name is the human readable name for the router. It does not have to be
// unique.
Name string `json:"name"` Name string `json:"name"`
// Unique identifier for the router. // ID is the unique identifier for the router.
ID string `json:"id"` ID string `json:"id"`
// Owner of the router. Only admin users can specify a tenant identifier // TenantID is the owner of the router. Only admin users can specify a tenant
// other than its own. // identifier other than its own.
TenantID string `json:"tenant_id"` TenantID string `json:"tenant_id"`
// Routes are a collection of static routes that the router will host.
Routes []Route `json:"routes"` Routes []Route `json:"routes"`
} }
...@@ -101,22 +103,26 @@ func (r commonResult) Extract() (*Router, error) { ...@@ -101,22 +103,26 @@ func (r commonResult) Extract() (*Router, error) {
return s.Router, err return s.Router, err
} }
// CreateResult represents the result of a create operation. // CreateResult represents the result of a create operation. Call its Extract
// method to interpret it as a Router.
type CreateResult struct { type CreateResult struct {
commonResult commonResult
} }
// GetResult represents the result of a get operation. // GetResult represents the result of a get operation. Call its Extract
// method to interpret it as a Router.
type GetResult struct { type GetResult struct {
commonResult commonResult
} }
// UpdateResult represents the result of an update operation. // UpdateResult represents the result of an update operation. Call its Extract
// method to interpret it as a Router.
type UpdateResult struct { type UpdateResult struct {
commonResult commonResult
} }
// DeleteResult represents the result of a delete operation. // DeleteResult represents the result of a delete operation. Call its ExtractErr
// method to determine if the request succeeded or failed.
type DeleteResult struct { type DeleteResult struct {
gophercloud.ErrResult gophercloud.ErrResult
} }
...@@ -125,21 +131,22 @@ type DeleteResult struct { ...@@ -125,21 +131,22 @@ type DeleteResult struct {
// mentioned above, in order for a router to forward to a subnet, it needs an // mentioned above, in order for a router to forward to a subnet, it needs an
// interface. // interface.
type InterfaceInfo struct { type InterfaceInfo struct {
// The ID of the subnet which this interface is associated with. // SubnetID is the ID of the subnet which this interface is associated with.
SubnetID string `json:"subnet_id"` SubnetID string `json:"subnet_id"`
// The ID of the port that is a part of the subnet. // PortID is the ID of the port that is a part of the subnet.
PortID string `json:"port_id"` PortID string `json:"port_id"`
// The UUID of the interface. // ID is the UUID of the interface.
ID string `json:"id"` ID string `json:"id"`
// Owner of the interface. // TenantID is the owner of the interface.
TenantID string `json:"tenant_id"` TenantID string `json:"tenant_id"`
} }
// InterfaceResult represents the result of interface operations, such as // InterfaceResult represents the result of interface operations, such as
// AddInterface() and RemoveInterface(). // AddInterface() and RemoveInterface(). Call its Extract method to interpret
// the result as a InterfaceInfo.
type InterfaceResult struct { type InterfaceResult struct {
gophercloud.Result gophercloud.Result
} }
......
...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") ...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"doc.go",
"requests.go", "requests.go",
"results.go", "results.go",
"urls.go", "urls.go",
......
/*
Package members provides information and interaction with Members of the
Load Balancer as a Service extension for the OpenStack Networking service.
Example to List Members
listOpts := members.ListOpts{
ProtocolPort: 80,
}
allPages, err := members.List(networkClient, listOpts).AllPages()
if err != nil {
panic(err)
}
allMembers, err := members.ExtractMembers(allPages)
if err != nil {
panic(err)
}
for _, member := range allMembers {
fmt.Printf("%+v\n", member)
}
Example to Create a Member
createOpts := members.CreateOpts{
Address: "192.168.2.14",
ProtocolPort: 80,
PoolID: "0b266a12-0fdf-4434-bd11-649d84e54bd5"
}
member, err := members.Create(networkClient, createOpts).Extract()
if err != nil {
panic(err)
}
Example to Update a Member
memberID := "46592c54-03f7-40ef-9cdf-b1fcf2775ddf"
updateOpts := members.UpdateOpts{
AdminStateUp: gophercloud.Disabled,
}
member, err := members.Update(networkClient, memberID, updateOpts).Extract()
if err != nil {
panic(err)
}
Example to Delete a Member
memberID := "46592c54-03f7-40ef-9cdf-b1fcf2775ddf"
err := members.Delete(networkClient, memberID).ExtractErr()
if err != nil {
panic(err)
}
*/
package members
...@@ -26,10 +26,10 @@ type ListOpts struct { ...@@ -26,10 +26,10 @@ type ListOpts struct {
} }
// List returns a Pager which allows you to iterate over a collection of // List returns a Pager which allows you to iterate over a collection of
// pools. It accepts a ListOpts struct, which allows you to filter and sort // members. It accepts a ListOpts struct, which allows you to filter and sort
// the returned collection for greater efficiency. // the returned collection for greater efficiency.
// //
// Default policy settings return only those pools that are owned by the // Default policy settings return only those members that are owned by the
// tenant who submits the request, unless an admin user submits the request. // tenant who submits the request, unless an admin user submits the request.
func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager { func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
q, err := gophercloud.BuildQueryString(&opts) q, err := gophercloud.BuildQueryString(&opts)
...@@ -42,23 +42,29 @@ func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager { ...@@ -42,23 +42,29 @@ func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
}) })
} }
// CreateOptsBuilder allows extensions to add additional parameters to the
// Create request.
type CreateOptsBuilder interface { type CreateOptsBuilder interface {
ToLBMemberCreateMap() (map[string]interface{}, error) ToLBMemberCreateMap() (map[string]interface{}, error)
} }
// CreateOpts contains all the values needed to create a new pool member. // CreateOpts contains all the values needed to create a new pool member.
type CreateOpts struct { type CreateOpts struct {
// The IP address of the member. // Address is the IP address of the member.
Address string `json:"address" required:"true"` Address string `json:"address" required:"true"`
// The port on which the application is hosted.
// ProtocolPort is the port on which the application is hosted.
ProtocolPort int `json:"protocol_port" required:"true"` ProtocolPort int `json:"protocol_port" required:"true"`
// The pool to which this member will belong.
// PoolID is the pool to which this member will belong.
PoolID string `json:"pool_id" required:"true"` PoolID string `json:"pool_id" required:"true"`
// Only required if the caller has an admin role and wants to create a pool
// for another tenant. // TenantID is only required if the caller has an admin role and wants
// to create a pool for another tenant.
TenantID string `json:"tenant_id,omitempty"` TenantID string `json:"tenant_id,omitempty"`
} }
// ToLBMemberCreateMap builds a request body from CreateOpts.
func (opts CreateOpts) ToLBMemberCreateMap() (map[string]interface{}, error) { func (opts CreateOpts) ToLBMemberCreateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "member") return gophercloud.BuildRequestBody(opts, "member")
} }
...@@ -81,6 +87,8 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { ...@@ -81,6 +87,8 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
return return
} }
// UpdateOptsBuilder allows extensions to add additional parameters to the
// Update request.
type UpdateOptsBuilder interface { type UpdateOptsBuilder interface {
ToLBMemberUpdateMap() (map[string]interface{}, error) ToLBMemberUpdateMap() (map[string]interface{}, error)
} }
...@@ -91,6 +99,7 @@ type UpdateOpts struct { ...@@ -91,6 +99,7 @@ type UpdateOpts struct {
AdminStateUp *bool `json:"admin_state_up,omitempty"` AdminStateUp *bool `json:"admin_state_up,omitempty"`
} }
// ToLBMemberUpdateMap builds a request body from UpdateOpts.
func (opts UpdateOpts) ToLBMemberUpdateMap() (map[string]interface{}, error) { func (opts UpdateOpts) ToLBMemberUpdateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "member") return gophercloud.BuildRequestBody(opts, "member")
} }
......
...@@ -7,29 +7,30 @@ import ( ...@@ -7,29 +7,30 @@ import (
// Member represents the application running on a backend server. // Member represents the application running on a backend server.
type Member struct { type Member struct {
// The status of the member. Indicates whether the member is operational. // Status is the status of the member. Indicates whether the member
// is operational.
Status string Status string
// Weight of member. // Weight is the weight of member.
Weight int Weight int
// The administrative state of the member, which is up (true) or down (false). // AdminStateUp is the administrative state of the member, which is up
// (true) or down (false).
AdminStateUp bool `json:"admin_state_up"` AdminStateUp bool `json:"admin_state_up"`
// Owner of the member. Only an administrative user can specify a tenant ID // TenantID is the owner of the member.
// other than its own.
TenantID string `json:"tenant_id"` TenantID string `json:"tenant_id"`
// The pool to which the member belongs. // PoolID is the pool to which the member belongs.
PoolID string `json:"pool_id"` PoolID string `json:"pool_id"`
// The IP address of the member. // Address is the IP address of the member.
Address string Address string
// The port on which the application is hosted. // ProtocolPort is the port on which the application is hosted.
ProtocolPort int `json:"protocol_port"` ProtocolPort int `json:"protocol_port"`
// The unique ID for the member. // ID is the unique ID for the member.
ID string ID string
} }
...@@ -74,7 +75,7 @@ type commonResult struct { ...@@ -74,7 +75,7 @@ type commonResult struct {
gophercloud.Result gophercloud.Result
} }
// Extract is a function that accepts a result and extracts a router. // Extract is a function that accepts a result and extracts a member.
func (r commonResult) Extract() (*Member, error) { func (r commonResult) Extract() (*Member, error) {
var s struct { var s struct {
Member *Member `json:"member"` Member *Member `json:"member"`
...@@ -83,22 +84,26 @@ func (r commonResult) Extract() (*Member, error) { ...@@ -83,22 +84,26 @@ func (r commonResult) Extract() (*Member, error) {
return s.Member, err return s.Member, err
} }
// CreateResult represents the result of a create operation. // CreateResult represents the result of a create operation. Call its Extract
// method to interpret it as a Member.
type CreateResult struct { type CreateResult struct {
commonResult commonResult
} }
// GetResult represents the result of a get operation. // GetResult represents the result of a get operation. Call its Extract
// method to interpret it as a Member.
type GetResult struct { type GetResult struct {
commonResult commonResult
} }
// UpdateResult represents the result of an update operation. // UpdateResult represents the result of an update operation. Call its Extract
// method to interpret it as a Member.
type UpdateResult struct { type UpdateResult struct {
commonResult commonResult
} }
// DeleteResult represents the result of a delete operation. // DeleteResult represents the result of a delete operation. Call its
// ExtractErr method to determine if the result succeeded or failed.
type DeleteResult struct { type DeleteResult struct {
gophercloud.ErrResult gophercloud.ErrResult
} }
...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") ...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"doc.go",
"requests.go", "requests.go",
"results.go", "results.go",
"urls.go", "urls.go",
......
/*
Package monitors provides information and interaction with the Monitors
of the Load Balancer as a Service extension for the OpenStack Networking
Service.
Example to List Monitors
listOpts: monitors.ListOpts{
Type: "HTTP",
}
allPages, err := monitors.List(networkClient, listOpts).AllPages()
if err != nil {
panic(err)
}
allMonitors, err := monitors.ExtractMonitors(allPages)
if err != nil {
panic(err)
}
for _, monitor := range allMonitors {
fmt.Printf("%+v\n", monitor)
}
Example to Create a Monitor
createOpts := monitors.CreateOpts{
Type: "HTTP",
Delay: 20,
Timeout: 20,
MaxRetries: 5,
URLPath: "/check",
ExpectedCodes: "200-299",
}
monitor, err := monitors.Create(networkClient, createOpts).Extract()
if err != nil {
panic(err)
}
Example to Update a Monitor
monitorID := "681aed03-aadb-43ae-aead-b9016375650a"
updateOpts := monitors.UpdateOpts{
Timeout: 30,
}
monitor, err := monitors.Update(networkClient, monitorID, updateOpts).Extract()
if err != nil {
panic(err)
}
Example to Delete a Member
monitorID := "681aed03-aadb-43ae-aead-b9016375650a"
err := monitors.Delete(networkClient, monitorID).ExtractErr()
if err != nil {
panic(err)
}
*/
package monitors
...@@ -31,10 +31,10 @@ type ListOpts struct { ...@@ -31,10 +31,10 @@ type ListOpts struct {
} }
// List returns a Pager which allows you to iterate over a collection of // List returns a Pager which allows you to iterate over a collection of
// routers. It accepts a ListOpts struct, which allows you to filter and sort // monitors. It accepts a ListOpts struct, which allows you to filter and sort
// the returned collection for greater efficiency. // the returned collection for greater efficiency.
// //
// Default policy settings return only those routers that are owned by the // Default policy settings return only those monitors that are owned by the
// tenant who submits the request, unless an admin user submits the request. // tenant who submits the request, unless an admin user submits the request.
func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager { func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
q, err := gophercloud.BuildQueryString(&opts) q, err := gophercloud.BuildQueryString(&opts)
...@@ -47,7 +47,7 @@ func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager { ...@@ -47,7 +47,7 @@ func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
}) })
} }
// MonitorType is the type for all the types of LB monitors // MonitorType is the type for all the types of LB monitors.
type MonitorType string type MonitorType string
// Constants that represent approved monitoring types. // Constants that represent approved monitoring types.
...@@ -58,42 +58,52 @@ const ( ...@@ -58,42 +58,52 @@ const (
TypeHTTPS MonitorType = "HTTPS" TypeHTTPS MonitorType = "HTTPS"
) )
// CreateOptsBuilder is what types must satisfy to be used as Create // CreateOptsBuilder allows extensions to add additional parameters to the
// options. // Create request.
type CreateOptsBuilder interface { type CreateOptsBuilder interface {
ToLBMonitorCreateMap() (map[string]interface{}, error) ToLBMonitorCreateMap() (map[string]interface{}, error)
} }
// CreateOpts contains all the values needed to create a new health monitor. // CreateOpts contains all the values needed to create a new health monitor.
type CreateOpts struct { type CreateOpts struct {
// Required. The type of probe, which is PING, TCP, HTTP, or HTTPS, that is // MonitorType is the type of probe, which is PING, TCP, HTTP, or HTTPS,
// sent by the load balancer to verify the member state. // that is sent by the load balancer to verify the member state.
Type MonitorType `json:"type" required:"true"` Type MonitorType `json:"type" required:"true"`
// Required. The time, in seconds, between sending probes to members.
// Delay is the time, in seconds, between sending probes to members.
Delay int `json:"delay" required:"true"` Delay int `json:"delay" required:"true"`
// Required. Maximum number of seconds for a monitor to wait for a ping reply
// before it times out. The value must be less than the delay value. // Timeout is the maximum number of seconds for a monitor to wait for a ping
// reply before it times out. The value must be less than the delay value.
Timeout int `json:"timeout" required:"true"` Timeout int `json:"timeout" required:"true"`
// Required. Number of permissible ping failures before changing the member's
// status to INACTIVE. Must be a number between 1 and 10. // MaxRetries is the number of permissible ping failures before changing the
// member's status to INACTIVE. Must be a number between 1 and 10.
MaxRetries int `json:"max_retries" required:"true"` MaxRetries int `json:"max_retries" required:"true"`
// Required for HTTP(S) types. URI path that will be accessed if monitor type
// is HTTP or HTTPS. // URLPath is the URI path that will be accessed if monitor type
// is HTTP or HTTPS. Required for HTTP(S) types.
URLPath string `json:"url_path,omitempty"` URLPath string `json:"url_path,omitempty"`
// Required for HTTP(S) types. The HTTP method used for requests by the
// monitor. If this attribute is not specified, it defaults to "GET". // HTTPMethod is the HTTP method used for requests by the monitor. If this
// attribute is not specified, it defaults to "GET". Required for HTTP(S)
// types.
HTTPMethod string `json:"http_method,omitempty"` HTTPMethod string `json:"http_method,omitempty"`
// Required for HTTP(S) types. Expected HTTP codes for a passing HTTP(S)
// monitor. You can either specify a single status like "200", or a range // ExpectedCodes is the expected HTTP codes for a passing HTTP(S) monitor
// like "200-202". // You can either specify a single status like "200", or a range like
// "200-202". Required for HTTP(S) types.
ExpectedCodes string `json:"expected_codes,omitempty"` ExpectedCodes string `json:"expected_codes,omitempty"`
// Required for admins. Indicates the owner of the VIP.
TenantID string `json:"tenant_id,omitempty"` // TenantID is only required if the caller has an admin role and wants
AdminStateUp *bool `json:"admin_state_up,omitempty"` // to create a pool for another tenant.
TenantID string `json:"tenant_id,omitempty"`
// AdminStateUp denotes whether the monitor is administratively up or down.
AdminStateUp *bool `json:"admin_state_up,omitempty"`
} }
// ToLBMonitorCreateMap allows CreateOpts to satisfy the CreateOptsBuilder // ToLBMonitorCreateMap builds a request body from CreateOpts.
// interface
func (opts CreateOpts) ToLBMonitorCreateMap() (map[string]interface{}, error) { func (opts CreateOpts) ToLBMonitorCreateMap() (map[string]interface{}, error) {
if opts.Type == TypeHTTP || opts.Type == TypeHTTPS { if opts.Type == TypeHTTP || opts.Type == TypeHTTPS {
if opts.URLPath == "" { if opts.URLPath == "" {
...@@ -146,39 +156,45 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { ...@@ -146,39 +156,45 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
return return
} }
// UpdateOptsBuilder is what types must satisfy to be used as Update // UpdateOptsBuilder allows extensions to add additional parameters to the
// options. // Update request.
type UpdateOptsBuilder interface { type UpdateOptsBuilder interface {
ToLBMonitorUpdateMap() (map[string]interface{}, error) ToLBMonitorUpdateMap() (map[string]interface{}, error)
} }
// UpdateOpts contains all the values needed to update an existing virtual IP. // UpdateOpts contains all the values needed to update an existing monitor.
// Attributes not listed here but appear in CreateOpts are immutable and cannot // Attributes not listed here but appear in CreateOpts are immutable and cannot
// be updated. // be updated.
type UpdateOpts struct { type UpdateOpts struct {
// The time, in seconds, between sending probes to members. // Delay is the time, in seconds, between sending probes to members.
Delay int `json:"delay,omitempty"` Delay int `json:"delay,omitempty"`
// Maximum number of seconds for a monitor to wait for a ping reply
// before it times out. The value must be less than the delay value. // Timeout is the maximum number of seconds for a monitor to wait for a ping
// reply before it times out. The value must be less than the delay value.
Timeout int `json:"timeout,omitempty"` Timeout int `json:"timeout,omitempty"`
// Number of permissible ping failures before changing the member's
// status to INACTIVE. Must be a number between 1 and 10. // MaxRetries is the number of permissible ping failures before changing the
// member's status to INACTIVE. Must be a number between 1 and 10.
MaxRetries int `json:"max_retries,omitempty"` MaxRetries int `json:"max_retries,omitempty"`
// URI path that will be accessed if monitor type
// URLPath is the URI path that will be accessed if monitor type
// is HTTP or HTTPS. // is HTTP or HTTPS.
URLPath string `json:"url_path,omitempty"` URLPath string `json:"url_path,omitempty"`
// The HTTP method used for requests by the
// monitor. If this attribute is not specified, it defaults to "GET". // HTTPMethod is the HTTP method used for requests by the monitor. If this
// attribute is not specified, it defaults to "GET".
HTTPMethod string `json:"http_method,omitempty"` HTTPMethod string `json:"http_method,omitempty"`
// Expected HTTP codes for a passing HTTP(S)
// monitor. You can either specify a single status like "200", or a range // ExpectedCodes is the expected HTTP codes for a passing HTTP(S) monitor
// like "200-202". // You can either specify a single status like "200", or a range like
// "200-202".
ExpectedCodes string `json:"expected_codes,omitempty"` ExpectedCodes string `json:"expected_codes,omitempty"`
AdminStateUp *bool `json:"admin_state_up,omitempty"`
// AdminStateUp denotes whether the monitor is administratively up or down.
AdminStateUp *bool `json:"admin_state_up,omitempty"`
} }
// ToLBMonitorUpdateMap allows UpdateOpts to satisfy the UpdateOptsBuilder // ToLBMonitorUpdateMap builds a request body from UpdateOpts.
// interface
func (opts UpdateOpts) ToLBMonitorUpdateMap() (map[string]interface{}, error) { func (opts UpdateOpts) ToLBMonitorUpdateMap() (map[string]interface{}, error) {
if opts.Delay > 0 && opts.Timeout > 0 && opts.Delay < opts.Timeout { if opts.Delay > 0 && opts.Timeout > 0 && opts.Delay < opts.Timeout {
err := gophercloud.ErrInvalidInput{} err := gophercloud.ErrInvalidInput{}
...@@ -190,7 +206,8 @@ func (opts UpdateOpts) ToLBMonitorUpdateMap() (map[string]interface{}, error) { ...@@ -190,7 +206,8 @@ func (opts UpdateOpts) ToLBMonitorUpdateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "health_monitor") return gophercloud.BuildRequestBody(opts, "health_monitor")
} }
// Update is an operation which modifies the attributes of the specified monitor. // Update is an operation which modifies the attributes of the specified
// monitor.
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
b, err := opts.ToLBMonitorUpdateMap() b, err := opts.ToLBMonitorUpdateMap()
if err != nil { if err != nil {
......
...@@ -21,46 +21,47 @@ import ( ...@@ -21,46 +21,47 @@ import (
// won't participate in its pool's load balancing. In other words, ALL monitors // won't participate in its pool's load balancing. In other words, ALL monitors
// must declare the member to be healthy for it to stay ACTIVE. // must declare the member to be healthy for it to stay ACTIVE.
type Monitor struct { type Monitor struct {
// The unique ID for the VIP. // ID is the unique ID for the Monitor.
ID string ID string
// Monitor name. Does not have to be unique. // Name is the monitor name. Does not have to be unique.
Name string Name string
// Owner of the VIP. Only an administrative user can specify a tenant ID // TenantID is the owner of the Monitor.
// other than its own.
TenantID string `json:"tenant_id"` TenantID string `json:"tenant_id"`
// The type of probe sent by the load balancer to verify the member state, // Type is the type of probe sent by the load balancer to verify the member
// which is PING, TCP, HTTP, or HTTPS. // state, which is PING, TCP, HTTP, or HTTPS.
Type string Type string
// The time, in seconds, between sending probes to members. // Delay is the time, in seconds, between sending probes to members.
Delay int Delay int
// The maximum number of seconds for a monitor to wait for a connection to be // Timeout is the maximum number of seconds for a monitor to wait for a
// established before it times out. This value must be less than the delay value. // connection to be established before it times out. This value must be less
// than the delay value.
Timeout int Timeout int
// Number of allowed connection failures before changing the status of the // MaxRetries is the number of allowed connection failures before changing the
// member to INACTIVE. A valid value is from 1 to 10. // status of the member to INACTIVE. A valid value is from 1 to 10.
MaxRetries int `json:"max_retries"` MaxRetries int `json:"max_retries"`
// The HTTP method that the monitor uses for requests. // HTTPMethod is the HTTP method that the monitor uses for requests.
HTTPMethod string `json:"http_method"` HTTPMethod string `json:"http_method"`
// The HTTP path of the request sent by the monitor to test the health of a // URLPath is the HTTP path of the request sent by the monitor to test the
// member. Must be a string beginning with a forward slash (/). // health of a member. Must be a string beginning with a forward slash (/).
URLPath string `json:"url_path"` URLPath string `json:"url_path"`
// Expected HTTP codes for a passing HTTP(S) monitor. // ExpectedCodes is the expected HTTP codes for a passing HTTP(S) monitor.
ExpectedCodes string `json:"expected_codes"` ExpectedCodes string `json:"expected_codes"`
// The administrative state of the health monitor, which is up (true) or down (false). // AdminStateUp is the administrative state of the health monitor, which is up
// (true) or down (false).
AdminStateUp bool `json:"admin_state_up"` AdminStateUp bool `json:"admin_state_up"`
// The status of the health monitor. Indicates whether the health monitor is // Status is the status of the health monitor. Indicates whether the health
// operational. // monitor is operational.
Status string Status string
} }
...@@ -115,22 +116,26 @@ func (r commonResult) Extract() (*Monitor, error) { ...@@ -115,22 +116,26 @@ func (r commonResult) Extract() (*Monitor, error) {
return s.Monitor, err return s.Monitor, err
} }
// CreateResult represents the result of a create operation. // CreateResult represents the result of a create operation. Call its Extract
// method to interpret it as a Monitor.
type CreateResult struct { type CreateResult struct {
commonResult commonResult
} }
// GetResult represents the result of a get operation. // GetResult represents the result of a get operation. Call its Extract
// method to interpret it as a Monitor.
type GetResult struct { type GetResult struct {
commonResult commonResult
} }
// UpdateResult represents the result of an update operation. // UpdateResult represents the result of an update operation. Call its Extract
// method to interpret it as a Monitor.
type UpdateResult struct { type UpdateResult struct {
commonResult commonResult
} }
// DeleteResult represents the result of a delete operation. // DeleteResult represents the result of a delete operation. Call its Extract
// method to determine if the request succeeded or failed.
type DeleteResult struct { type DeleteResult struct {
gophercloud.ErrResult gophercloud.ErrResult
} }
...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") ...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"doc.go",
"requests.go", "requests.go",
"results.go", "results.go",
"urls.go", "urls.go",
......
/*
Package pools provides information and interaction with the Pools of the
Load Balancing as a Service extension for the OpenStack Networking service.
Example to List Pools
listOpts := pools.ListOpts{
SubnetID: "d9bd223b-f1a9-4f98-953b-df977b0f902d",
}
allPages, err := pools.List(networkClient, listOpts).AllPages()
if err != nil {
panic(err)
}
allPools, err := pools.ExtractPools(allPages)
if err != nil {
panic(err)
}
for _, pool := range allPools {
fmt.Printf("%+v\n", pool)
}
Example to Create a Pool
createOpts := pools.CreateOpts{
LBMethod: pools.LBMethodRoundRobin,
Protocol: "HTTP",
Name: "Example pool",
SubnetID: "1981f108-3c48-48d2-b908-30f7d28532c9",
Provider: "haproxy",
}
pool, err := pools.Create(networkClient, createOpts).Extract()
if err != nil {
panic(err)
}
Example to Update a Pool
poolID := "166db5e6-c72a-4d77-8776-3573e27ae271"
updateOpts := pools.UpdateOpts{
LBMethod: pools.LBMethodLeastConnections,
}
pool, err := pools.Update(networkClient, poolID, updateOpts).Extract()
if err != nil {
panic(err)
}
Example to Delete a Pool
poolID := "166db5e6-c72a-4d77-8776-3573e27ae271"
err := pools.Delete(networkClient, poolID).ExtractErr()
if err != nil {
panic(err)
}
Example to Associate a Monitor to a Pool
poolID := "166db5e6-c72a-4d77-8776-3573e27ae271"
monitorID := "8bbfbe1c-6faa-4d97-abdb-0df6c90df70b"
pool, err := pools.AssociateMonitor(networkClient, poolID, monitorID).Extract()
if err != nil {
panic(err)
}
Example to Disassociate a Monitor from a Pool
poolID := "166db5e6-c72a-4d77-8776-3573e27ae271"
monitorID := "8bbfbe1c-6faa-4d97-abdb-0df6c90df70b"
pool, err := pools.DisassociateMonitor(networkClient, poolID, monitorID).Extract()
if err != nil {
panic(err)
}
*/
package pools
...@@ -43,10 +43,10 @@ func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager { ...@@ -43,10 +43,10 @@ func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
}) })
} }
// LBMethod is a type used for possible load balancing methods // LBMethod is a type used for possible load balancing methods.
type LBMethod string type LBMethod string
// LBProtocol is a type used for possible load balancing protocols // LBProtocol is a type used for possible load balancing protocols.
type LBProtocol string type LBProtocol string
// Supported attributes for create/update operations. // Supported attributes for create/update operations.
...@@ -59,8 +59,8 @@ const ( ...@@ -59,8 +59,8 @@ const (
ProtocolHTTPS LBProtocol = "HTTPS" ProtocolHTTPS LBProtocol = "HTTPS"
) )
// CreateOptsBuilder is the interface types must satisfy to be used as options // CreateOptsBuilder allows extensions to add additional parameters to the
// for the Create function // Create request.
type CreateOptsBuilder interface { type CreateOptsBuilder interface {
ToLBPoolCreateMap() (map[string]interface{}, error) ToLBPoolCreateMap() (map[string]interface{}, error)
} }
...@@ -69,25 +69,29 @@ type CreateOptsBuilder interface { ...@@ -69,25 +69,29 @@ type CreateOptsBuilder interface {
type CreateOpts struct { type CreateOpts struct {
// Name of the pool. // Name of the pool.
Name string `json:"name" required:"true"` Name string `json:"name" required:"true"`
// The protocol used by the pool members, you can use either
// Protocol used by the pool members, you can use either
// ProtocolTCP, ProtocolHTTP, or ProtocolHTTPS. // ProtocolTCP, ProtocolHTTP, or ProtocolHTTPS.
Protocol LBProtocol `json:"protocol" required:"true"` Protocol LBProtocol `json:"protocol" required:"true"`
// Only required if the caller has an admin role and wants to create a pool
// for another tenant. // TenantID is only required if the caller has an admin role and wants
// to create a pool for another tenant.
TenantID string `json:"tenant_id,omitempty"` TenantID string `json:"tenant_id,omitempty"`
// The network on which the members of the pool will be located. Only members
// that are on this network can be added to the pool. // SubnetID is the network on which the members of the pool will be located.
// Only members that are on this network can be added to the pool.
SubnetID string `json:"subnet_id,omitempty"` SubnetID string `json:"subnet_id,omitempty"`
// The algorithm used to distribute load between the members of the pool. The
// current specification supports LBMethodRoundRobin and // LBMethod is the algorithm used to distribute load between the members of
// the pool. The current specification supports LBMethodRoundRobin and
// LBMethodLeastConnections as valid values for this attribute. // LBMethodLeastConnections as valid values for this attribute.
LBMethod LBMethod `json:"lb_method" required:"true"` LBMethod LBMethod `json:"lb_method" required:"true"`
// The provider of the pool // Provider of the pool.
Provider string `json:"provider,omitempty"` Provider string `json:"provider,omitempty"`
} }
// ToLBPoolCreateMap allows CreateOpts to satisfy the CreateOptsBuilder interface // ToLBPoolCreateMap builds a request body based on CreateOpts.
func (opts CreateOpts) ToLBPoolCreateMap() (map[string]interface{}, error) { func (opts CreateOpts) ToLBPoolCreateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "pool") return gophercloud.BuildRequestBody(opts, "pool")
} }
...@@ -110,8 +114,8 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { ...@@ -110,8 +114,8 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
return return
} }
// UpdateOptsBuilder is the interface types must satisfy to be used as options // UpdateOptsBuilder allows extensions to add additional parameters ot the
// for the Update function // Update request.
type UpdateOptsBuilder interface { type UpdateOptsBuilder interface {
ToLBPoolUpdateMap() (map[string]interface{}, error) ToLBPoolUpdateMap() (map[string]interface{}, error)
} }
...@@ -120,13 +124,14 @@ type UpdateOptsBuilder interface { ...@@ -120,13 +124,14 @@ type UpdateOptsBuilder interface {
type UpdateOpts struct { type UpdateOpts struct {
// Name of the pool. // Name of the pool.
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
// The algorithm used to distribute load between the members of the pool. The
// current specification supports LBMethodRoundRobin and // LBMethod is the algorithm used to distribute load between the members of
// the pool. The current specification supports LBMethodRoundRobin and
// LBMethodLeastConnections as valid values for this attribute. // LBMethodLeastConnections as valid values for this attribute.
LBMethod LBMethod `json:"lb_method,omitempty"` LBMethod LBMethod `json:"lb_method,omitempty"`
} }
// ToLBPoolUpdateMap allows UpdateOpts to satisfy the UpdateOptsBuilder interface // ToLBPoolUpdateMap builds a request body based on UpdateOpts.
func (opts UpdateOpts) ToLBPoolUpdateMap() (map[string]interface{}, error) { func (opts UpdateOpts) ToLBPoolUpdateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "pool") return gophercloud.BuildRequestBody(opts, "pool")
} }
......
...@@ -11,47 +11,48 @@ import ( ...@@ -11,47 +11,48 @@ import (
// method to handle the new requests or connections received on the VIP address. // method to handle the new requests or connections received on the VIP address.
// There is only one pool per virtual IP. // There is only one pool per virtual IP.
type Pool struct { type Pool struct {
// The status of the pool. Indicates whether the pool is operational. // Status of the pool. Indicates whether the pool is operational.
Status string Status string
// The load-balancer algorithm, which is round-robin, least-connections, and // LBMethod is the load-balancer algorithm, which is round-robin,
// so on. This value, which must be supported, is dependent on the provider. // least-connections, and so on. This value, which must be supported, is
// Round-robin must be supported. // dependent on the provider.
LBMethod string `json:"lb_method"` LBMethod string `json:"lb_method"`
// The protocol of the pool, which is TCP, HTTP, or HTTPS. // Protocol of the pool, which is TCP, HTTP, or HTTPS.
Protocol string Protocol string
// Description for the pool. // Description for the pool.
Description string Description string
// The IDs of associated monitors which check the health of the pool members. // MonitorIDs are the IDs of associated monitors which check the health of
// the pool members.
MonitorIDs []string `json:"health_monitors"` MonitorIDs []string `json:"health_monitors"`
// The network on which the members of the pool will be located. Only members // SubnetID is the network on which the members of the pool will be located.
// that are on this network can be added to the pool. // Only members that are on this network can be added to the pool.
SubnetID string `json:"subnet_id"` SubnetID string `json:"subnet_id"`
// Owner of the pool. Only an administrative user can specify a tenant ID // TenantID is the owner of the pool.
// other than its own.
TenantID string `json:"tenant_id"` TenantID string `json:"tenant_id"`
// The administrative state of the pool, which is up (true) or down (false). // AdminStateUp is the administrative state of the pool, which is up
// (true) or down (false).
AdminStateUp bool `json:"admin_state_up"` AdminStateUp bool `json:"admin_state_up"`
// Pool name. Does not have to be unique. // Name of the pool.
Name string Name string
// List of member IDs that belong to the pool. // MemberIDs is the list of member IDs that belong to the pool.
MemberIDs []string `json:"members"` MemberIDs []string `json:"members"`
// The unique ID for the pool. // ID is the unique ID for the pool.
ID string ID string
// The ID of the virtual IP associated with this pool // VIPID is the ID of the virtual IP associated with this pool.
VIPID string `json:"vip_id"` VIPID string `json:"vip_id"`
// The provider // The provider.
Provider string Provider string
} }
...@@ -81,7 +82,7 @@ func (r PoolPage) IsEmpty() (bool, error) { ...@@ -81,7 +82,7 @@ func (r PoolPage) IsEmpty() (bool, error) {
return len(is) == 0, err return len(is) == 0, err
} }
// ExtractPools accepts a Page struct, specifically a RouterPage struct, // ExtractPools accepts a Page struct, specifically a PoolPage struct,
// and extracts the elements into a slice of Router structs. In other words, // and extracts the elements into a slice of Router structs. In other words,
// a generic collection is mapped into a relevant slice. // a generic collection is mapped into a relevant slice.
func ExtractPools(r pagination.Page) ([]Pool, error) { func ExtractPools(r pagination.Page) ([]Pool, error) {
...@@ -105,27 +106,32 @@ func (r commonResult) Extract() (*Pool, error) { ...@@ -105,27 +106,32 @@ func (r commonResult) Extract() (*Pool, error) {
return s.Pool, err return s.Pool, err
} }
// CreateResult represents the result of a create operation. // CreateResult represents the result of a create operation. Call its Extract
// method to interpret it as a Pool.
type CreateResult struct { type CreateResult struct {
commonResult commonResult
} }
// GetResult represents the result of a get operation. // GetResult represents the result of a get operation. Call its Extract
// method to interpret it as a Pool.
type GetResult struct { type GetResult struct {
commonResult commonResult
} }
// UpdateResult represents the result of an update operation. // UpdateResult represents the result of an update operation. Call its Extract
// method to interpret it as a Pool.
type UpdateResult struct { type UpdateResult struct {
commonResult commonResult
} }
// DeleteResult represents the result of a delete operation. // DeleteResult represents the result of a delete operation. Call its
// ExtractErr method to interpret it as a Pool.
type DeleteResult struct { type DeleteResult struct {
gophercloud.ErrResult gophercloud.ErrResult
} }
// AssociateResult represents the result of an association operation. // AssociateResult represents the result of an association operation. Call its Extract
// method to interpret it as a Pool.
type AssociateResult struct { type AssociateResult struct {
commonResult commonResult
} }
...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") ...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"doc.go",
"requests.go", "requests.go",
"results.go", "results.go",
"urls.go", "urls.go",
......
/*
Package vips provides information and interaction with the Virtual IPs of the
Load Balancing as a Service extension for the OpenStack Networking service.
Example to List Virtual IPs
listOpts := vips.ListOpts{
SubnetID: "d9bd223b-f1a9-4f98-953b-df977b0f902d",
}
allPages, err := vips.List(networkClient, listOpts).AllPages()
if err != nil {
panic(err)
}
allVIPs, err := vips.ExtractVIPs(allPages)
if err != nil {
panic(err)
}
for _, vip := range allVIPs {
fmt.Printf("%+v\n", vip)
}
Example to Create a Virtual IP
createOpts := vips.CreateOpts{
Protocol: "HTTP",
Name: "NewVip",
AdminStateUp: gophercloud.Enabled,
SubnetID: "8032909d-47a1-4715-90af-5153ffe39861",
PoolID: "61b1f87a-7a21-4ad3-9dda-7f81d249944f",
ProtocolPort: 80,
Persistence: &vips.SessionPersistence{Type: "SOURCE_IP"},
}
vip, err := vips.Create(networkClient, createOpts).Extract()
if err != nil {
panic(err)
}
Example to Update a Virtual IP
vipID := "93f1bad4-0423-40a8-afac-3fc541839912"
i1000 := 1000
updateOpts := vips.UpdateOpts{
ConnLimit: &i1000,
Persistence: &vips.SessionPersistence{Type: "SOURCE_IP"},
}
vip, err := vips.Update(networkClient, vipID, updateOpts).Extract()
if err != nil {
panic(err)
}
Example to Delete a Virtual IP
vipID := "93f1bad4-0423-40a8-afac-3fc541839912"
err := vips.Delete(networkClient, vipID).ExtractErr()
if err != nil {
panic(err)
}
*/
package vips
...@@ -29,10 +29,10 @@ type ListOpts struct { ...@@ -29,10 +29,10 @@ type ListOpts struct {
} }
// List returns a Pager which allows you to iterate over a collection of // List returns a Pager which allows you to iterate over a collection of
// routers. It accepts a ListOpts struct, which allows you to filter and sort // Virtual IPs. It accepts a ListOpts struct, which allows you to filter and
// the returned collection for greater efficiency. // sort the returned collection for greater efficiency.
// //
// Default policy settings return only those routers that are owned by the // Default policy settings return only those virtual IPs that are owned by the
// tenant who submits the request, unless an admin user submits the request. // tenant who submits the request, unless an admin user submits the request.
func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager { func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
q, err := gophercloud.BuildQueryString(&opts) q, err := gophercloud.BuildQueryString(&opts)
...@@ -45,43 +45,54 @@ func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager { ...@@ -45,43 +45,54 @@ func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
}) })
} }
// CreateOptsBuilder is what types must satisfy to be used as Create // CreateOptsBuilder allows extensions to add additional parameters to the
// options. // Create Request.
type CreateOptsBuilder interface { type CreateOptsBuilder interface {
ToVIPCreateMap() (map[string]interface{}, error) ToVIPCreateMap() (map[string]interface{}, error)
} }
// CreateOpts contains all the values needed to create a new virtual IP. // CreateOpts contains all the values needed to create a new virtual IP.
type CreateOpts struct { type CreateOpts struct {
// Human-readable name for the VIP. Does not have to be unique. // Name is the human-readable name for the VIP. Does not have to be unique.
Name string `json:"name" required:"true"` Name string `json:"name" required:"true"`
// The network on which to allocate the VIP's address. A tenant can
// only create VIPs on networks authorized by policy (e.g. networks that // SubnetID is the network on which to allocate the VIP's address. A tenant
// can only create VIPs on networks authorized by policy (e.g. networks that
// belong to them or networks that are shared). // belong to them or networks that are shared).
SubnetID string `json:"subnet_id" required:"true"` SubnetID string `json:"subnet_id" required:"true"`
// The protocol - can either be TCP, HTTP or HTTPS.
// Protocol - can either be TCP, HTTP or HTTPS.
Protocol string `json:"protocol" required:"true"` Protocol string `json:"protocol" required:"true"`
// The port on which to listen for client traffic.
// ProtocolPort is the port on which to listen for client traffic.
ProtocolPort int `json:"protocol_port" required:"true"` ProtocolPort int `json:"protocol_port" required:"true"`
// The ID of the pool with which the VIP is associated.
// PoolID is the ID of the pool with which the VIP is associated.
PoolID string `json:"pool_id" required:"true"` PoolID string `json:"pool_id" required:"true"`
// Required for admins. Indicates the owner of the VIP.
// TenantID is only required if the caller has an admin role and wants
// to create a pool for another tenant.
TenantID string `json:"tenant_id,omitempty"` TenantID string `json:"tenant_id,omitempty"`
// The IP address of the VIP.
// Address is the IP address of the VIP.
Address string `json:"address,omitempty"` Address string `json:"address,omitempty"`
// Human-readable description for the VIP.
// Description is the human-readable description for the VIP.
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
// Persistence is the the of session persistence to use.
// Omit this field to prevent session persistence. // Omit this field to prevent session persistence.
Persistence *SessionPersistence `json:"session_persistence,omitempty"` Persistence *SessionPersistence `json:"session_persistence,omitempty"`
// The maximum number of connections allowed for the VIP.
// ConnLimit is the maximum number of connections allowed for the VIP.
ConnLimit *int `json:"connection_limit,omitempty"` ConnLimit *int `json:"connection_limit,omitempty"`
// The administrative state of the VIP. A valid value is true (UP)
// or false (DOWN). // AdminStateUp is the administrative state of the VIP. A valid value is
// true (UP) or false (DOWN).
AdminStateUp *bool `json:"admin_state_up,omitempty"` AdminStateUp *bool `json:"admin_state_up,omitempty"`
} }
// ToVIPCreateMap allows CreateOpts to satisfy the CreateOptsBuilder // ToVIPCreateMap builds a request body from CreateOpts.
// interface
func (opts CreateOpts) ToVIPCreateMap() (map[string]interface{}, error) { func (opts CreateOpts) ToVIPCreateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "vip") return gophercloud.BuildRequestBody(opts, "vip")
} }
...@@ -113,8 +124,8 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { ...@@ -113,8 +124,8 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
return return
} }
// UpdateOptsBuilder is what types must satisfy to be used as Update // UpdateOptsBuilder allows extensions to add additional parameters to the
// options. // Update request.
type UpdateOptsBuilder interface { type UpdateOptsBuilder interface {
ToVIPUpdateMap() (map[string]interface{}, error) ToVIPUpdateMap() (map[string]interface{}, error)
} }
...@@ -123,22 +134,28 @@ type UpdateOptsBuilder interface { ...@@ -123,22 +134,28 @@ type UpdateOptsBuilder interface {
// Attributes not listed here but appear in CreateOpts are immutable and cannot // Attributes not listed here but appear in CreateOpts are immutable and cannot
// be updated. // be updated.
type UpdateOpts struct { type UpdateOpts struct {
// Human-readable name for the VIP. Does not have to be unique. // Name is the human-readable name for the VIP. Does not have to be unique.
Name *string `json:"name,omitempty"` Name *string `json:"name,omitempty"`
// The ID of the pool with which the VIP is associated.
// PoolID is the ID of the pool with which the VIP is associated.
PoolID *string `json:"pool_id,omitempty"` PoolID *string `json:"pool_id,omitempty"`
// Human-readable description for the VIP.
// Description is the human-readable description for the VIP.
Description *string `json:"description,omitempty"` Description *string `json:"description,omitempty"`
// Persistence is the the of session persistence to use.
// Omit this field to prevent session persistence. // Omit this field to prevent session persistence.
Persistence *SessionPersistence `json:"session_persistence,omitempty"` Persistence *SessionPersistence `json:"session_persistence,omitempty"`
// The maximum number of connections allowed for the VIP.
// ConnLimit is the maximum number of connections allowed for the VIP.
ConnLimit *int `json:"connection_limit,omitempty"` ConnLimit *int `json:"connection_limit,omitempty"`
// The administrative state of the VIP. A valid value is true (UP)
// or false (DOWN). // AdminStateUp is the administrative state of the VIP. A valid value is
// true (UP) or false (DOWN).
AdminStateUp *bool `json:"admin_state_up,omitempty"` AdminStateUp *bool `json:"admin_state_up,omitempty"`
} }
// ToVIPUpdateMap allows UpdateOpts to satisfy the UpdateOptsBuilder interface // ToVIPUpdateMap builds a request body based on UpdateOpts.
func (opts UpdateOpts) ToVIPUpdateMap() (map[string]interface{}, error) { func (opts UpdateOpts) ToVIPUpdateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "vip") return gophercloud.BuildRequestBody(opts, "vip")
} }
......
...@@ -21,10 +21,10 @@ import ( ...@@ -21,10 +21,10 @@ import (
// requests carrying the same cookie value will be handled by the // requests carrying the same cookie value will be handled by the
// same member of the pool. // same member of the pool.
type SessionPersistence struct { type SessionPersistence struct {
// The type of persistence mode // Type is the type of persistence mode.
Type string `json:"type"` Type string `json:"type"`
// Name of cookie if persistence mode is set appropriately // CookieName is the name of cookie if persistence mode is set appropriately.
CookieName string `json:"cookie_name,omitempty"` CookieName string `json:"cookie_name,omitempty"`
} }
...@@ -34,54 +34,55 @@ type SessionPersistence struct { ...@@ -34,54 +34,55 @@ type SessionPersistence struct {
// This entity is sometimes known in LB products under the name of a "virtual // This entity is sometimes known in LB products under the name of a "virtual
// server", a "vserver" or a "listener". // server", a "vserver" or a "listener".
type VirtualIP struct { type VirtualIP struct {
// The unique ID for the VIP. // ID is the unique ID for the VIP.
ID string `json:"id"` ID string `json:"id"`
// Owner of the VIP. Only an admin user can specify a tenant ID other than its own. // TenantID is the owner of the VIP.
TenantID string `json:"tenant_id"` TenantID string `json:"tenant_id"`
// Human-readable name for the VIP. Does not have to be unique. // Name is the human-readable name for the VIP. Does not have to be unique.
Name string `json:"name"` Name string `json:"name"`
// Human-readable description for the VIP. // Description is the human-readable description for the VIP.
Description string `json:"description"` Description string `json:"description"`
// The ID of the subnet on which to allocate the VIP address. // SubnetID is the ID of the subnet on which to allocate the VIP address.
SubnetID string `json:"subnet_id"` SubnetID string `json:"subnet_id"`
// The IP address of the VIP. // Address is the IP address of the VIP.
Address string `json:"address"` Address string `json:"address"`
// The protocol of the VIP address. A valid value is TCP, HTTP, or HTTPS. // Protocol of the VIP address. A valid value is TCP, HTTP, or HTTPS.
Protocol string `json:"protocol"` Protocol string `json:"protocol"`
// The port on which to listen to client traffic that is associated with the // ProtocolPort is the port on which to listen to client traffic that is
// VIP address. A valid value is from 0 to 65535. // associated with the VIP address. A valid value is from 0 to 65535.
ProtocolPort int `json:"protocol_port"` ProtocolPort int `json:"protocol_port"`
// The ID of the pool with which the VIP is associated. // PoolID is the ID of the pool with which the VIP is associated.
PoolID string `json:"pool_id"` PoolID string `json:"pool_id"`
// The ID of the port which belongs to the load balancer // PortID is the ID of the port which belongs to the load balancer.
PortID string `json:"port_id"` PortID string `json:"port_id"`
// Indicates whether connections in the same session will be processed by the // Persistence indicates whether connections in the same session will be
// same pool member or not. // processed by the same pool member or not.
Persistence SessionPersistence `json:"session_persistence"` Persistence SessionPersistence `json:"session_persistence"`
// The maximum number of connections allowed for the VIP. Default is -1, // ConnLimit is the maximum number of connections allowed for the VIP.
// meaning no limit. // Default is -1, meaning no limit.
ConnLimit int `json:"connection_limit"` ConnLimit int `json:"connection_limit"`
// The administrative state of the VIP. A valid value is true (UP) or false (DOWN). // AdminStateUp is the administrative state of the VIP. A valid value is
// true (UP) or false (DOWN).
AdminStateUp bool `json:"admin_state_up"` AdminStateUp bool `json:"admin_state_up"`
// The status of the VIP. Indicates whether the VIP is operational. // Status is the status of the VIP. Indicates whether the VIP is operational.
Status string `json:"status"` Status string `json:"status"`
} }
// VIPPage is the page returned by a pager when traversing over a // VIPPage is the page returned by a pager when traversing over a
// collection of routers. // collection of virtual IPs.
type VIPPage struct { type VIPPage struct {
pagination.LinkedPageBase pagination.LinkedPageBase
} }
...@@ -121,7 +122,7 @@ type commonResult struct { ...@@ -121,7 +122,7 @@ type commonResult struct {
gophercloud.Result gophercloud.Result
} }
// Extract is a function that accepts a result and extracts a router. // Extract is a function that accepts a result and extracts a VirtualIP.
func (r commonResult) Extract() (*VirtualIP, error) { func (r commonResult) Extract() (*VirtualIP, error) {
var s struct { var s struct {
VirtualIP *VirtualIP `json:"vip" json:"vip"` VirtualIP *VirtualIP `json:"vip" json:"vip"`
...@@ -130,22 +131,26 @@ func (r commonResult) Extract() (*VirtualIP, error) { ...@@ -130,22 +131,26 @@ func (r commonResult) Extract() (*VirtualIP, error) {
return s.VirtualIP, err return s.VirtualIP, err
} }
// CreateResult represents the result of a create operation. // CreateResult represents the result of a create operation. Call its Extract
// method to interpret it as a VirtualIP
type CreateResult struct { type CreateResult struct {
commonResult commonResult
} }
// GetResult represents the result of a get operation. // GetResult represents the result of a get operation. Call its Extract
// method to interpret it as a VirtualIP
type GetResult struct { type GetResult struct {
commonResult commonResult
} }
// UpdateResult represents the result of an update operation. // UpdateResult represents the result of an update operation. Call its Extract
// method to interpret it as a VirtualIP
type UpdateResult struct { type UpdateResult struct {
commonResult commonResult
} }
// DeleteResult represents the result of a delete operation. // DeleteResult represents the result of a delete operation. Call its
// ExtractErr method to determine if the request succeeded or failed.
type DeleteResult struct { type DeleteResult struct {
gophercloud.ErrResult gophercloud.ErrResult
} }
...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") ...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"doc.go",
"requests.go", "requests.go",
"results.go", "results.go",
"urls.go", "urls.go",
......
/*
Package listeners provides information and interaction with Listeners of the
LBaaS v2 extension for the OpenStack Networking service.
Example to List Listeners
listOpts := listeners.ListOpts{
LoadbalancerID : "ca430f80-1737-4712-8dc6-3f640d55594b",
}
allPages, err := listeners.List(networkClient, listOpts).AllPages()
if err != nil {
panic(err)
}
allListeners, err := listeners.ExtractListeners(allPages)
if err != nil {
panic(err)
}
for _, listener := range allListeners {
fmt.Printf("%+v\n", listener)
}
Example to Create a Listener
createOpts := listeners.CreateOpts{
Protocol: "TCP",
Name: "db",
LoadbalancerID: "79e05663-7f03-45d2-a092-8b94062f22ab",
AdminStateUp: gophercloud.Enabled,
DefaultPoolID: "41efe233-7591-43c5-9cf7-923964759f9e",
ProtocolPort: 3306,
}
listener, err := listeners.Create(networkClient, createOpts).Extract()
if err != nil {
panic(err)
}
Example to Update a Listener
listenerID := "d67d56a6-4a86-4688-a282-f46444705c64"
i1001 := 1001
updateOpts := listeners.UpdateOpts{
ConnLimit: &i1001,
}
listener, err := listeners.Update(networkClient, listenerID, updateOpts).Extract()
if err != nil {
panic(err)
}
Example to Delete a Listener
listenerID := "d67d56a6-4a86-4688-a282-f46444705c64"
err := listeners.Delete(networkClient, listenerID).ExtractErr()
if err != nil {
panic(err)
}
*/
package listeners
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"github.com/gophercloud/gophercloud/pagination" "github.com/gophercloud/gophercloud/pagination"
) )
// Type Protocol represents a listener protocol.
type Protocol string type Protocol string
// Supported attributes for create/update operations. // Supported attributes for create/update operations.
...@@ -48,10 +49,10 @@ func (opts ListOpts) ToListenerListQuery() (string, error) { ...@@ -48,10 +49,10 @@ func (opts ListOpts) ToListenerListQuery() (string, error) {
} }
// List returns a Pager which allows you to iterate over a collection of // List returns a Pager which allows you to iterate over a collection of
// routers. It accepts a ListOpts struct, which allows you to filter and sort // listeners. It accepts a ListOpts struct, which allows you to filter and sort
// the returned collection for greater efficiency. // the returned collection for greater efficiency.
// //
// Default policy settings return only those routers that are owned by the // Default policy settings return only those listeners that are owned by the
// tenant who submits the request, unless an admin user submits the request. // tenant who submits the request, unless an admin user submits the request.
func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
url := rootURL(c) url := rootURL(c)
...@@ -67,43 +68,51 @@ func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { ...@@ -67,43 +68,51 @@ func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
}) })
} }
// CreateOptsBuilder is the interface options structs have to satisfy in order // CreateOptsBuilder allows extensions to add additional parameters to the
// to be used in the main Create operation in this package. Since many // Create request.
// extensions decorate or modify the common logic, it is useful for them to
// satisfy a basic interface in order for them to be used.
type CreateOptsBuilder interface { type CreateOptsBuilder interface {
ToListenerCreateMap() (map[string]interface{}, error) ToListenerCreateMap() (map[string]interface{}, error)
} }
// CreateOpts is the common options struct used in this package's Create // CreateOpts represents options for creating a listener.
// operation.
type CreateOpts struct { type CreateOpts struct {
// The load balancer on which to provision this listener. // The load balancer on which to provision this listener.
LoadbalancerID string `json:"loadbalancer_id" required:"true"` LoadbalancerID string `json:"loadbalancer_id" required:"true"`
// The protocol - can either be TCP, HTTP or HTTPS. // The protocol - can either be TCP, HTTP or HTTPS.
Protocol Protocol `json:"protocol" required:"true"` Protocol Protocol `json:"protocol" required:"true"`
// The port on which to listen for client traffic. // The port on which to listen for client traffic.
ProtocolPort int `json:"protocol_port" required:"true"` ProtocolPort int `json:"protocol_port" required:"true"`
// Indicates the owner of the Listener. Required for admins.
// TenantID is only required if the caller has an admin role and wants
// to create a pool for another tenant.
TenantID string `json:"tenant_id,omitempty"` TenantID string `json:"tenant_id,omitempty"`
// Human-readable name for the Listener. Does not have to be unique. // Human-readable name for the Listener. Does not have to be unique.
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
// The ID of the default pool with which the Listener is associated. // The ID of the default pool with which the Listener is associated.
DefaultPoolID string `json:"default_pool_id,omitempty"` DefaultPoolID string `json:"default_pool_id,omitempty"`
// Human-readable description for the Listener. // Human-readable description for the Listener.
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
// The maximum number of connections allowed for the Listener. // The maximum number of connections allowed for the Listener.
ConnLimit *int `json:"connection_limit,omitempty"` ConnLimit *int `json:"connection_limit,omitempty"`
// A reference to a container of TLS secrets.
// A reference to a Barbican container of TLS secrets.
DefaultTlsContainerRef string `json:"default_tls_container_ref,omitempty"` DefaultTlsContainerRef string `json:"default_tls_container_ref,omitempty"`
// A list of references to TLS secrets. // A list of references to TLS secrets.
SniContainerRefs []string `json:"sni_container_refs,omitempty"` SniContainerRefs []string `json:"sni_container_refs,omitempty"`
// The administrative state of the Listener. A valid value is true (UP) // The administrative state of the Listener. A valid value is true (UP)
// or false (DOWN). // or false (DOWN).
AdminStateUp *bool `json:"admin_state_up,omitempty"` AdminStateUp *bool `json:"admin_state_up,omitempty"`
} }
// ToListenerCreateMap casts a CreateOpts struct to a map. // ToListenerCreateMap builds a request body from CreateOpts.
func (opts CreateOpts) ToListenerCreateMap() (map[string]interface{}, error) { func (opts CreateOpts) ToListenerCreateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "listener") return gophercloud.BuildRequestBody(opts, "listener")
} }
...@@ -131,38 +140,41 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { ...@@ -131,38 +140,41 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
return return
} }
// UpdateOptsBuilder is the interface options structs have to satisfy in order // UpdateOptsBuilder allows extensions to add additional parameters to the
// to be used in the main Update operation in this package. Since many // Update request.
// extensions decorate or modify the common logic, it is useful for them to
// satisfy a basic interface in order for them to be used.
type UpdateOptsBuilder interface { type UpdateOptsBuilder interface {
ToListenerUpdateMap() (map[string]interface{}, error) ToListenerUpdateMap() (map[string]interface{}, error)
} }
// UpdateOpts is the common options struct used in this package's Update // UpdateOpts represents options for updating a Listener.
// operation.
type UpdateOpts struct { type UpdateOpts struct {
// Human-readable name for the Listener. Does not have to be unique. // Human-readable name for the Listener. Does not have to be unique.
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
// Human-readable description for the Listener. // Human-readable description for the Listener.
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
// The maximum number of connections allowed for the Listener. // The maximum number of connections allowed for the Listener.
ConnLimit *int `json:"connection_limit,omitempty"` ConnLimit *int `json:"connection_limit,omitempty"`
// A reference to a container of TLS secrets.
// A reference to a Barbican container of TLS secrets.
DefaultTlsContainerRef string `json:"default_tls_container_ref,omitempty"` DefaultTlsContainerRef string `json:"default_tls_container_ref,omitempty"`
// A list of references to TLS secrets.
// A list of references to TLS secrets.
SniContainerRefs []string `json:"sni_container_refs,omitempty"` SniContainerRefs []string `json:"sni_container_refs,omitempty"`
// The administrative state of the Listener. A valid value is true (UP) // The administrative state of the Listener. A valid value is true (UP)
// or false (DOWN). // or false (DOWN).
AdminStateUp *bool `json:"admin_state_up,omitempty"` AdminStateUp *bool `json:"admin_state_up,omitempty"`
} }
// ToListenerUpdateMap casts a UpdateOpts struct to a map. // ToListenerUpdateMap builds a request body from UpdateOpts.
func (opts UpdateOpts) ToListenerUpdateMap() (map[string]interface{}, error) { func (opts UpdateOpts) ToListenerUpdateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "listener") return gophercloud.BuildRequestBody(opts, "listener")
} }
// Update is an operation which modifies the attributes of the specified Listener. // Update is an operation which modifies the attributes of the specified
// Listener.
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) (r UpdateResult) { func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) (r UpdateResult) {
b, err := opts.ToListenerUpdateMap() b, err := opts.ToListenerUpdateMap()
if err != nil { if err != nil {
......
...@@ -16,40 +16,53 @@ type LoadBalancerID struct { ...@@ -16,40 +16,53 @@ type LoadBalancerID struct {
type Listener struct { type Listener struct {
// The unique ID for the Listener. // The unique ID for the Listener.
ID string `json:"id"` ID string `json:"id"`
// Owner of the Listener. Only an admin user can specify a tenant ID other than its own.
// Owner of the Listener.
TenantID string `json:"tenant_id"` TenantID string `json:"tenant_id"`
// Human-readable name for the Listener. Does not have to be unique. // Human-readable name for the Listener. Does not have to be unique.
Name string `json:"name"` Name string `json:"name"`
// Human-readable description for the Listener. // Human-readable description for the Listener.
Description string `json:"description"` Description string `json:"description"`
// The protocol to loadbalance. A valid value is TCP, HTTP, or HTTPS. // The protocol to loadbalance. A valid value is TCP, HTTP, or HTTPS.
Protocol string `json:"protocol"` Protocol string `json:"protocol"`
// The port on which to listen to client traffic that is associated with the // The port on which to listen to client traffic that is associated with the
// Loadbalancer. A valid value is from 0 to 65535. // Loadbalancer. A valid value is from 0 to 65535.
ProtocolPort int `json:"protocol_port"` ProtocolPort int `json:"protocol_port"`
// The UUID of default pool. Must have compatible protocol with listener. // The UUID of default pool. Must have compatible protocol with listener.
DefaultPoolID string `json:"default_pool_id"` DefaultPoolID string `json:"default_pool_id"`
// A list of load balancer IDs. // A list of load balancer IDs.
Loadbalancers []LoadBalancerID `json:"loadbalancers"` Loadbalancers []LoadBalancerID `json:"loadbalancers"`
// The maximum number of connections allowed for the Loadbalancer. Default is -1,
// meaning no limit. // The maximum number of connections allowed for the Loadbalancer.
// Default is -1, meaning no limit.
ConnLimit int `json:"connection_limit"` ConnLimit int `json:"connection_limit"`
// The list of references to TLS secrets. // The list of references to TLS secrets.
SniContainerRefs []string `json:"sni_container_refs"` SniContainerRefs []string `json:"sni_container_refs"`
// Optional. A reference to a container of TLS secrets.
// A reference to a Barbican container of TLS secrets.
DefaultTlsContainerRef string `json:"default_tls_container_ref"` DefaultTlsContainerRef string `json:"default_tls_container_ref"`
// The administrative state of the Listener. A valid value is true (UP) or false (DOWN). // The administrative state of the Listener. A valid value is true (UP) or false (DOWN).
AdminStateUp bool `json:"admin_state_up"` AdminStateUp bool `json:"admin_state_up"`
Pools []pools.Pool `json:"pools"`
// Pools are the pools which are part of this listener.
Pools []pools.Pool `json:"pools"`
} }
// ListenerPage is the page returned by a pager when traversing over a // ListenerPage is the page returned by a pager when traversing over a
// collection of routers. // collection of listeners.
type ListenerPage struct { type ListenerPage struct {
pagination.LinkedPageBase pagination.LinkedPageBase
} }
// NextPageURL is invoked when a paginated collection of routers has reached // NextPageURL is invoked when a paginated collection of listeners has reached
// the end of a page and the pager seeks to traverse over a new one. In order // the end of a page and the pager seeks to traverse over a new one. In order
// to do this, it needs to construct the next page's URL. // to do this, it needs to construct the next page's URL.
func (r ListenerPage) NextPageURL() (string, error) { func (r ListenerPage) NextPageURL() (string, error) {
...@@ -63,7 +76,7 @@ func (r ListenerPage) NextPageURL() (string, error) { ...@@ -63,7 +76,7 @@ func (r ListenerPage) NextPageURL() (string, error) {
return gophercloud.ExtractNextURL(s.Links) return gophercloud.ExtractNextURL(s.Links)
} }
// IsEmpty checks whether a RouterPage struct is empty. // IsEmpty checks whether a ListenerPage struct is empty.
func (r ListenerPage) IsEmpty() (bool, error) { func (r ListenerPage) IsEmpty() (bool, error) {
is, err := ExtractListeners(r) is, err := ExtractListeners(r)
return len(is) == 0, err return len(is) == 0, err
...@@ -84,7 +97,7 @@ type commonResult struct { ...@@ -84,7 +97,7 @@ type commonResult struct {
gophercloud.Result gophercloud.Result
} }
// Extract is a function that accepts a result and extracts a router. // Extract is a function that accepts a result and extracts a listener.
func (r commonResult) Extract() (*Listener, error) { func (r commonResult) Extract() (*Listener, error) {
var s struct { var s struct {
Listener *Listener `json:"listener"` Listener *Listener `json:"listener"`
...@@ -93,22 +106,26 @@ func (r commonResult) Extract() (*Listener, error) { ...@@ -93,22 +106,26 @@ func (r commonResult) Extract() (*Listener, error) {
return s.Listener, err return s.Listener, err
} }
// CreateResult represents the result of a create operation. // CreateResult represents the result of a create operation. Call its Extract
// method to interpret it as a Listener.
type CreateResult struct { type CreateResult struct {
commonResult commonResult
} }
// GetResult represents the result of a get operation. // GetResult represents the result of a get operation. Call its Extract
// method to interpret it as a Listener.
type GetResult struct { type GetResult struct {
commonResult commonResult
} }
// UpdateResult represents the result of an update operation. // UpdateResult represents the result of an update operation. Call its Extract
// method to interpret it as a Listener.
type UpdateResult struct { type UpdateResult struct {
commonResult commonResult
} }
// DeleteResult represents the result of a delete operation. // DeleteResult represents the result of a delete operation. Call its
// ExtractErr method to determine if the request succeeded or failed.
type DeleteResult struct { type DeleteResult struct {
gophercloud.ErrResult gophercloud.ErrResult
} }
...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") ...@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"doc.go",
"requests.go", "requests.go",
"results.go", "results.go",
"urls.go", "urls.go",
......
/*
Package loadbalancers provides information and interaction with Load Balancers
of the LBaaS v2 extension for the OpenStack Networking service.
Example to List Load Balancers
listOpts := loadbalancers.ListOpts{
Provider: "haproxy",
}
allPages, err := loadbalancers.List(networkClient, listOpts).AllPages()
if err != nil {
panic(err)
}
allLoadbalancers, err := loadbalancers.ExtractLoadBalancers(allPages)
if err != nil {
panic(err)
}
for _, lb := range allLoadbalancers {
fmt.Printf("%+v\n", lb)
}
Example to Create a Load Balancer
createOpts := loadbalancers.CreateOpts{
Name: "db_lb",
AdminStateUp: gophercloud.Enabled,
VipSubnetID: "9cedb85d-0759-4898-8a4b-fa5a5ea10086",
VipAddress: "10.30.176.48",
Flavor: "medium",
Provider: "haproxy",
}
lb, err := loadbalancers.Create(networkClient, createOpts).Extract()
if err != nil {
panic(err)
}
Example to Update a Load Balancer
lbID := "d67d56a6-4a86-4688-a282-f46444705c64"
i1001 := 1001
updateOpts := loadbalancers.UpdateOpts{
Name: "new-name",
}
lb, err := loadbalancers.Update(networkClient, lbID, updateOpts).Extract()
if err != nil {
panic(err)
}
Example to Delete a Load Balancers
lbID := "d67d56a6-4a86-4688-a282-f46444705c64"
err := loadbalancers.Delete(networkClient, lbID).ExtractErr()
if err != nil {
panic(err)
}
Example to Get the Status of a Load Balancer
lbID := "d67d56a6-4a86-4688-a282-f46444705c64"
status, err := loadbalancers.GetStatuses(networkClient, LBID).Extract()
if err != nil {
panic(err)
}
*/
package loadbalancers
...@@ -42,11 +42,11 @@ func (opts ListOpts) ToLoadBalancerListQuery() (string, error) { ...@@ -42,11 +42,11 @@ func (opts ListOpts) ToLoadBalancerListQuery() (string, error) {
} }
// List returns a Pager which allows you to iterate over a collection of // List returns a Pager which allows you to iterate over a collection of
// routers. It accepts a ListOpts struct, which allows you to filter and sort // load balancers. It accepts a ListOpts struct, which allows you to filter
// the returned collection for greater efficiency. // and sort the returned collection for greater efficiency.
// //
// Default policy settings return only those routers that are owned by the // Default policy settings return only those load balancers that are owned by
// tenant who submits the request, unless an admin user submits the request. // the tenant who submits the request, unless an admin user submits the request.
func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
url := rootURL(c) url := rootURL(c)
if opts != nil { if opts != nil {
...@@ -61,10 +61,8 @@ func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { ...@@ -61,10 +61,8 @@ func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
}) })
} }
// CreateOptsBuilder is the interface options structs have to satisfy in order // CreateOptsBuilder allows extensions to add additional parameters to the
// to be used in the main Create operation in this package. Since many // Create request.
// extensions decorate or modify the common logic, it is useful for them to
// satisfy a basic interface in order for them to be used.
type CreateOptsBuilder interface { type CreateOptsBuilder interface {
ToLoadBalancerCreateMap() (map[string]interface{}, error) ToLoadBalancerCreateMap() (map[string]interface{}, error)
} }
...@@ -72,29 +70,36 @@ type CreateOptsBuilder interface { ...@@ -72,29 +70,36 @@ type CreateOptsBuilder interface {
// CreateOpts is the common options struct used in this package's Create // CreateOpts is the common options struct used in this package's Create
// operation. // operation.
type CreateOpts struct { type CreateOpts struct {
// Optional. Human-readable name for the Loadbalancer. Does not have to be unique. // Human-readable name for the Loadbalancer. Does not have to be unique.
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
// Optional. Human-readable description for the Loadbalancer.
// Human-readable description for the Loadbalancer.
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
// Required. The network on which to allocate the Loadbalancer's address. A tenant can
// only create Loadbalancers on networks authorized by policy (e.g. networks that // The network on which to allocate the Loadbalancer's address. A tenant can
// belong to them or networks that are shared). // only create Loadbalancers on networks authorized by policy (e.g. networks
// that belong to them or networks that are shared).
VipSubnetID string `json:"vip_subnet_id" required:"true"` VipSubnetID string `json:"vip_subnet_id" required:"true"`
// Required for admins. The UUID of the tenant who owns the Loadbalancer.
// Only administrative users can specify a tenant UUID other than their own. // The UUID of the tenant who owns the Loadbalancer. Only administrative users
// can specify a tenant UUID other than their own.
TenantID string `json:"tenant_id,omitempty"` TenantID string `json:"tenant_id,omitempty"`
// Optional. The IP address of the Loadbalancer.
// The IP address of the Loadbalancer.
VipAddress string `json:"vip_address,omitempty"` VipAddress string `json:"vip_address,omitempty"`
// Optional. The administrative state of the Loadbalancer. A valid value is true (UP)
// The administrative state of the Loadbalancer. A valid value is true (UP)
// or false (DOWN). // or false (DOWN).
AdminStateUp *bool `json:"admin_state_up,omitempty"` AdminStateUp *bool `json:"admin_state_up,omitempty"`
// Optional. The UUID of a flavor.
// The UUID of a flavor.
Flavor string `json:"flavor,omitempty"` Flavor string `json:"flavor,omitempty"`
// Optional. The name of the provider.
// The name of the provider.
Provider string `json:"provider,omitempty"` Provider string `json:"provider,omitempty"`
} }
// ToLoadBalancerCreateMap casts a CreateOpts struct to a map. // ToLoadBalancerCreateMap builds a request body from CreateOpts.
func (opts CreateOpts) ToLoadBalancerCreateMap() (map[string]interface{}, error) { func (opts CreateOpts) ToLoadBalancerCreateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "loadbalancer") return gophercloud.BuildRequestBody(opts, "loadbalancer")
} }
...@@ -103,9 +108,6 @@ func (opts CreateOpts) ToLoadBalancerCreateMap() (map[string]interface{}, error) ...@@ -103,9 +108,6 @@ func (opts CreateOpts) ToLoadBalancerCreateMap() (map[string]interface{}, error)
// configuration defined in the CreateOpts struct. Once the request is // configuration defined in the CreateOpts struct. Once the request is
// validated and progress has started on the provisioning process, a // validated and progress has started on the provisioning process, a
// CreateResult will be returned. // CreateResult will be returned.
//
// Users with an admin role can create loadbalancers on behalf of other tenants by
// specifying a TenantID attribute different than their own.
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
b, err := opts.ToLoadBalancerCreateMap() b, err := opts.ToLoadBalancerCreateMap()
if err != nil { if err != nil {
...@@ -122,10 +124,8 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) { ...@@ -122,10 +124,8 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
return return
} }
// UpdateOptsBuilder is the interface options structs have to satisfy in order // UpdateOptsBuilder allows extensions to add additional parameters to the
// to be used in the main Update operation in this package. Since many // Update request.
// extensions decorate or modify the common logic, it is useful for them to
// satisfy a basic interface in order for them to be used.
type UpdateOptsBuilder interface { type UpdateOptsBuilder interface {
ToLoadBalancerUpdateMap() (map[string]interface{}, error) ToLoadBalancerUpdateMap() (map[string]interface{}, error)
} }
...@@ -133,21 +133,24 @@ type UpdateOptsBuilder interface { ...@@ -133,21 +133,24 @@ type UpdateOptsBuilder interface {
// UpdateOpts is the common options struct used in this package's Update // UpdateOpts is the common options struct used in this package's Update
// operation. // operation.
type UpdateOpts struct { type UpdateOpts struct {
// Optional. Human-readable name for the Loadbalancer. Does not have to be unique. // Human-readable name for the Loadbalancer. Does not have to be unique.
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
// Optional. Human-readable description for the Loadbalancer.
// Human-readable description for the Loadbalancer.
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
// Optional. The administrative state of the Loadbalancer. A valid value is true (UP)
// The administrative state of the Loadbalancer. A valid value is true (UP)
// or false (DOWN). // or false (DOWN).
AdminStateUp *bool `json:"admin_state_up,omitempty"` AdminStateUp *bool `json:"admin_state_up,omitempty"`
} }
// ToLoadBalancerUpdateMap casts a UpdateOpts struct to a map. // ToLoadBalancerUpdateMap builds a request body from UpdateOpts.
func (opts UpdateOpts) ToLoadBalancerUpdateMap() (map[string]interface{}, error) { func (opts UpdateOpts) ToLoadBalancerUpdateMap() (map[string]interface{}, error) {
return gophercloud.BuildRequestBody(opts, "loadbalancer") return gophercloud.BuildRequestBody(opts, "loadbalancer")
} }
// Update is an operation which modifies the attributes of the specified LoadBalancer. // Update is an operation which modifies the attributes of the specified
// LoadBalancer.
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) (r UpdateResult) { func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) (r UpdateResult) {
b, err := opts.ToLoadBalancerUpdateMap() b, err := opts.ToLoadBalancerUpdateMap()
if err != nil { if err != nil {
...@@ -160,12 +163,14 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) (r UpdateR ...@@ -160,12 +163,14 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) (r UpdateR
return return
} }
// Delete will permanently delete a particular LoadBalancer based on its unique ID. // Delete will permanently delete a particular LoadBalancer based on its
// unique ID.
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) { func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
_, r.Err = c.Delete(resourceURL(c, id), nil) _, r.Err = c.Delete(resourceURL(c, id), nil)
return return
} }
// GetStatuses will return the status of a particular LoadBalancer.
func GetStatuses(c *gophercloud.ServiceClient, id string) (r GetStatusesResult) { func GetStatuses(c *gophercloud.ServiceClient, id string) (r GetStatusesResult) {
_, r.Err = c.Get(statusRootURL(c, id), &r.Body, nil) _, r.Err = c.Get(statusRootURL(c, id), &r.Body, nil)
return return
......
...@@ -6,50 +6,67 @@ import ( ...@@ -6,50 +6,67 @@ import (
"github.com/gophercloud/gophercloud/pagination" "github.com/gophercloud/gophercloud/pagination"
) )
// LoadBalancer is the primary load balancing configuration object that specifies // LoadBalancer is the primary load balancing configuration object that
// the virtual IP address on which client traffic is received, as well // specifies the virtual IP address on which client traffic is received, as well
// as other details such as the load balancing method to be use, protocol, etc. // as other details such as the load balancing method to be use, protocol, etc.
type LoadBalancer struct { type LoadBalancer struct {
// Human-readable description for the Loadbalancer. // Human-readable description for the Loadbalancer.
Description string `json:"description"` Description string `json:"description"`
// The administrative state of the Loadbalancer. A valid value is true (UP) or false (DOWN).
// The administrative state of the Loadbalancer.
// A valid value is true (UP) or false (DOWN).
AdminStateUp bool `json:"admin_state_up"` AdminStateUp bool `json:"admin_state_up"`
// Owner of the LoadBalancer. Only an admin user can specify a tenant ID other than its own.
// Owner of the LoadBalancer.
TenantID string `json:"tenant_id"` TenantID string `json:"tenant_id"`
// The provisioning status of the LoadBalancer. This value is ACTIVE, PENDING_CREATE or ERROR.
// The provisioning status of the LoadBalancer.
// This value is ACTIVE, PENDING_CREATE or ERROR.
ProvisioningStatus string `json:"provisioning_status"` ProvisioningStatus string `json:"provisioning_status"`
// The IP address of the Loadbalancer. // The IP address of the Loadbalancer.
VipAddress string `json:"vip_address"` VipAddress string `json:"vip_address"`
// The UUID of the port associated with the IP address. // The UUID of the port associated with the IP address.
VipPortID string `json:"vip_port_id"` VipPortID string `json:"vip_port_id"`
// The UUID of the subnet on which to allocate the virtual IP for the Loadbalancer address.
// The UUID of the subnet on which to allocate the virtual IP for the
// Loadbalancer address.
VipSubnetID string `json:"vip_subnet_id"` VipSubnetID string `json:"vip_subnet_id"`
// The unique ID for the LoadBalancer. // The unique ID for the LoadBalancer.
ID string `json:"id"` ID string `json:"id"`
// The operating status of the LoadBalancer. This value is ONLINE or OFFLINE. // The operating status of the LoadBalancer. This value is ONLINE or OFFLINE.
OperatingStatus string `json:"operating_status"` OperatingStatus string `json:"operating_status"`
// Human-readable name for the LoadBalancer. Does not have to be unique. // Human-readable name for the LoadBalancer. Does not have to be unique.
Name string `json:"name"` Name string `json:"name"`
// The UUID of a flavor if set. // The UUID of a flavor if set.
Flavor string `json:"flavor"` Flavor string `json:"flavor"`
// The name of the provider. // The name of the provider.
Provider string `json:"provider"` Provider string `json:"provider"`
// Listeners are the listeners related to this Loadbalancer.
Listeners []listeners.Listener `json:"listeners"` Listeners []listeners.Listener `json:"listeners"`
} }
// StatusTree represents the status of a loadbalancer.
type StatusTree struct { type StatusTree struct {
Loadbalancer *LoadBalancer `json:"loadbalancer"` Loadbalancer *LoadBalancer `json:"loadbalancer"`
} }
// LoadBalancerPage is the page returned by a pager when traversing over a // LoadBalancerPage is the page returned by a pager when traversing over a
// collection of routers. // collection of load balancers.
type LoadBalancerPage struct { type LoadBalancerPage struct {
pagination.LinkedPageBase pagination.LinkedPageBase
} }
// NextPageURL is invoked when a paginated collection of routers has reached // NextPageURL is invoked when a paginated collection of load balancers has
// the end of a page and the pager seeks to traverse over a new one. In order // reached the end of a page and the pager seeks to traverse over a new one.
// to do this, it needs to construct the next page's URL. // In order to do this, it needs to construct the next page's URL.
func (r LoadBalancerPage) NextPageURL() (string, error) { func (r LoadBalancerPage) NextPageURL() (string, error) {
var s struct { var s struct {
Links []gophercloud.Link `json:"loadbalancers_links"` Links []gophercloud.Link `json:"loadbalancers_links"`
...@@ -67,9 +84,9 @@ func (p LoadBalancerPage) IsEmpty() (bool, error) { ...@@ -67,9 +84,9 @@ func (p LoadBalancerPage) IsEmpty() (bool, error) {
return len(is) == 0, err return len(is) == 0, err
} }
// ExtractLoadBalancers accepts a Page struct, specifically a LoadbalancerPage struct, // ExtractLoadBalancers accepts a Page struct, specifically a LoadbalancerPage
// and extracts the elements into a slice of LoadBalancer structs. In other words, // struct, and extracts the elements into a slice of LoadBalancer structs. In
// a generic collection is mapped into a relevant slice. // other words, a generic collection is mapped into a relevant slice.
func ExtractLoadBalancers(r pagination.Page) ([]LoadBalancer, error) { func ExtractLoadBalancers(r pagination.Page) ([]LoadBalancer, error) {
var s struct { var s struct {
LoadBalancers []LoadBalancer `json:"loadbalancers"` LoadBalancers []LoadBalancer `json:"loadbalancers"`
...@@ -82,7 +99,7 @@ type commonResult struct { ...@@ -82,7 +99,7 @@ type commonResult struct {
gophercloud.Result gophercloud.Result
} }
// Extract is a function that accepts a result and extracts a router. // Extract is a function that accepts a result and extracts a loadbalancer.
func (r commonResult) Extract() (*LoadBalancer, error) { func (r commonResult) Extract() (*LoadBalancer, error) {
var s struct { var s struct {
LoadBalancer *LoadBalancer `json:"loadbalancer"` LoadBalancer *LoadBalancer `json:"loadbalancer"`
...@@ -91,11 +108,14 @@ func (r commonResult) Extract() (*LoadBalancer, error) { ...@@ -91,11 +108,14 @@ func (r commonResult) Extract() (*LoadBalancer, error) {
return s.LoadBalancer, err return s.LoadBalancer, err
} }
// GetStatusesResult represents the result of a GetStatuses operation.
// Call its Extract method to interpret it as a StatusTree.
type GetStatusesResult struct { type GetStatusesResult struct {
gophercloud.Result gophercloud.Result
} }
// Extract is a function that accepts a result and extracts a Loadbalancer. // Extract is a function that accepts a result and extracts the status of
// a Loadbalancer.
func (r GetStatusesResult) Extract() (*StatusTree, error) { func (r GetStatusesResult) Extract() (*StatusTree, error) {
var s struct { var s struct {
Statuses *StatusTree `json:"statuses"` Statuses *StatusTree `json:"statuses"`
...@@ -104,22 +124,26 @@ func (r GetStatusesResult) Extract() (*StatusTree, error) { ...@@ -104,22 +124,26 @@ func (r GetStatusesResult) Extract() (*StatusTree, error) {
return s.Statuses, err return s.Statuses, err
} }
// CreateResult represents the result of a create operation. // CreateResult represents the result of a create operation. Call its Extract
// method to interpret it as a LoadBalancer.
type CreateResult struct { type CreateResult struct {
commonResult commonResult
} }
// GetResult represents the result of a get operation. // GetResult represents the result of a get operation. Call its Extract
// method to interpret it as a LoadBalancer.
type GetResult struct { type GetResult struct {
commonResult commonResult
} }
// UpdateResult represents the result of an update operation. // UpdateResult represents the result of an update operation. Call its Extract
// method to interpret it as a LoadBalancer.
type UpdateResult struct { type UpdateResult struct {
commonResult commonResult
} }
// DeleteResult represents the result of a delete operation. // DeleteResult represents the result of a delete operation. Call its
// ExtractErr method to determine if the request succeeded or failed.
type DeleteResult struct { type DeleteResult struct {
gophercloud.ErrResult gophercloud.ErrResult
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment