Merge pull request #10556 from zetaab/feature/updatedeps

update gophercloud dependency
This commit is contained in:
Kubernetes Prow Robot 2021-01-11 06:13:08 -08:00 committed by GitHub
commit f94539f6f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 703 additions and 238 deletions

4
go.mod
View File

@ -47,8 +47,6 @@ replace k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.20.0
// This should match hack/go.mod // This should match hack/go.mod
replace k8s.io/code-generator => k8s.io/code-generator v0.20.0 replace k8s.io/code-generator => k8s.io/code-generator v0.20.0
replace github.com/gophercloud/gophercloud => github.com/gophercloud/gophercloud v0.11.0
require ( require (
cloud.google.com/go v0.54.0 cloud.google.com/go v0.54.0
github.com/Azure/azure-pipeline-go v0.2.3 github.com/Azure/azure-pipeline-go v0.2.3
@ -75,7 +73,7 @@ require (
github.com/gogo/protobuf v1.3.1 github.com/gogo/protobuf v1.3.1
github.com/google/go-cmp v0.5.2 github.com/google/go-cmp v0.5.2
github.com/google/uuid v1.1.2 github.com/google/uuid v1.1.2
github.com/gophercloud/gophercloud v0.11.1-0.20200518183226-7aec46f32c19 github.com/gophercloud/gophercloud v0.15.0
github.com/gorilla/mux v1.7.3 github.com/gorilla/mux v1.7.3
github.com/hashicorp/hcl/v2 v2.7.0 github.com/hashicorp/hcl/v2 v2.7.0
github.com/hashicorp/vault/api v1.0.4 github.com/hashicorp/vault/api v1.0.4

12
go.sum
View File

@ -501,8 +501,12 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/gophercloud/gophercloud v0.11.0 h1:pYMP9UZBdQa3lsfIZ1tZor4EbtxiuB6BHhocenkiH/E= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gophercloud/gophercloud v0.11.0/go.mod h1:gmC5oQqMDOMO1t1gq5DquX/yAU808e/4mzjjDA76+Ss= github.com/gophercloud/gophercloud v0.6.1-0.20191122030953-d8ac278c1c9d/go.mod h1:ozGNgr9KYOVATV5jsgHl/ceCDXGuguqOZAzoQ/2vcNM=
github.com/gophercloud/gophercloud v0.11.1-0.20200518183226-7aec46f32c19 h1:Amaxs7PsvtzbahUHadno+OZI0IrMqwbPhoGUVLdM1NA=
github.com/gophercloud/gophercloud v0.11.1-0.20200518183226-7aec46f32c19/go.mod h1:gmC5oQqMDOMO1t1gq5DquX/yAU808e/4mzjjDA76+Ss=
github.com/gophercloud/gophercloud v0.15.0 h1:jQeAWj0s1p83+TrUXhJhEOK4oe2g6YcBcFwEyMNIjEk=
github.com/gophercloud/gophercloud v0.15.0/go.mod h1:VX0Ibx85B60B5XOrZr6kaNwrmPUzcmMpwxvQ1WQIIWM=
github.com/gophercloud/utils v0.0.0-20200423144003-7c72efc7435d/go.mod h1:ehWUbLQJPqS0Ep+CxeD559hsm9pthPXadJNKwZkp43w= github.com/gophercloud/utils v0.0.0-20200423144003-7c72efc7435d/go.mod h1:ehWUbLQJPqS0Ep+CxeD559hsm9pthPXadJNKwZkp43w=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@ -646,6 +650,8 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
@ -1043,6 +1049,7 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@ -1165,6 +1172,7 @@ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View File

@ -57,6 +57,7 @@ go_test(
"//vendor/github.com/aws/aws-sdk-go/service/autoscaling/autoscalingiface:go_default_library", "//vendor/github.com/aws/aws-sdk-go/service/autoscaling/autoscalingiface:go_default_library",
"//vendor/github.com/aws/aws-sdk-go/service/ec2:go_default_library", "//vendor/github.com/aws/aws-sdk-go/service/ec2:go_default_library",
"//vendor/github.com/aws/aws-sdk-go/service/ec2/ec2iface:go_default_library", "//vendor/github.com/aws/aws-sdk-go/service/ec2/ec2iface:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers:go_default_library", "//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports:go_default_library", "//vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/ports:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library",

View File

@ -22,14 +22,9 @@ import (
"testing" "testing"
"time" "time"
"k8s.io/kops/upup/pkg/fi" "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups"
"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
"k8s.io/kops/util/pkg/vfs"
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers" "github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
v1meta "k8s.io/apimachinery/pkg/apis/meta/v1" v1meta "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -39,8 +34,10 @@ import (
"k8s.io/kops/pkg/client/simple/vfsclientset" "k8s.io/kops/pkg/client/simple/vfsclientset"
"k8s.io/kops/pkg/cloudinstances" "k8s.io/kops/pkg/cloudinstances"
"k8s.io/kops/pkg/testutils" "k8s.io/kops/pkg/testutils"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup" "k8s.io/kops/upup/pkg/fi/cloudup"
"k8s.io/kops/upup/pkg/fi/cloudup/openstack" "k8s.io/kops/upup/pkg/fi/cloudup/openstack"
"k8s.io/kops/util/pkg/vfs"
) )
func getTestSetupOS(t *testing.T) (*RollingUpdateCluster, *openstack.MockCloud) { func getTestSetupOS(t *testing.T) (*RollingUpdateCluster, *openstack.MockCloud) {
@ -211,7 +208,7 @@ func getGroupsAllNeedUpdateOS(t *testing.T, c *RollingUpdateCluster) (map[string
func assertGroupInstanceCountOS(t *testing.T, cloud *openstack.MockCloud, groupName string, expected int) { func assertGroupInstanceCountOS(t *testing.T, cloud *openstack.MockCloud, groupName string, expected int) {
groups, _ := cloud.ListServerGroups() groups, _ := cloud.ListServerGroups(servergroups.ListOpts{})
for _, g := range groups { for _, g := range groups {
if g.Name == groupName { if g.Name == groupName {
assert.Lenf(t, g.Members, expected, "%s instances", groupName) assert.Lenf(t, g.Members, expected, "%s instances", groupName)

View File

@ -23,6 +23,7 @@ go_library(
"//upup/pkg/fi:go_default_library", "//upup/pkg/fi:go_default_library",
"//upup/pkg/fi/cloudup/openstack:go_default_library", "//upup/pkg/fi/cloudup/openstack:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes:go_default_library", "//vendor/github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers:go_default_library", "//vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/servers:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/openstack/dns/v2/recordsets:go_default_library", "//vendor/github.com/gophercloud/gophercloud/openstack/dns/v2/recordsets:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/openstack/dns/v2/zones:go_default_library", "//vendor/github.com/gophercloud/gophercloud/openstack/dns/v2/zones:go_default_library",

View File

@ -19,6 +19,7 @@ package openstack
import ( import (
"strings" "strings"
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups"
"k8s.io/kops/pkg/resources" "k8s.io/kops/pkg/resources"
"k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/openstack" "k8s.io/kops/upup/pkg/fi/cloudup/openstack"
@ -30,7 +31,7 @@ const (
func (os *clusterDiscoveryOS) ListServerGroups() ([]*resources.Resource, error) { func (os *clusterDiscoveryOS) ListServerGroups() ([]*resources.Resource, error) {
var resourceTrackers []*resources.Resource var resourceTrackers []*resources.Resource
servergroups, err := os.osCloud.ListServerGroups() servergroups, err := os.osCloud.ListServerGroups(servergroups.ListOpts{})
if err != nil { if err != nil {
return resourceTrackers, err return resourceTrackers, err
} }

View File

@ -235,7 +235,7 @@ type OpenstackCloud interface {
CreateServerGroup(opt servergroups.CreateOptsBuilder) (*servergroups.ServerGroup, error) CreateServerGroup(opt servergroups.CreateOptsBuilder) (*servergroups.ServerGroup, error)
// ListServerGroups will list available server groups // ListServerGroups will list available server groups
ListServerGroups() ([]servergroups.ServerGroup, error) ListServerGroups(opts servergroups.ListOptsBuilder) ([]servergroups.ServerGroup, error)
// DeleteServerGroup will delete a nova server group // DeleteServerGroup will delete a nova server group
DeleteServerGroup(groupID string) error DeleteServerGroup(groupID string) error
@ -617,7 +617,7 @@ func getCloudGroups(c OpenstackCloud, cluster *kops.Cluster, instancegroups []*k
nodeMap := cloudinstances.GetNodeMap(nodes, cluster) nodeMap := cloudinstances.GetNodeMap(nodes, cluster)
groups := make(map[string]*cloudinstances.CloudInstanceGroup) groups := make(map[string]*cloudinstances.CloudInstanceGroup)
serverGrps, err := c.ListServerGroups() serverGrps, err := c.ListServerGroups(servergroups.ListOpts{})
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to list servergroups: %v", err) return nil, fmt.Errorf("unable to list servergroups: %v", err)
} }

View File

@ -423,8 +423,8 @@ func (c *MockCloud) ListSecurityGroupRules(opt sgr.ListOpts) ([]sgr.SecGroupRule
func (c *MockCloud) ListServerFloatingIPs(instanceID string) ([]*string, error) { func (c *MockCloud) ListServerFloatingIPs(instanceID string) ([]*string, error) {
return listServerFloatingIPs(c, instanceID, true) return listServerFloatingIPs(c, instanceID, true)
} }
func (c *MockCloud) ListServerGroups() ([]servergroups.ServerGroup, error) { func (c *MockCloud) ListServerGroups(opts servergroups.ListOptsBuilder) ([]servergroups.ServerGroup, error) {
return listServerGroups(c) return listServerGroups(c, opts)
} }
func (c *MockCloud) ListSubnets(opt subnets.ListOptsBuilder) ([]subnets.Subnet, error) { func (c *MockCloud) ListSubnets(opt subnets.ListOptsBuilder) ([]subnets.Subnet, error) {
return listSubnets(c, opt) return listSubnets(c, opt)

View File

@ -55,14 +55,14 @@ func createServerGroup(c OpenstackCloud, opt servergroups.CreateOptsBuilder) (*s
} }
} }
func (c *openstackCloud) ListServerGroups() ([]servergroups.ServerGroup, error) { func (c *openstackCloud) ListServerGroups(opts servergroups.ListOptsBuilder) ([]servergroups.ServerGroup, error) {
return listServerGroups(c) return listServerGroups(c, opts)
} }
func listServerGroups(c OpenstackCloud) ([]servergroups.ServerGroup, error) { func listServerGroups(c OpenstackCloud, opts servergroups.ListOptsBuilder) ([]servergroups.ServerGroup, error) {
var sgs []servergroups.ServerGroup var sgs []servergroups.ServerGroup
done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) { done, err := vfs.RetryWithBackoff(readBackoff, func() (bool, error) {
allPages, err := servergroups.List(c.ComputeClient()).AllPages() allPages, err := servergroups.List(c.ComputeClient(), opts).AllPages()
if err != nil { if err != nil {
return false, fmt.Errorf("error listing server groups: %v", err) return false, fmt.Errorf("error listing server groups: %v", err)
} }

View File

@ -262,7 +262,6 @@ func (_ *Instance) RenderOpenstack(t *openstack.OpenstackAPITarget, a, e, change
}, },
}, },
Metadata: e.Metadata, Metadata: e.Metadata,
ServiceClient: t.Cloud.ComputeClient(),
SecurityGroups: e.SecurityGroups, SecurityGroups: e.SecurityGroups,
} }
if e.UserData != nil { if e.UserData != nil {

View File

@ -62,7 +62,7 @@ func (s *ServerGroup) Find(context *fi.Context) (*ServerGroup, error) {
cloud := context.Cloud.(openstack.OpenstackCloud) cloud := context.Cloud.(openstack.OpenstackCloud)
//TODO: move to cloud, add vfs backoff //TODO: move to cloud, add vfs backoff
page, err := servergroups.List(cloud.ComputeClient()).AllPages() page, err := servergroups.List(cloud.ComputeClient(), servergroups.ListOpts{}).AllPages()
if err != nil { if err != nil {
return nil, fmt.Errorf("Failed to list server groups: %v", err) return nil, fmt.Errorf("Failed to list server groups: %v", err)
} }

View File

@ -1,25 +0,0 @@
language: go
sudo: false
install:
- GO111MODULE=off go get golang.org/x/crypto/ssh
- GO111MODULE=off go get -v -tags 'fixtures acceptance' ./...
- GO111MODULE=off go get github.com/wadey/gocovmerge
- GO111MODULE=off go get github.com/mattn/goveralls
- GO111MODULE=off go get golang.org/x/tools/cmd/goimports
go:
- "1.11"
- "1.12"
- "1.13"
- "tip"
env:
global:
- secure: "xSQsAG5wlL9emjbCdxzz/hYQsSpJ/bABO1kkbwMSISVcJ3Nk0u4ywF+LS4bgeOnwPfmFvNTOqVDu3RwEvMeWXSI76t1piCPcObutb2faKLVD/hLoAS76gYX+Z8yGWGHrSB7Do5vTPj1ERe2UljdrnsSeOXzoDwFxYRaZLX4bBOB4AyoGvRniil5QXPATiA1tsWX1VMicj8a4F8X+xeESzjt1Q5Iy31e7vkptu71bhvXCaoo5QhYwT+pLR9dN0S1b7Ro0KVvkRefmr1lUOSYd2e74h6Lc34tC1h3uYZCS4h47t7v5cOXvMNxinEj2C51RvbjvZI1RLVdkuAEJD1Iz4+Ote46nXbZ//6XRZMZz/YxQ13l7ux1PFjgEB6HAapmF5Xd8PRsgeTU9LRJxpiTJ3P5QJ3leS1va8qnziM5kYipj/Rn+V8g2ad/rgkRox9LSiR9VYZD2Pe45YCb1mTKSl2aIJnV7nkOqsShY5LNB4JZSg7xIffA+9YVDktw8dJlATjZqt7WvJJ49g6A61mIUV4C15q2JPGKTkZzDiG81NtmS7hFa7k0yaE2ELgYocbcuyUcAahhxntYTC0i23nJmEHVNiZmBO3u7EgpWe4KGVfumU+lt12tIn5b3dZRBBUk3QakKKozSK1QPHGpk/AZGrhu7H6l8to6IICKWtDcyMPQ="
- GO111MODULE=on
before_script:
- go vet ./...
script:
- ./script/coverage
- ./script/unittest
- ./script/format
after_success:
- $HOME/gopath/bin/goveralls -service=travis-ci -coverprofile=cover.out

View File

@ -12,6 +12,7 @@
description: | description: |
Run gophercloud acceptance test on master branch Run gophercloud acceptance test on master branch
run: .zuul/playbooks/gophercloud-acceptance-test/run.yaml run: .zuul/playbooks/gophercloud-acceptance-test/run.yaml
timeout: 18000 # 5 hours
nodeset: ubuntu-bionic nodeset: ubuntu-bionic
- job: - job:
@ -22,6 +23,24 @@
run: .zuul/playbooks/gophercloud-acceptance-test-ironic/run.yaml run: .zuul/playbooks/gophercloud-acceptance-test-ironic/run.yaml
nodeset: ubuntu-bionic nodeset: ubuntu-bionic
- job:
name: gophercloud-acceptance-test-ussuri
parent: gophercloud-acceptance-test
description: |
Run gophercloud acceptance test on ussuri branch
vars:
global_env:
OS_BRANCH: stable/ussuri
- job:
name: gophercloud-acceptance-test-train
parent: gophercloud-acceptance-test
description: |
Run gophercloud acceptance test on train branch
vars:
global_env:
OS_BRANCH: stable/train
- job: - job:
name: gophercloud-acceptance-test-stein name: gophercloud-acceptance-test-stein
parent: gophercloud-acceptance-test parent: gophercloud-acceptance-test
@ -45,15 +64,19 @@
parent: gophercloud-acceptance-test parent: gophercloud-acceptance-test
description: | description: |
Run gophercloud acceptance test on queens branch Run gophercloud acceptance test on queens branch
nodeset: ubuntu-xenial
vars: vars:
global_env: global_env:
OS_BRANCH: stable/queens OS_BRANCH: stable/queens
# NOTE: A Pike-based devstack environment is currently
# not building correctly. This might be a temporary issue.
- job: - job:
name: gophercloud-acceptance-test-pike name: gophercloud-acceptance-test-pike
parent: gophercloud-acceptance-test parent: gophercloud-acceptance-test
description: | description: |
Run gophercloud acceptance test on pike branch Run gophercloud acceptance test on pike branch
nodeset: ubuntu-xenial
vars: vars:
global_env: global_env:
OS_BRANCH: stable/pike OS_BRANCH: stable/pike
@ -63,15 +86,19 @@
parent: gophercloud-acceptance-test parent: gophercloud-acceptance-test
description: | description: |
Run gophercloud acceptance test on ocata branch Run gophercloud acceptance test on ocata branch
nodeset: ubuntu-xenial
vars: vars:
global_env: global_env:
OS_BRANCH: stable/ocata OS_BRANCH: stable/ocata
# NOTE: A Newton-based devstack environment is currently
# not building correctly. This might be a temporary issue.
- job: - job:
name: gophercloud-acceptance-test-newton name: gophercloud-acceptance-test-newton
parent: gophercloud-acceptance-test parent: gophercloud-acceptance-test
description: | description: |
Run gophercloud acceptance test on newton branch Run gophercloud acceptance test on newton branch
nodeset: ubuntu-xenial
vars: vars:
global_env: global_env:
OS_BRANCH: stable/newton OS_BRANCH: stable/newton
@ -101,3 +128,9 @@
recheck-stein: recheck-stein:
jobs: jobs:
- gophercloud-acceptance-test-stein - gophercloud-acceptance-test-stein
recheck-train:
jobs:
- gophercloud-acceptance-test-train
recheck-ussuri:
jobs:
- gophercloud-acceptance-test-ussuri

View File

@ -1,4 +1,123 @@
## 0.12.0 (Unreleased) ## 0.16.0 (Unreleased)
## 0.15.0 (December 27, 2020)
BREAKING CHANGES
* `compute/v2/extensions/servergroups.List` now takes a `ListOpts` parameter. You can pass `nil` if you don't need to use this.
IMPROVEMENTS
* Added `loadbalancer/v2/pools.CreateMemberOpts.Tags` [GH-2056](https://github.com/gophercloud/gophercloud/pull/2056)
* Added `loadbalancer/v2/pools.UpdateMemberOpts.Backup` [GH-2056](https://github.com/gophercloud/gophercloud/pull/2056)
* Added `loadbalancer/v2/pools.UpdateMemberOpts.MonitorAddress` [GH-2056](https://github.com/gophercloud/gophercloud/pull/2056)
* Added `loadbalancer/v2/pools.UpdateMemberOpts.MonitorPort` [GH-2056](https://github.com/gophercloud/gophercloud/pull/2056)
* Added `loadbalancer/v2/pools.UpdateMemberOpts.Tags` [GH-2056](https://github.com/gophercloud/gophercloud/pull/2056)
* Added `loadbalancer/v2/pools.BatchUpdateMemberOpts.Backup` [GH-2056](https://github.com/gophercloud/gophercloud/pull/2056)
* Added `loadbalancer/v2/pools.BatchUpdateMemberOpts.MonitorAddress` [GH-2056](https://github.com/gophercloud/gophercloud/pull/2056)
* Added `loadbalancer/v2/pools.BatchUpdateMemberOpts.MonitorPort` [GH-2056](https://github.com/gophercloud/gophercloud/pull/2056)
* Added `loadbalancer/v2/pools.BatchUpdateMemberOpts.Tags` [GH-2056](https://github.com/gophercloud/gophercloud/pull/2056)
* Added `networking/v2/extensions/quotas.GetDetail` [GH-2061](https://github.com/gophercloud/gophercloud/pull/2061)
* Added `networking/v2/extensions/quotas.UpdateOpts.Trunk` [GH-2061](https://github.com/gophercloud/gophercloud/pull/2061)
* Added `objectstorage/v1/accounts.UpdateOpts.RemoveMetadata` [GH-2063](https://github.com/gophercloud/gophercloud/pull/2063)
* Added `objectstorage/v1/objects.UpdateOpts.RemoveMetadata` [GH-2063](https://github.com/gophercloud/gophercloud/pull/2063)
* Added `identity/v3/catalog.List` [GH-2067](https://github.com/gophercloud/gophercloud/pull/2067)
* Added `networking/v2/extensions/fwaas_v2/policies.List` [GH-2057](https://github.com/gophercloud/gophercloud/pull/2057)
* Added `networking/v2/extensions/fwaas_v2/policies.Create` [GH-2057](https://github.com/gophercloud/gophercloud/pull/2057)
* Added `networking/v2/extensions/fwaas_v2/policies.Get` [GH-2057](https://github.com/gophercloud/gophercloud/pull/2057)
* Added `networking/v2/extensions/fwaas_v2/policies.Update` [GH-2057](https://github.com/gophercloud/gophercloud/pull/2057)
* Added `networking/v2/extensions/fwaas_v2/policies.Delete` [GH-2057](https://github.com/gophercloud/gophercloud/pull/2057)
* Added `compute/v2/extensions/servergroups.ListOpts.AllProjects` [GH-2070](https://github.com/gophercloud/gophercloud/pull/2070)
* Added `objectstorage/v1/containers.CreateOpts.StoragePolicy` [GH-2075](https://github.com/gophercloud/gophercloud/pull/2075)
* Added `blockstorage/v3/snapshots.Update` [GH-2081](https://github.com/gophercloud/gophercloud/pull/2081)
* Added `loadbalancer/v2/l7policies.CreateOpts.Rules` [GH-2077](https://github.com/gophercloud/gophercloud/pull/2077)
* Added `loadbalancer/v2/listeners.CreateOpts.DefaultPool` [GH-2077](https://github.com/gophercloud/gophercloud/pull/2077)
* Added `loadbalancer/v2/listeners.CreateOpts.L7Policies` [GH-2077](https://github.com/gophercloud/gophercloud/pull/2077)
* Added `loadbalancer/v2/listeners.Listener.DefaultPool` [GH-2077](https://github.com/gophercloud/gophercloud/pull/2077)
* Added `loadbalancer/v2/loadbalancers.CreateOpts.Listeners` [GH-2077](https://github.com/gophercloud/gophercloud/pull/2077)
* Added `loadbalancer/v2/loadbalancers.CreateOpts.Pools` [GH-2077](https://github.com/gophercloud/gophercloud/pull/2077)
* Added `loadbalancer/v2/pools.CreateOpts.Members` [GH-2077](https://github.com/gophercloud/gophercloud/pull/2077)
* Added `loadbalancer/v2/pools.CreateOpts.Monitor` [GH-2077](https://github.com/gophercloud/gophercloud/pull/2077)
## 0.14.0 (November 11, 2020)
IMPROVEMENTS
* Added `identity/v3/endpoints.Endpoint.Enabled` [GH-2030](https://github.com/gophercloud/gophercloud/pull/2030)
* Added `containerinfra/v1/clusters.Upgrade` [GH-2032](https://github.com/gophercloud/gophercloud/pull/2032)
* Added `compute/apiversions.List` [GH-2037](https://github.com/gophercloud/gophercloud/pull/2037)
* Added `compute/apiversions.Get` [GH-2037](https://github.com/gophercloud/gophercloud/pull/2037)
* Added `compute/v2/servers.ListOpts.IP` [GH-2038](https://github.com/gophercloud/gophercloud/pull/2038)
* Added `compute/v2/servers.ListOpts.IP6` [GH-2038](https://github.com/gophercloud/gophercloud/pull/2038)
* Added `compute/v2/servers.ListOpts.UserID` [GH-2038](https://github.com/gophercloud/gophercloud/pull/2038)
* Added `dns/v2/transfer/accept.List` [GH-2041](https://github.com/gophercloud/gophercloud/pull/2041)
* Added `dns/v2/transfer/accept.Get` [GH-2041](https://github.com/gophercloud/gophercloud/pull/2041)
* Added `dns/v2/transfer/accept.Create` [GH-2041](https://github.com/gophercloud/gophercloud/pull/2041)
* Added `dns/v2/transfer/requests.List` [GH-2041](https://github.com/gophercloud/gophercloud/pull/2041)
* Added `dns/v2/transfer/requests.Get` [GH-2041](https://github.com/gophercloud/gophercloud/pull/2041)
* Added `dns/v2/transfer/requests.Update` [GH-2041](https://github.com/gophercloud/gophercloud/pull/2041)
* Added `dns/v2/transfer/requests.Delete` [GH-2041](https://github.com/gophercloud/gophercloud/pull/2041)
* Added `baremetal/v1/nodes.RescueWait` [GH-2052](https://github.com/gophercloud/gophercloud/pull/2052)
* Added `baremetal/v1/nodes.Unrescuing` [GH-2052](https://github.com/gophercloud/gophercloud/pull/2052)
* Added `networking/v2/extensions/fwaas_v2/groups.List` [GH-2050](https://github.com/gophercloud/gophercloud/pull/2050)
* Added `networking/v2/extensions/fwaas_v2/groups.Get` [GH-2050](https://github.com/gophercloud/gophercloud/pull/2050)
* Added `networking/v2/extensions/fwaas_v2/groups.Create` [GH-2050](https://github.com/gophercloud/gophercloud/pull/2050)
* Added `networking/v2/extensions/fwaas_v2/groups.Update` [GH-2050](https://github.com/gophercloud/gophercloud/pull/2050)
* Added `networking/v2/extensions/fwaas_v2/groups.Delete` [GH-2050](https://github.com/gophercloud/gophercloud/pull/2050)
BUG FIXES
* Changed `networking/v2/extensions/layer3/routers.Routes` from `[]Route` to `*[]Route` [GH-2043](https://github.com/gophercloud/gophercloud/pull/2043)
## 0.13.0 (September 27, 2020)
IMPROVEMENTS
* Added `ProtocolTerminatedHTTPS` as a valid listener protocol to `loadbalancer/v2/listeners` [GH-1992](https://github.com/gophercloud/gophercloud/pull/1992)
* Added `objectstorage/v1/objects.CreateTempURLOpts.Timestamp` [GH-1994](https://github.com/gophercloud/gophercloud/pull/1994)
* Added `compute/v2/extensions/schedulerhints.SchedulerHints.DifferentCell` [GH-2012](https://github.com/gophercloud/gophercloud/pull/2012)
* Added `loadbalancer/v2/quotas.Get` [GH-2010](https://github.com/gophercloud/gophercloud/pull/2010)
* Added `messaging/v2/queues.CreateOpts.EnableEncryptMessages` [GH-2016](https://github.com/gophercloud/gophercloud/pull/2016)
* Added `messaging/v2/queues.ListOpts.Name` [GH-2018](https://github.com/gophercloud/gophercloud/pull/2018)
* Added `messaging/v2/queues.ListOpts.WithCount` [GH-2018](https://github.com/gophercloud/gophercloud/pull/2018)
* Added `loadbalancer/v2/quotas.Update` [GH-2023](https://github.com/gophercloud/gophercloud/pull/2023)
* Added `loadbalancer/v2/loadbalancers.ListOpts.AvailabilityZone` [GH-2026](https://github.com/gophercloud/gophercloud/pull/2026)
* Added `loadbalancer/v2/loadbalancers.CreateOpts.AvailabilityZone` [GH-2026](https://github.com/gophercloud/gophercloud/pull/2026)
* Added `loadbalancer/v2/loadbalancers.LoadBalancer.AvailabilityZone` [GH-2026](https://github.com/gophercloud/gophercloud/pull/2026)
* Added `networking/v2/extensions/layer3/routers.ListL3Agents` [GH-2025](https://github.com/gophercloud/gophercloud/pull/2025)
BUG FIXES
* Fixed URL escaping in `objectstorage/v1/objects.CreateTempURL` [GH-1994](https://github.com/gophercloud/gophercloud/pull/1994)
* Remove unused `ServiceClient` from `compute/v2/servers.CreateOpts` [GH-2004](https://github.com/gophercloud/gophercloud/pull/2004)
* Changed `objectstorage/v1/objects.CreateOpts.DeleteAfter` from `int` to `int64` [GH-2014](https://github.com/gophercloud/gophercloud/pull/2014)
* Changed `objectstorage/v1/objects.CreateOpts.DeleteAt` from `int` to `int64` [GH-2014](https://github.com/gophercloud/gophercloud/pull/2014)
* Changed `objectstorage/v1/objects.UpdateOpts.DeleteAfter` from `int` to `int64` [GH-2014](https://github.com/gophercloud/gophercloud/pull/2014)
* Changed `objectstorage/v1/objects.UpdateOpts.DeleteAt` from `int` to `int64` [GH-2014](https://github.com/gophercloud/gophercloud/pull/2014)
## 0.12.0 (June 25, 2020)
UPGRADE NOTES
* The URL used in the `compute/v2/extensions/bootfromvolume` package has been changed from `os-volumes_boot` to `servers`.
IMPROVEMENTS
* The URL used in the `compute/v2/extensions/bootfromvolume` package has been changed from `os-volumes_boot` to `servers` [GH-1973](https://github.com/gophercloud/gophercloud/pull/1973)
* Modify `baremetal/v1/nodes.LogicalDisk.PhysicalDisks` type to support physical disks hints [GH-1982](https://github.com/gophercloud/gophercloud/pull/1982)
* Added `baremetalintrospection/httpbasic` which provides an HTTP Basic Auth client [GH-1986](https://github.com/gophercloud/gophercloud/pull/1986)
* Added `baremetal/httpbasic` which provides an HTTP Basic Auth client [GH-1983](https://github.com/gophercloud/gophercloud/pull/1983)
* Added `containerinfra/v1/clusters.CreateOpts.MergeLabels` [GH-1985](https://github.com/gophercloud/gophercloud/pull/1985)
BUG FIXES
* Changed `containerinfra/v1/clusters.Cluster.HealthStatusReason` from `string` to `map[string]interface{}` [GH-1968](https://github.com/gophercloud/gophercloud/pull/1968)
* Fixed marshalling of `blockstorage/extensions/backups.ImportBackup.Metadata` [GH-1967](https://github.com/gophercloud/gophercloud/pull/1967)
* Fixed typo of "OAUth" to "OAuth" in `identity/v3/extensions/oauth1` [GH-1969](https://github.com/gophercloud/gophercloud/pull/1969)
* Fixed goroutine leak during reauthentication [GH-1978](https://github.com/gophercloud/gophercloud/pull/1978)
* Changed `baremetalintrospection/v1/introspection.RootDiskType.Size` from `int` to `int64` [GH-1988](https://github.com/gophercloud/gophercloud/pull/1988)
## 0.11.0 (May 14, 2020) ## 0.11.0 (May 14, 2020)
@ -176,7 +295,7 @@ IMPROVEMENTS
* Added `MonitorAddress` to `loadbalancer/v2/pools.CreateMemberOpts` [GH-1824](https://github.com/gophercloud/gophercloud/pull/1824) * Added `MonitorAddress` to `loadbalancer/v2/pools.CreateMemberOpts` [GH-1824](https://github.com/gophercloud/gophercloud/pull/1824)
* Added `MonitorPort` to `loadbalancer/v2/pools.CreateMemberOpts` [GH-1824](https://github.com/gophercloud/gophercloud/pull/1824) * Added `MonitorPort` to `loadbalancer/v2/pools.CreateMemberOpts` [GH-1824](https://github.com/gophercloud/gophercloud/pull/1824)
* Changed `Impersonation` to a non-required field in `identity/v3/extensions/trusts.CreateOpts` [GH-1818](https://github.com/gophercloud/gophercloud/pull/1818) * Changed `Impersonation` to a non-required field in `identity/v3/extensions/trusts.CreateOpts` [GH-1818](https://github.com/gophercloud/gophercloud/pull/1818)
* Added `InsertHeaders` to `loadbalancer/v2/listeners.UpdateOpts` [GH-1835] * Added `InsertHeaders` to `loadbalancer/v2/listeners.UpdateOpts` [GH-1835](https://github.com/gophercloud/gophercloud/pull/1835)
* Added `NUMATopology` to `baremetalintrospection/v1/introspection.Data` [GH-1842](https://github.com/gophercloud/gophercloud/pull/1842) * Added `NUMATopology` to `baremetalintrospection/v1/introspection.Data` [GH-1842](https://github.com/gophercloud/gophercloud/pull/1842)
* Added `placement/v1/resourceproviders.Create` [GH-1841](https://github.com/gophercloud/gophercloud/pull/1841) * Added `placement/v1/resourceproviders.Create` [GH-1841](https://github.com/gophercloud/gophercloud/pull/1841)
* Added `blockstorage/extensions/volumeactions.UploadImageOpts.Visibility` [GH-1873](https://github.com/gophercloud/gophercloud/pull/1873) * Added `blockstorage/extensions/volumeactions.UploadImageOpts.Visibility` [GH-1873](https://github.com/gophercloud/gophercloud/pull/1873)

View File

@ -60,6 +60,13 @@ prompted for your password.
### Authentication ### Authentication
> NOTE: It is now recommended to use the `clientconfig` package found at
> https://github.com/gophercloud/utils/tree/master/openstack/clientconfig
> for all authentication purposes.
>
> The below documentation is still relevant. clientconfig simply implements
> the below and presents it in an easier and more flexible way.
Once you have access to your credentials, you can begin plugging them into Once you have access to your credentials, you can begin plugging them into
Gophercloud. The next step is authentication, and this is handled by a base Gophercloud. The next step is authentication, and this is handled by a base
"Provider" struct. To get one, you can either pass in your credentials "Provider" struct. To get one, you can either pass in your credentials

View File

@ -1,13 +1,11 @@
module github.com/gophercloud/gophercloud module github.com/gophercloud/gophercloud
go 1.13
require ( require (
github.com/kr/pretty v0.2.1 // indirect
golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 // indirect
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 // indirect golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 // indirect
golang.org/x/text v0.3.2 // indirect
golang.org/x/tools v0.0.0-20191203134012-c197fd4bf371 // indirect
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v2 v2.2.7 gopkg.in/yaml.v2 v2.3.0
) )

View File

@ -1,26 +1,19 @@
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e h1:egKlR8l7Nu9vHGWbcUV8lqR4987UfUbBd7GbhqGzNYU= golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e h1:egKlR8l7Nu9vHGWbcUV8lqR4987UfUbBd7GbhqGzNYU=
golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU=
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191203134012-c197fd4bf371/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -1,12 +0,0 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"pkg.go",
"util.go",
],
importmap = "k8s.io/kops/vendor/github.com/gophercloud/gophercloud/internal",
importpath = "github.com/gophercloud/gophercloud/internal",
visibility = ["//vendor/github.com/gophercloud/gophercloud:__subpackages__"],
)

View File

@ -1 +0,0 @@
package internal

View File

@ -1,34 +0,0 @@
package internal
import (
"reflect"
"strings"
)
// RemainingKeys will inspect a struct and compare it to a map. Any struct
// field that does not have a JSON tag that matches a key in the map or
// a matching lower-case field in the map will be returned as an extra.
//
// This is useful for determining the extra fields returned in response bodies
// for resources that can contain an arbitrary or dynamic number of fields.
func RemainingKeys(s interface{}, m map[string]interface{}) (extras map[string]interface{}) {
extras = make(map[string]interface{})
for k, v := range m {
extras[k] = v
}
valueOf := reflect.ValueOf(s)
typeOf := reflect.TypeOf(s)
for i := 0; i < valueOf.NumField(); i++ {
field := typeOf.Field(i)
lowerField := strings.ToLower(field.Name)
delete(extras, lowerField)
if tagValue := field.Tag.Get("json"); tagValue != "" && tagValue != "-" {
delete(extras, tagValue)
}
}
return
}

View File

@ -3,5 +3,5 @@ package bootfromvolume
import "github.com/gophercloud/gophercloud" import "github.com/gophercloud/gophercloud"
func createURL(c *gophercloud.ServiceClient) string { func createURL(c *gophercloud.ServiceClient) string {
return c.ServiceURL("os-volumes_boot") return c.ServiceURL("servers")
} }

View File

@ -31,6 +31,9 @@ type SchedulerHints struct {
// TargetCell specifies a cell name where the instance will be placed. // TargetCell specifies a cell name where the instance will be placed.
TargetCell string `json:"target_cell,omitempty"` TargetCell string `json:"target_cell,omitempty"`
// DifferentCell specifies cells names where an instance should not be placed.
DifferentCell []string `json:"different_cell,omitempty"`
// BuildNearHostIP specifies a subnet of compute nodes to host the instance. // BuildNearHostIP specifies a subnet of compute nodes to host the instance.
BuildNearHostIP string BuildNearHostIP string
@ -124,6 +127,10 @@ func (opts SchedulerHints) ToServerSchedulerHintsCreateMap() (map[string]interfa
sh["target_cell"] = opts.TargetCell sh["target_cell"] = opts.TargetCell
} }
if len(opts.DifferentCell) > 0 {
sh["different_cell"] = opts.DifferentCell
}
if opts.BuildNearHostIP != "" { if opts.BuildNearHostIP != "" {
if _, _, err := net.ParseCIDR(opts.BuildNearHostIP); err != nil { if _, _, err := net.ParseCIDR(opts.BuildNearHostIP); err != nil {
err := gophercloud.ErrInvalidInput{} err := gophercloud.ErrInvalidInput{}

View File

@ -5,10 +5,34 @@ import (
"github.com/gophercloud/gophercloud/pagination" "github.com/gophercloud/gophercloud/pagination"
) )
type ListOptsBuilder interface {
ToServerListQuery() (string, error)
}
type ListOpts struct {
// AllProjects is a bool to show all projects.
AllProjects bool `q:"all_projects"`
}
// ToServerListQuery formats a ListOpts into a query string.
func (opts ListOpts) ToServerListQuery() (string, error) {
q, err := gophercloud.BuildQueryString(opts)
return q.String(), err
}
// List returns a Pager that allows you to iterate over a collection of // List returns a Pager that allows you to iterate over a collection of
// ServerGroups. // ServerGroups.
func List(client *gophercloud.ServiceClient) pagination.Pager { func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page { url := listURL(client)
if opts != nil {
query, err := opts.ToServerListQuery()
if err != nil {
return pagination.Pager{Err: err}
}
url += query
}
return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
return ServerGroupPage{pagination.SinglePageBase(r)} return ServerGroupPage{pagination.SinglePageBase(r)}
}) })
} }

View File

@ -29,6 +29,14 @@ type ListOpts struct {
// Flavor is the name of the flavor in URL format. // Flavor is the name of the flavor in URL format.
Flavor string `q:"flavor"` Flavor string `q:"flavor"`
// IP is a regular expression to match the IPv4 address of the server.
IP string `q:"ip"`
// This requires the client to be set to microversion 2.5 or later, unless
// the user is an admin.
// IP is a regular expression to match the IPv6 address of the server.
IP6 string `q:"ip6"`
// Name of the server as a string; can be queried with regular expressions. // Name of the server as a string; can be queried with regular expressions.
// Realize that ?name=bob returns both bob and bobb. If you need to match bob // Realize that ?name=bob returns both bob and bobb. If you need to match bob
// only, you can use a regular expression matching the syntax of the // only, you can use a regular expression matching the syntax of the
@ -55,6 +63,11 @@ type ListOpts struct {
// Setting "AllTenants = true" is required. // Setting "AllTenants = true" is required.
TenantID string `q:"tenant_id"` TenantID string `q:"tenant_id"`
// This requires the client to be set to microversion 2.83 or later, unless
// the user is an admin.
// UserID lists servers for a particular user.
UserID string `q:"user_id"`
// This requires the client to be set to microversion 2.26 or later. // This requires the client to be set to microversion 2.26 or later.
// Tags filters on specific server tags. All tags must be present for the server. // Tags filters on specific server tags. All tags must be present for the server.
Tags string `q:"tags"` Tags string `q:"tags"`
@ -199,10 +212,6 @@ type CreateOpts struct {
// Max specifies Maximum number of servers to launch. // Max specifies Maximum number of servers to launch.
Max int `json:"max_count,omitempty"` Max int `json:"max_count,omitempty"`
// ServiceClient will allow calls to be made to retrieve an image or
// flavor ID by name.
ServiceClient *gophercloud.ServiceClient `json:"-"`
// Tags allows a server to be tagged with single-word metadata. // Tags allows a server to be tagged with single-word metadata.
// Requires microversion 2.52 or later. // Requires microversion 2.52 or later.
Tags []string `json:"tags,omitempty"` Tags []string `json:"tags,omitempty"`
@ -211,7 +220,6 @@ type CreateOpts struct {
// ToServerCreateMap assembles a request body based on the contents of a // ToServerCreateMap assembles a request body based on the contents of a
// CreateOpts. // CreateOpts.
func (opts CreateOpts) ToServerCreateMap() (map[string]interface{}, error) { func (opts CreateOpts) ToServerCreateMap() (map[string]interface{}, error) {
opts.ServiceClient = nil
b, err := gophercloud.BuildRequestBody(opts, "") b, err := gophercloud.BuildRequestBody(opts, "")
if err != nil { if err != nil {
return nil, err return nil, err
@ -447,10 +455,6 @@ type RebuildOpts struct {
// Personality [optional] includes files to inject into the server at launch. // Personality [optional] includes files to inject into the server at launch.
// Rebuild will base64-encode file contents for you. // Rebuild will base64-encode file contents for you.
Personality Personality `json:"personality,omitempty"` Personality Personality `json:"personality,omitempty"`
// ServiceClient will allow calls to be made to retrieve an image or
// flavor ID by name.
ServiceClient *gophercloud.ServiceClient `json:"-"`
} }
// ToServerRebuildMap formats a RebuildOpts struct into a map for use in JSON // ToServerRebuildMap formats a RebuildOpts struct into a map for use in JSON

View File

@ -8,7 +8,7 @@ for more information.
Example to List Tenants Example to List Tenants
listOpts := tenants.ListOpts{ listOpts := &tenants.ListOpts{
Limit: 2, Limit: 2,
} }

View File

@ -96,8 +96,8 @@ type Token struct {
OAuthToken string `q:"oauth_token"` OAuthToken string `q:"oauth_token"`
// OAuthTokenSecret is the secret value associated with the OAuth Token. // OAuthTokenSecret is the secret value associated with the OAuth Token.
OAuthTokenSecret string `q:"oauth_token_secret"` OAuthTokenSecret string `q:"oauth_token_secret"`
// OAUthExpiresAt is the date and time when an OAuth token expires. // OAuthExpiresAt is the date and time when an OAuth token expires.
OAUthExpiresAt *time.Time `q:"-"` OAuthExpiresAt *time.Time `q:"-"`
} }
// TokenResult is a struct to handle // TokenResult is a struct to handle
@ -127,7 +127,7 @@ func (r TokenResult) Extract() (*Token, error) {
if t, err := time.Parse(gophercloud.RFC3339Milli, v); err != nil { if t, err := time.Parse(gophercloud.RFC3339Milli, v); err != nil {
return nil, err return nil, err
} else { } else {
token.OAUthExpiresAt = &t token.OAuthExpiresAt = &t
} }
} }

View File

@ -14,7 +14,6 @@ go_library(
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
"//vendor/github.com/gophercloud/gophercloud:go_default_library", "//vendor/github.com/gophercloud/gophercloud:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/internal:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/openstack/utils:go_default_library", "//vendor/github.com/gophercloud/gophercloud/openstack/utils:go_default_library",
"//vendor/github.com/gophercloud/gophercloud/pagination:go_default_library", "//vendor/github.com/gophercloud/gophercloud/pagination:go_default_library",
], ],

View File

@ -8,7 +8,6 @@ import (
"time" "time"
"github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/internal"
"github.com/gophercloud/gophercloud/pagination" "github.com/gophercloud/gophercloud/pagination"
) )
@ -132,7 +131,7 @@ func (r *Image) UnmarshalJSON(b []byte) error {
delete(resultMap, "size") delete(resultMap, "size")
delete(resultMap, "openstack-image-import-methods") delete(resultMap, "openstack-image-import-methods")
delete(resultMap, "openstack-image-store-ids") delete(resultMap, "openstack-image-store-ids")
r.Properties = internal.RemainingKeys(Image{}, resultMap) r.Properties = gophercloud.RemainingKeys(Image{}, resultMap)
} }
if v := strings.FieldsFunc(strings.TrimSpace(s.OpenStackImageImportMethods), splitFunc); len(v) > 0 { if v := strings.FieldsFunc(strings.TrimSpace(s.OpenStackImageImportMethods), splitFunc); len(v) > 0 {

View File

@ -40,7 +40,7 @@ type CreateOpts struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
// The ID of the listener. // The ID of the listener.
ListenerID string `json:"listener_id" required:"true"` ListenerID string `json:"listener_id,omitempty"`
// The L7 policy action. One of REDIRECT_TO_POOL, REDIRECT_TO_URL, or REJECT. // The L7 policy action. One of REDIRECT_TO_POOL, REDIRECT_TO_URL, or REJECT.
Action Action `json:"action" required:"true"` Action Action `json:"action" required:"true"`
@ -66,6 +66,13 @@ type CreateOpts struct {
// 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"`
// Rules is a slice of CreateRuleOpts which allows a set of rules
// to be created at the same time the policy is created.
//
// This is only possible to use when creating a fully populated
// Loadbalancer.
Rules []CreateRuleOpts `json:"rules,omitempty" xor:"ListenerID"`
} }
// ToL7PolicyCreateMap builds a request body from CreateOpts. // ToL7PolicyCreateMap builds a request body from CreateOpts.

View File

@ -2,6 +2,8 @@ package listeners
import ( import (
"github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/l7policies"
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/pools"
"github.com/gophercloud/gophercloud/pagination" "github.com/gophercloud/gophercloud/pagination"
) )
@ -10,11 +12,12 @@ type Protocol string
// Supported attributes for create/update operations. // Supported attributes for create/update operations.
const ( const (
ProtocolTCP Protocol = "TCP" ProtocolTCP Protocol = "TCP"
ProtocolUDP Protocol = "UDP" ProtocolUDP Protocol = "UDP"
ProtocolPROXY Protocol = "PROXY" ProtocolPROXY Protocol = "PROXY"
ProtocolHTTP Protocol = "HTTP" ProtocolHTTP Protocol = "HTTP"
ProtocolHTTPS Protocol = "HTTPS" ProtocolHTTPS Protocol = "HTTPS"
ProtocolTerminatedHTTPS Protocol = "TERMINATED_HTTPS"
) )
// ListOptsBuilder allows extensions to add additional parameters to the // ListOptsBuilder allows extensions to add additional parameters to the
@ -83,9 +86,9 @@ type CreateOptsBuilder interface {
// CreateOpts represents options for creating a listener. // CreateOpts represents options for creating a listener.
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,omitempty"`
// The protocol - can either be TCP, HTTP or HTTPS. // The protocol - can either be TCP, HTTP, HTTPS or TERMINATED_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.
@ -101,6 +104,13 @@ type CreateOpts struct {
// 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"`
// DefaultPool an instance of pools.CreateOpts which allows a
// (default) pool to be created at the same time the listener is created.
//
// This is only possible to use when creating a fully populated
// load balancer.
DefaultPool *pools.CreateOpts `json:"default_pool,omitempty" xor:"LoadbalancerID"`
// Human-readable description for the Listener. // Human-readable description for the Listener.
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
@ -117,6 +127,13 @@ type CreateOpts struct {
// or false (DOWN). // or false (DOWN).
AdminStateUp *bool `json:"admin_state_up,omitempty"` AdminStateUp *bool `json:"admin_state_up,omitempty"`
// L7Policies is a slice of l7policies.CreateOpts which allows a set
// of policies to be created at the same time the listener is created.
//
// This is only possible to use when creating a fully populated
// Loadbalancer.
L7Policies []l7policies.CreateOpts `json:"l7policies,omitempty" xor:"LoadbalancerID"`
// Frontend client inactivity timeout in milliseconds // Frontend client inactivity timeout in milliseconds
TimeoutClientData *int `json:"timeout_client_data,omitempty"` TimeoutClientData *int `json:"timeout_client_data,omitempty"`

View File

@ -37,6 +37,9 @@ type Listener struct {
// 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"`
// The default pool with which the Listener is associated.
DefaultPool *pools.Pool `json:"default_pool"`
// A list of load balancer IDs. // A list of load balancer IDs.
Loadbalancers []LoadBalancerID `json:"loadbalancers"` Loadbalancers []LoadBalancerID `json:"loadbalancers"`

View File

@ -39,6 +39,54 @@ Example to Create a Load Balancer
panic(err) panic(err)
} }
Example to Create a fully populated Load Balancer
createOpts := loadbalancers.CreateOpts{
Name: "db_lb",
AdminStateUp: gophercloud.Enabled,
VipSubnetID: "9cedb85d-0759-4898-8a4b-fa5a5ea10086",
VipAddress: "10.30.176.48",
FlavorID: "60df399a-ee85-11e9-81b4-2a2ae2dbcce4",
Provider: "haproxy",
Tags: []string{"test", "stage"},
Listeners: []listeners.CreateOpts{{
Protocol: "HTTP",
ProtocolPort: 8080,
Name: "redirect_listener",
L7Policies: []l7policies.CreateOpts{{
Name: "redirect-example.com",
Action: l7policies.ActionRedirectToURL,
RedirectURL: "http://www.example.com",
Rules: []l7policies.CreateRuleOpts{{
RuleType: l7policies.TypePath,
CompareType: l7policies.CompareTypeRegex,
Value: "/images*",
}},
}},
DefaultPool: &pools.CreateOpts{
LBMethod: pools.LBMethodRoundRobin,
Protocol: "HTTP",
Name: "example pool",
Members: []pools.BatchUpdateMemberOpts{{
Address: "192.0.2.51",
ProtocolPort: 80,
},},
Monitor: &monitors.CreateOpts{
Name: "db",
Type: "HTTP",
Delay: 3,
MaxRetries: 2,
Timeout: 1,
},
},
}},
}
lb, err := loadbalancers.Create(networkClient, createOpts).Extract()
if err != nil {
panic(err)
}
Example to Update a Load Balancer Example to Update a Load Balancer
lbID := "d67d56a6-4a86-4688-a282-f46444705c64" lbID := "d67d56a6-4a86-4688-a282-f46444705c64"

View File

@ -2,6 +2,8 @@ package loadbalancers
import ( import (
"github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/listeners"
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/pools"
"github.com/gophercloud/gophercloud/pagination" "github.com/gophercloud/gophercloud/pagination"
) )
@ -29,6 +31,7 @@ type ListOpts struct {
OperatingStatus string `q:"operating_status"` OperatingStatus string `q:"operating_status"`
Name string `q:"name"` Name string `q:"name"`
FlavorID string `q:"flavor_id"` FlavorID string `q:"flavor_id"`
AvailabilityZone string `q:"availability_zone"`
Provider string `q:"provider"` Provider string `q:"provider"`
Limit int `q:"limit"` Limit int `q:"limit"`
Marker string `q:"marker"` Marker string `q:"marker"`
@ -111,9 +114,27 @@ type CreateOpts struct {
// The UUID of a flavor. // The UUID of a flavor.
FlavorID string `json:"flavor_id,omitempty"` FlavorID string `json:"flavor_id,omitempty"`
// The name of an Octavia availability zone.
// Requires Octavia API version 2.14 or later.
AvailabilityZone string `json:"availability_zone,omitempty"`
// The name of the provider. // The name of the provider.
Provider string `json:"provider,omitempty"` Provider string `json:"provider,omitempty"`
// Listeners is a slice of listeners.CreateOpts which allows a set
// of listeners to be created at the same time the Loadbalancer is created.
//
// This is only possible to use when creating a fully populated
// load balancer.
Listeners []listeners.CreateOpts `json:"listeners,omitempty"`
// Pools is a slice of pools.CreateOpts which allows a set of pools
// to be created at the same time the Loadbalancer is created.
//
// This is only possible to use when creating a fully populated
// load balancer.
Pools []pools.CreateOpts `json:"pools,omitempty"`
// Tags is a set of resource tags. // Tags is a set of resource tags.
Tags []string `json:"tags,omitempty"` Tags []string `json:"tags,omitempty"`
} }

View File

@ -59,6 +59,9 @@ type LoadBalancer struct {
// The UUID of a flavor if set. // The UUID of a flavor if set.
FlavorID string `json:"flavor_id"` FlavorID string `json:"flavor_id"`
// The name of an Octavia availability zone if set.
AvailabilityZone string `json:"availability_zone"`
// The name of the provider. // The name of the provider.
Provider string `json:"provider"` Provider string `json:"provider"`

View File

@ -91,7 +91,7 @@ type CreateOptsBuilder interface {
// operation. // operation.
type CreateOpts struct { type CreateOpts struct {
// The Pool to Monitor. // The Pool to Monitor.
PoolID string `json:"pool_id" required:"true"` PoolID string `json:"pool_id,omitempty"`
// The type of probe, which is PING, TCP, HTTP, or HTTPS, that is // The type of probe, which is PING, TCP, HTTP, or HTTPS, that is
// sent by the load balancer to verify the member state. // sent by the load balancer to verify the member state.

View File

@ -2,6 +2,7 @@ package pools
import ( import (
"github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/monitors"
"github.com/gophercloud/gophercloud/pagination" "github.com/gophercloud/gophercloud/pagination"
) )
@ -92,11 +93,11 @@ type CreateOpts struct {
// The Loadbalancer on which the members of the pool will be associated with. // The Loadbalancer on which the members of the pool will be associated with.
// Note: one of LoadbalancerID or ListenerID must be provided. // Note: one of LoadbalancerID or ListenerID must be provided.
LoadbalancerID string `json:"loadbalancer_id,omitempty" xor:"ListenerID"` LoadbalancerID string `json:"loadbalancer_id,omitempty"`
// The Listener on which the members of the pool will be associated with. // The Listener on which the members of the pool will be associated with.
// Note: one of LoadbalancerID or ListenerID must be provided. // Note: one of LoadbalancerID or ListenerID must be provided.
ListenerID string `json:"listener_id,omitempty" xor:"LoadbalancerID"` ListenerID string `json:"listener_id,omitempty"`
// ProjectID is the UUID of the project who owns the Pool. // ProjectID is the UUID of the project who owns the Pool.
// Only administrative users can specify a project UUID other than their own. // Only administrative users can specify a project UUID other than their own.
@ -115,6 +116,20 @@ type CreateOpts struct {
// The administrative state of the Pool. A valid value is true (UP) // The administrative state of the Pool. 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"`
// Members is a slice of BatchUpdateMemberOpts which allows a set of
// members to be created at the same time the pool is created.
//
// This is only possible to use when creating a fully populated
// Loadbalancer.
Members []BatchUpdateMemberOpts `json:"members,omitempty"`
// Monitor is an instance of monitors.CreateOpts which allows a monitor
// to be created at the same time the pool is created.
//
// This is only possible to use when creating a fully populated
// Loadbalancer.
Monitor *monitors.CreateOpts `json:"healthmonitor,omitempty"`
} }
// ToPoolCreateMap builds a request body from CreateOpts. // ToPoolCreateMap builds a request body from CreateOpts.
@ -280,7 +295,9 @@ type CreateMemberOpts struct {
// or false (DOWN). // or false (DOWN).
AdminStateUp *bool `json:"admin_state_up,omitempty"` AdminStateUp *bool `json:"admin_state_up,omitempty"`
// Is the member a backup? Backup members only receive traffic when all non-backup members are down. // Is the member a backup? Backup members only receive traffic when all
// non-backup members are down.
// Requires microversion 2.1 or later.
Backup *bool `json:"backup,omitempty"` Backup *bool `json:"backup,omitempty"`
// An alternate IP address used for health monitoring a backend member. // An alternate IP address used for health monitoring a backend member.
@ -288,6 +305,10 @@ type CreateMemberOpts struct {
// An alternate protocol port used for health monitoring a backend member. // An alternate protocol port used for health monitoring a backend member.
MonitorPort *int `json:"monitor_port,omitempty"` MonitorPort *int `json:"monitor_port,omitempty"`
// A list of simple strings assigned to the resource.
// Requires microversion 2.5 or later.
Tags []string `json:"tags,omitempty"`
} }
// ToMemberCreateMap builds a request body from CreateMemberOpts. // ToMemberCreateMap builds a request body from CreateMemberOpts.
@ -335,6 +356,21 @@ type UpdateMemberOpts struct {
// The administrative state of the Pool. A valid value is true (UP) // The administrative state of the Pool. 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"`
// Is the member a backup? Backup members only receive traffic when all
// non-backup members are down.
// Requires microversion 2.1 or later.
Backup *bool `json:"backup,omitempty"`
// An alternate IP address used for health monitoring a backend member.
MonitorAddress *string `json:"monitor_address,omitempty"`
// An alternate protocol port used for health monitoring a backend member.
MonitorPort *int `json:"monitor_port,omitempty"`
// A list of simple strings assigned to the resource.
// Requires microversion 2.5 or later.
Tags []string `json:"tags,omitempty"`
} }
// ToMemberUpdateMap builds a request body from UpdateMemberOpts. // ToMemberUpdateMap builds a request body from UpdateMemberOpts.
@ -390,6 +426,21 @@ type BatchUpdateMemberOpts struct {
// The administrative state of the Pool. A valid value is true (UP) // The administrative state of the Pool. 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"`
// Is the member a backup? Backup members only receive traffic when all
// non-backup members are down.
// Requires microversion 2.1 or later.
Backup *bool `json:"backup,omitempty"`
// An alternate IP address used for health monitoring a backend member.
MonitorAddress *string `json:"monitor_address,omitempty"`
// An alternate protocol port used for health monitoring a backend member.
MonitorPort *int `json:"monitor_port,omitempty"`
// A list of simple strings assigned to the resource.
// Requires microversion 2.5 or later.
Tags []string `json:"tags,omitempty"`
} }
// ToBatchMemberUpdateMap builds a request body from BatchUpdateMemberOpts. // ToBatchMemberUpdateMap builds a request body from BatchUpdateMemberOpts.
@ -425,8 +476,7 @@ func BatchUpdateMembers(c *gophercloud.ServiceClient, poolID string, opts []Batc
return return
} }
// DisassociateMember will remove and disassociate a Member from a particular // DeleteMember will remove and disassociate a Member from a particular Pool.
// Pool.
func DeleteMember(c *gophercloud.ServiceClient, poolID string, memberID string) (r DeleteMemberResult) { func DeleteMember(c *gophercloud.ServiceClient, poolID string, memberID string) (r DeleteMemberResult) {
resp, err := c.Delete(memberResourceURL(c, poolID, memberID), nil) resp, err := c.Delete(memberResourceURL(c, poolID, memberID), nil)
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err)

View File

@ -228,6 +228,10 @@ type Member struct {
// An alternate protocol port used for health monitoring a backend member. // An alternate protocol port used for health monitoring a backend member.
MonitorPort int `json:"monitor_port"` MonitorPort int `json:"monitor_port"`
// A list of simple strings assigned to the resource.
// Requires microversion 2.5 or later.
Tags []string `json:"tags"`
} }
// MemberPage is the page returned by a pager when traversing over a // MemberPage is the page returned by a pager when traversing over a

View File

@ -48,7 +48,20 @@ Example to Update a Router
updateOpts := routers.UpdateOpts{ updateOpts := routers.UpdateOpts{
Name: "new_name", Name: "new_name",
Routes: routes, Routes: &routes,
}
router, err := routers.Update(networkClient, routerID, updateOpts).Extract()
if err != nil {
panic(err)
}
Example to Update just the Router name, keeping everything else as-is
routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
updateOpts := routers.UpdateOpts{
Name: "new_name",
} }
router, err := routers.Update(networkClient, routerID, updateOpts).Extract() router, err := routers.Update(networkClient, routerID, updateOpts).Extract()
@ -63,7 +76,7 @@ Example to Remove all Routes from a Router
routes := []routers.Route{} routes := []routers.Route{}
updateOpts := routers.UpdateOpts{ updateOpts := routers.UpdateOpts{
Routes: routes, Routes: &routes,
} }
router, err := routers.Update(networkClient, routerID, updateOpts).Extract() router, err := routers.Update(networkClient, routerID, updateOpts).Extract()
@ -104,5 +117,23 @@ Example to Remove an Interface from a Router
if err != nil { if err != nil {
panic(err) panic(err)
} }
Example to List an L3 agents for a Router
routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
allPages, err := routers.ListL3Agents(networkClient, routerID).AllPages()
if err != nil {
panic(err)
}
allL3Agents, err := routers.ExtractL3Agents(allPages)
if err != nil {
panic(err)
}
for _, agent := range allL3Agents {
fmt.Printf("%+v\n", agent)
}
*/ */
package routers package routers

View File

@ -109,7 +109,7 @@ type UpdateOpts struct {
AdminStateUp *bool `json:"admin_state_up,omitempty"` AdminStateUp *bool `json:"admin_state_up,omitempty"`
Distributed *bool `json:"distributed,omitempty"` Distributed *bool `json:"distributed,omitempty"`
GatewayInfo *GatewayInfo `json:"external_gateway_info,omitempty"` GatewayInfo *GatewayInfo `json:"external_gateway_info,omitempty"`
Routes []Route `json:"routes"` Routes *[]Route `json:"routes,omitempty"`
} }
// ToRouterUpdateMap builds an update body based on UpdateOpts. // ToRouterUpdateMap builds an update body based on UpdateOpts.
@ -237,3 +237,10 @@ func RemoveInterface(c *gophercloud.ServiceClient, id string, opts RemoveInterfa
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
return return
} }
// ListL3Agents returns a list of l3-agents scheduled for a specific router.
func ListL3Agents(c *gophercloud.ServiceClient, id string) (result pagination.Pager) {
return pagination.NewPager(c, listl3AgentsURL(c, id), func(r pagination.PageResult) pagination.Page {
return ListL3AgentsPage{pagination.SinglePageBase(r)}
})
}

View File

@ -1,6 +1,9 @@
package routers package routers
import ( import (
"encoding/json"
"time"
"github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/pagination" "github.com/gophercloud/gophercloud/pagination"
) )
@ -179,3 +182,96 @@ func (r InterfaceResult) Extract() (*InterfaceInfo, error) {
err := r.ExtractInto(&s) err := r.ExtractInto(&s)
return &s, err return &s, err
} }
// L3Agent represents a Neutron agent for routers.
type L3Agent struct {
// ID is the id of the agent.
ID string `json:"id"`
// AdminStateUp is an administrative state of the agent.
AdminStateUp bool `json:"admin_state_up"`
// AgentType is a type of the agent.
AgentType string `json:"agent_type"`
// Alive indicates whether agent is alive or not.
Alive bool `json:"alive"`
// ResourcesSynced indicates whether agent is synced or not.
// Not all agent types track resources via Placement.
ResourcesSynced bool `json:"resources_synced"`
// AvailabilityZone is a zone of the agent.
AvailabilityZone string `json:"availability_zone"`
// Binary is an executable binary of the agent.
Binary string `json:"binary"`
// Configurations is a configuration specific key/value pairs that are
// determined by the agent binary and type.
Configurations map[string]interface{} `json:"configurations"`
// CreatedAt is a creation timestamp.
CreatedAt time.Time `json:"-"`
// StartedAt is a starting timestamp.
StartedAt time.Time `json:"-"`
// HeartbeatTimestamp is a last heartbeat timestamp.
HeartbeatTimestamp time.Time `json:"-"`
// Description contains agent description.
Description string `json:"description"`
// Host is a hostname of the agent system.
Host string `json:"host"`
// Topic contains name of AMQP topic.
Topic string `json:"topic"`
// HAState is a ha state of agent(active/standby) for router
HAState string `json:"ha_state"`
// ResourceVersions is a list agent known objects and version numbers
ResourceVersions map[string]interface{} `json:"resource_versions"`
}
// UnmarshalJSON helps to convert the timestamps into the time.Time type.
func (r *L3Agent) UnmarshalJSON(b []byte) error {
type tmp L3Agent
var s struct {
tmp
CreatedAt gophercloud.JSONRFC3339ZNoTNoZ `json:"created_at"`
StartedAt gophercloud.JSONRFC3339ZNoTNoZ `json:"started_at"`
HeartbeatTimestamp gophercloud.JSONRFC3339ZNoTNoZ `json:"heartbeat_timestamp"`
}
err := json.Unmarshal(b, &s)
if err != nil {
return err
}
*r = L3Agent(s.tmp)
r.CreatedAt = time.Time(s.CreatedAt)
r.StartedAt = time.Time(s.StartedAt)
r.HeartbeatTimestamp = time.Time(s.HeartbeatTimestamp)
return nil
}
type ListL3AgentsPage struct {
pagination.SinglePageBase
}
func (r ListL3AgentsPage) IsEmpty() (bool, error) {
v, err := ExtractL3Agents(r)
return len(v) == 0, err
}
func ExtractL3Agents(r pagination.Page) ([]L3Agent, error) {
var s struct {
L3Agents []L3Agent `json:"agents"`
}
err := (r.(ListL3AgentsPage)).ExtractInto(&s)
return s.L3Agents, err
}

View File

@ -19,3 +19,7 @@ func addInterfaceURL(c *gophercloud.ServiceClient, id string) string {
func removeInterfaceURL(c *gophercloud.ServiceClient, id string) string { func removeInterfaceURL(c *gophercloud.ServiceClient, id string) string {
return c.ServiceURL(resourcePath, id, "remove_router_interface") return c.ServiceURL(resourcePath, id, "remove_router_interface")
} }
func listl3AgentsURL(c *gophercloud.ServiceClient, id string) string {
return c.ServiceURL(resourcePath, id, "l3-agents")
}

View File

@ -53,6 +53,7 @@ type UpdateOptsBuilder interface {
// deleting an account's metadata. // deleting an account's metadata.
type UpdateOpts struct { type UpdateOpts struct {
Metadata map[string]string Metadata map[string]string
RemoveMetadata []string
ContentType string `h:"Content-Type"` ContentType string `h:"Content-Type"`
DetectContentType bool `h:"X-Detect-Content-Type"` DetectContentType bool `h:"X-Detect-Content-Type"`
TempURLKey string `h:"X-Account-Meta-Temp-URL-Key"` TempURLKey string `h:"X-Account-Meta-Temp-URL-Key"`
@ -65,9 +66,15 @@ func (opts UpdateOpts) ToAccountUpdateMap() (map[string]string, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
for k, v := range opts.Metadata { for k, v := range opts.Metadata {
headers["X-Account-Meta-"+k] = v headers["X-Account-Meta-"+k] = v
} }
for _, k := range opts.RemoveMetadata {
headers["X-Remove-Account-Meta-"+k] = "remove"
}
return headers, err return headers, err
} }

View File

@ -80,6 +80,7 @@ type CreateOpts struct {
HistoryLocation string `h:"X-History-Location"` HistoryLocation string `h:"X-History-Location"`
TempURLKey string `h:"X-Container-Meta-Temp-URL-Key"` TempURLKey string `h:"X-Container-Meta-Temp-URL-Key"`
TempURLKey2 string `h:"X-Container-Meta-Temp-URL-Key-2"` TempURLKey2 string `h:"X-Container-Meta-Temp-URL-Key-2"`
StoragePolicy string `h:"X-Storage-Policy"`
} }
// ToContainerCreateMap formats a CreateOpts into a map of headers. // ToContainerCreateMap formats a CreateOpts into a map of headers.

View File

@ -153,8 +153,8 @@ type CreateOpts struct {
ContentLength int64 `h:"Content-Length"` ContentLength int64 `h:"Content-Length"`
ContentType string `h:"Content-Type"` ContentType string `h:"Content-Type"`
CopyFrom string `h:"X-Copy-From"` CopyFrom string `h:"X-Copy-From"`
DeleteAfter int `h:"X-Delete-After"` DeleteAfter int64 `h:"X-Delete-After"`
DeleteAt int `h:"X-Delete-At"` DeleteAt int64 `h:"X-Delete-At"`
DetectContentType string `h:"X-Detect-Content-Type"` DetectContentType string `h:"X-Detect-Content-Type"`
ETag string `h:"ETag"` ETag string `h:"ETag"`
IfNoneMatch string `h:"If-None-Match"` IfNoneMatch string `h:"If-None-Match"`
@ -388,11 +388,12 @@ type UpdateOptsBuilder interface {
// deleting an object's metadata. // deleting an object's metadata.
type UpdateOpts struct { type UpdateOpts struct {
Metadata map[string]string Metadata map[string]string
RemoveMetadata []string
ContentDisposition string `h:"Content-Disposition"` ContentDisposition string `h:"Content-Disposition"`
ContentEncoding string `h:"Content-Encoding"` ContentEncoding string `h:"Content-Encoding"`
ContentType string `h:"Content-Type"` ContentType string `h:"Content-Type"`
DeleteAfter int `h:"X-Delete-After"` DeleteAfter int64 `h:"X-Delete-After"`
DeleteAt int `h:"X-Delete-At"` DeleteAt int64 `h:"X-Delete-At"`
DetectContentType bool `h:"X-Detect-Content-Type"` DetectContentType bool `h:"X-Detect-Content-Type"`
} }
@ -402,9 +403,14 @@ func (opts UpdateOpts) ToObjectUpdateMap() (map[string]string, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
for k, v := range opts.Metadata { for k, v := range opts.Metadata {
h["X-Object-Meta-"+k] = v h["X-Object-Meta-"+k] = v
} }
for _, k := range opts.RemoveMetadata {
h["X-Remove-Object-Meta-"+k] = "remove"
}
return h, nil return h, nil
} }
@ -454,6 +460,9 @@ type CreateTempURLOpts struct {
// the object path is used in the hash, the object URL needs to be parsed. If // the object path is used in the hash, the object URL needs to be parsed. If
// empty, the default OpenStack URL split point will be used ("/v1/"). // empty, the default OpenStack URL split point will be used ("/v1/").
Split string Split string
// Timestamp is a timestamp to calculate Temp URL signature. Optional.
Timestamp time.Time
} }
// CreateTempURL is a function for creating a temporary URL for an object. It // CreateTempURL is a function for creating a temporary URL for an object. It
@ -463,8 +472,17 @@ func CreateTempURL(c *gophercloud.ServiceClient, containerName, objectName strin
if opts.Split == "" { if opts.Split == "" {
opts.Split = "/v1/" opts.Split = "/v1/"
} }
// Initialize time if it was not passed as opts
var date time.Time
if opts.Timestamp.IsZero() {
date = time.Now().UTC()
} else {
date = opts.Timestamp
}
duration := time.Duration(opts.TTL) * time.Second duration := time.Duration(opts.TTL) * time.Second
expiry := time.Now().Add(duration).Unix() expiry := date.Add(duration).Unix()
getHeader, err := containers.Get(c, url.QueryEscape(containerName), nil).Extract() getHeader, err := containers.Get(c, url.QueryEscape(containerName), nil).Extract()
if err != nil { if err != nil {
return "", err return "", err
@ -479,7 +497,7 @@ func CreateTempURL(c *gophercloud.ServiceClient, containerName, objectName strin
tempURLKey = getHeader.TempURLKey tempURLKey = getHeader.TempURLKey
} }
secretKey := []byte(tempURLKey) secretKey := []byte(tempURLKey)
url := getURL(c, url.QueryEscape(containerName), url.QueryEscape(objectName)) url := getURL(c, containerName, objectName)
splitPath := strings.Split(url, opts.Split) splitPath := strings.Split(url, opts.Split)
baseURL, objectPath := splitPath[0], splitPath[1] baseURL, objectPath := splitPath[0], splitPath[1]
objectPath = opts.Split + objectPath objectPath = opts.Split + objectPath

View File

@ -40,7 +40,7 @@ func (current LinkedPageBase) NextPageURL() (string, error) {
} }
for { for {
key, path = path[0], path[1:len(path)] key, path = path[0], path[1:]
value, ok := submap[key] value, ok := submap[key]
if !ok { if !ok {

View File

@ -94,10 +94,32 @@ type ProviderClient struct {
// reauthlock represents a set of attributes used to help in the reauthentication process. // reauthlock represents a set of attributes used to help in the reauthentication process.
type reauthlock struct { type reauthlock struct {
sync.RWMutex sync.RWMutex
// This channel is non-nil during reauthentication. It can be used to ask the ongoing *reauthFuture
// goroutine doing Reauthenticate() for its result. Look at the implementation }
// of Reauthenticate() for details.
ongoing chan<- (chan<- error) // reauthFuture represents future result of the reauthentication process.
// while done channel is not closed, reauthentication is in progress.
// when done channel is closed, err contains the result of reauthentication.
type reauthFuture struct {
done chan struct{}
err error
}
func newReauthFuture() *reauthFuture {
return &reauthFuture{
make(chan struct{}),
nil,
}
}
func (f *reauthFuture) Set(err error) {
f.err = err
close(f.done)
}
func (f *reauthFuture) Get() error {
<-f.done
return f.err
} }
// AuthenticatedHeaders returns a map of HTTP headers that are common for all // AuthenticatedHeaders returns a map of HTTP headers that are common for all
@ -112,9 +134,7 @@ func (client *ProviderClient) AuthenticatedHeaders() (m map[string]string) {
ongoing := client.reauthmut.ongoing ongoing := client.reauthmut.ongoing
client.reauthmut.Unlock() client.reauthmut.Unlock()
if ongoing != nil { if ongoing != nil {
responseChannel := make(chan error) _ = ongoing.Get()
ongoing <- responseChannel
_ = <-responseChannel
} }
} }
t := client.Token() t := client.Token()
@ -237,21 +257,19 @@ func (client *ProviderClient) Reauthenticate(previousToken string) error {
return client.ReauthFunc() return client.ReauthFunc()
} }
messages := make(chan (chan<- error)) future := newReauthFuture()
// Check if a Reauthenticate is in progress, or start one if not. // Check if a Reauthenticate is in progress, or start one if not.
client.reauthmut.Lock() client.reauthmut.Lock()
ongoing := client.reauthmut.ongoing ongoing := client.reauthmut.ongoing
if ongoing == nil { if ongoing == nil {
client.reauthmut.ongoing = messages client.reauthmut.ongoing = future
} }
client.reauthmut.Unlock() client.reauthmut.Unlock()
// If Reauthenticate is running elsewhere, wait for its result. // If Reauthenticate is running elsewhere, wait for its result.
if ongoing != nil { if ongoing != nil {
responseChannel := make(chan error) return ongoing.Get()
ongoing <- responseChannel
return <-responseChannel
} }
// Perform the actual reauthentication. // Perform the actual reauthentication.
@ -264,22 +282,10 @@ func (client *ProviderClient) Reauthenticate(previousToken string) error {
// Mark Reauthenticate as finished. // Mark Reauthenticate as finished.
client.reauthmut.Lock() client.reauthmut.Lock()
client.reauthmut.ongoing.Set(err)
client.reauthmut.ongoing = nil client.reauthmut.ongoing = nil
client.reauthmut.Unlock() client.reauthmut.Unlock()
// Report result to all other interested goroutines.
//
// This happens in a separate goroutine because another goroutine might have
// acquired a copy of `client.reauthmut.ongoing` before we cleared it, but not
// have come around to sending its request. By answering in a goroutine, we
// can have that goroutine linger until all responseChannels have been sent.
// When GC has collected all sendings ends of the channel, our receiving end
// will be closed and the goroutine will end.
go func() {
for responseChannel := range messages {
responseChannel <- err
}
}()
return err return err
} }

View File

@ -4,10 +4,85 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"path/filepath" "path/filepath"
"reflect"
"strings" "strings"
"time" "time"
) )
// NormalizePathURL is used to convert rawPath to a fqdn, using basePath as
// a reference in the filesystem, if necessary. basePath is assumed to contain
// either '.' when first used, or the file:// type fqdn of the parent resource.
// e.g. myFavScript.yaml => file://opt/lib/myFavScript.yaml
func NormalizePathURL(basePath, rawPath string) (string, error) {
u, err := url.Parse(rawPath)
if err != nil {
return "", err
}
// if a scheme is defined, it must be a fqdn already
if u.Scheme != "" {
return u.String(), nil
}
// if basePath is a url, then child resources are assumed to be relative to it
bu, err := url.Parse(basePath)
if err != nil {
return "", err
}
var basePathSys, absPathSys string
if bu.Scheme != "" {
basePathSys = filepath.FromSlash(bu.Path)
absPathSys = filepath.Join(basePathSys, rawPath)
bu.Path = filepath.ToSlash(absPathSys)
return bu.String(), nil
}
absPathSys = filepath.Join(basePath, rawPath)
u.Path = filepath.ToSlash(absPathSys)
if err != nil {
return "", err
}
u.Scheme = "file"
return u.String(), nil
}
// NormalizeURL is an internal function to be used by provider clients.
//
// It ensures that each endpoint URL has a closing `/`, as expected by
// ServiceClient's methods.
func NormalizeURL(url string) string {
if !strings.HasSuffix(url, "/") {
return url + "/"
}
return url
}
// RemainingKeys will inspect a struct and compare it to a map. Any struct
// field that does not have a JSON tag that matches a key in the map or
// a matching lower-case field in the map will be returned as an extra.
//
// This is useful for determining the extra fields returned in response bodies
// for resources that can contain an arbitrary or dynamic number of fields.
func RemainingKeys(s interface{}, m map[string]interface{}) (extras map[string]interface{}) {
extras = make(map[string]interface{})
for k, v := range m {
extras[k] = v
}
valueOf := reflect.ValueOf(s)
typeOf := reflect.TypeOf(s)
for i := 0; i < valueOf.NumField(); i++ {
field := typeOf.Field(i)
lowerField := strings.ToLower(field.Name)
delete(extras, lowerField)
if tagValue := field.Tag.Get("json"); tagValue != "" && tagValue != "-" {
delete(extras, tagValue)
}
}
return
}
// WaitFor polls a predicate function, once per second, up to a timeout limit. // WaitFor polls a predicate function, once per second, up to a timeout limit.
// This is useful to wait for a resource to transition to a certain state. // This is useful to wait for a resource to transition to a certain state.
// To handle situations when the predicate might hang indefinitely, the // To handle situations when the predicate might hang indefinitely, the
@ -53,50 +128,3 @@ func WaitFor(timeout int, predicate func() (bool, error)) error {
} }
} }
} }
// NormalizeURL is an internal function to be used by provider clients.
//
// It ensures that each endpoint URL has a closing `/`, as expected by
// ServiceClient's methods.
func NormalizeURL(url string) string {
if !strings.HasSuffix(url, "/") {
return url + "/"
}
return url
}
// NormalizePathURL is used to convert rawPath to a fqdn, using basePath as
// a reference in the filesystem, if necessary. basePath is assumed to contain
// either '.' when first used, or the file:// type fqdn of the parent resource.
// e.g. myFavScript.yaml => file://opt/lib/myFavScript.yaml
func NormalizePathURL(basePath, rawPath string) (string, error) {
u, err := url.Parse(rawPath)
if err != nil {
return "", err
}
// if a scheme is defined, it must be a fqdn already
if u.Scheme != "" {
return u.String(), nil
}
// if basePath is a url, then child resources are assumed to be relative to it
bu, err := url.Parse(basePath)
if err != nil {
return "", err
}
var basePathSys, absPathSys string
if bu.Scheme != "" {
basePathSys = filepath.FromSlash(bu.Path)
absPathSys = filepath.Join(basePathSys, rawPath)
bu.Path = filepath.ToSlash(absPathSys)
return bu.String(), nil
}
absPathSys = filepath.Join(basePath, rawPath)
u.Path = filepath.ToSlash(absPathSys)
if err != nil {
return "", err
}
u.Scheme = "file"
return u.String(), nil
}

4
vendor/modules.txt vendored
View File

@ -300,10 +300,9 @@ github.com/googleapis/gax-go/v2
github.com/googleapis/gnostic/compiler github.com/googleapis/gnostic/compiler
github.com/googleapis/gnostic/extensions github.com/googleapis/gnostic/extensions
github.com/googleapis/gnostic/openapiv2 github.com/googleapis/gnostic/openapiv2
# github.com/gophercloud/gophercloud v0.11.1-0.20200518183226-7aec46f32c19 => github.com/gophercloud/gophercloud v0.11.0 # github.com/gophercloud/gophercloud v0.15.0
## explicit ## explicit
github.com/gophercloud/gophercloud github.com/gophercloud/gophercloud
github.com/gophercloud/gophercloud/internal
github.com/gophercloud/gophercloud/openstack github.com/gophercloud/gophercloud/openstack
github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes
github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/availabilityzones github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/availabilityzones
@ -1393,4 +1392,3 @@ sigs.k8s.io/yaml
# k8s.io/cli-runtime => k8s.io/cli-runtime v0.20.0 # k8s.io/cli-runtime => k8s.io/cli-runtime v0.20.0
# k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.20.0 # k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.20.0
# k8s.io/code-generator => k8s.io/code-generator v0.20.0 # k8s.io/code-generator => k8s.io/code-generator v0.20.0
# github.com/gophercloud/gophercloud => github.com/gophercloud/gophercloud v0.11.0