From 2cdaf1f32b1238517ae3526c1e8cde996df0c8e7 Mon Sep 17 00:00:00 2001 From: Nick Sardo Date: Thu, 1 Jun 2017 15:22:34 -0700 Subject: [PATCH] Refactor compute API calls --- pkg/cloudprovider/providers/gce/gce.go | 2 + .../providers/gce/gce_addresses.go | 58 +++++++++---- .../providers/gce/gce_backendservice.go | 40 ++++----- .../providers/gce/gce_forwardingrule.go | 57 +++++++++---- .../providers/gce/gce_healthchecks.go | 21 +---- .../providers/gce/gce_instancegroup.go | 23 ++--- .../providers/gce/gce_instances.go | 33 ++++++++ .../providers/gce/gce_targetpool.go | 84 +++++++++++++++++++ pkg/cloudprovider/providers/gce/gce_util.go | 15 ++++ pkg/cloudprovider/providers/gce/gce_zones.go | 32 ++++++- 10 files changed, 281 insertions(+), 84 deletions(-) create mode 100644 pkg/cloudprovider/providers/gce/gce_targetpool.go diff --git a/pkg/cloudprovider/providers/gce/gce.go b/pkg/cloudprovider/providers/gce/gce.go index 5cb2d7bf447..90e2570a429 100644 --- a/pkg/cloudprovider/providers/gce/gce.go +++ b/pkg/cloudprovider/providers/gce/gce.go @@ -78,6 +78,8 @@ const ( // GCECloud is an implementation of Interface, LoadBalancer and Instances for Google Compute Engine. type GCECloud struct { + // ClusterID contains functionality for getting (and initializing) the ingress-uid. Call GCECloud.Initialize() + // for the cloudprovider to start watching the configmap. ClusterID ClusterID service *compute.Service diff --git a/pkg/cloudprovider/providers/gce/gce_addresses.go b/pkg/cloudprovider/providers/gce/gce_addresses.go index 36aa119e898..877d744ddfa 100644 --- a/pkg/cloudprovider/providers/gce/gce_addresses.go +++ b/pkg/cloudprovider/providers/gce/gce_addresses.go @@ -22,21 +22,20 @@ import ( compute "google.golang.org/api/compute/v1" ) -func newStaticIPMetricContext(request string) *metricContext { +func newAddressMetricContext(request, region string) *metricContext { return &metricContext{ start: time.Now(), - attributes: []string{"staticip_" + request, unusedMetricLabel, unusedMetricLabel}, + attributes: []string{"address_" + request, region, unusedMetricLabel}, } } -// ReserveGlobalStaticIP creates a global static IP. +// ReserveGlobalAddress creates a global address. // Caller is allocated a random IP if they do not specify an ipAddress. If an // ipAddress is specified, it must belong to the current project, eg: an // ephemeral IP associated with a global forwarding rule. -func (gce *GCECloud) ReserveGlobalStaticIP(name, ipAddress string) (address *compute.Address, err error) { - mc := newStaticIPMetricContext("reserve") - op, err := gce.service.GlobalAddresses.Insert(gce.projectID, &compute.Address{Name: name, Address: ipAddress}).Do() - +func (gce *GCECloud) ReserveGlobalAddress(addr *compute.Address) (*compute.Address, error) { + mc := newAddressMetricContext("reserve", "") + op, err := gce.service.GlobalAddresses.Insert(gce.projectID, addr).Do() if err != nil { return nil, mc.Observe(err) } @@ -45,12 +44,12 @@ func (gce *GCECloud) ReserveGlobalStaticIP(name, ipAddress string) (address *com return nil, err } - return gce.service.GlobalAddresses.Get(gce.projectID, name).Do() + return gce.GetGlobalAddress(addr.Name) } -// DeleteGlobalStaticIP deletes a global static IP by name. -func (gce *GCECloud) DeleteGlobalStaticIP(name string) error { - mc := newStaticIPMetricContext("delete") +// DeleteGlobalAddress deletes a global address by name. +func (gce *GCECloud) DeleteGlobalAddress(name string) error { + mc := newAddressMetricContext("delete", "") op, err := gce.service.GlobalAddresses.Delete(gce.projectID, name).Do() if err != nil { return mc.Observe(err) @@ -58,9 +57,40 @@ func (gce *GCECloud) DeleteGlobalStaticIP(name string) error { return gce.waitForGlobalOp(op, mc) } -// GetGlobalStaticIP returns the global static IP by name. -func (gce *GCECloud) GetGlobalStaticIP(name string) (*compute.Address, error) { - mc := newStaticIPMetricContext("get") +// GetGlobalAddress returns the global address by name. +func (gce *GCECloud) GetGlobalAddress(name string) (*compute.Address, error) { + mc := newAddressMetricContext("get", "") v, err := gce.service.GlobalAddresses.Get(gce.projectID, name).Do() return v, mc.Observe(err) } + +// ReserveRegionAddress creates a region address +func (gce *GCECloud) ReserveRegionAddress(addr *compute.Address, region string) (*compute.Address, error) { + mc := newAddressMetricContext("reserve", region) + op, err := gce.service.Addresses.Insert(gce.projectID, region, addr).Do() + if err != nil { + return nil, mc.Observe(err) + } + if err := gce.waitForRegionOp(op, region, mc); err != nil { + return nil, err + } + + return gce.GetRegionAddress(addr.Name, region) +} + +// DeleteRegionAddress deletes a region address by name. +func (gce *GCECloud) DeleteRegionAddress(name, region string) error { + mc := newAddressMetricContext("delete", region) + op, err := gce.service.Addresses.Delete(gce.projectID, region, name).Do() + if err != nil { + return mc.Observe(err) + } + return gce.waitForRegionOp(op, region, mc) +} + +// GetRegionAddress returns the region address by name +func (gce *GCECloud) GetRegionAddress(name, region string) (*compute.Address, error) { + mc := newAddressMetricContext("get", region) + v, err := gce.service.Addresses.Get(gce.projectID, region, name).Do() + return v, mc.Observe(err) +} diff --git a/pkg/cloudprovider/providers/gce/gce_backendservice.go b/pkg/cloudprovider/providers/gce/gce_backendservice.go index 1d79dfde0d3..d460c6157d8 100644 --- a/pkg/cloudprovider/providers/gce/gce_backendservice.go +++ b/pkg/cloudprovider/providers/gce/gce_backendservice.go @@ -23,23 +23,23 @@ import ( compute "google.golang.org/api/compute/v1" ) -func newBackendServiceMetricContext(request string) *metricContext { +func newBackendServiceMetricContext(request, region string) *metricContext { return &metricContext{ start: time.Now(), - attributes: []string{"backendservice_" + request, unusedMetricLabel, unusedMetricLabel}, + attributes: []string{"backendservice_" + request, region, unusedMetricLabel}, } } // GetGlobalBackendService retrieves a backend by name. func (gce *GCECloud) GetGlobalBackendService(name string) (*compute.BackendService, error) { - mc := newBackendServiceMetricContext("get") + mc := newBackendServiceMetricContext("get", "") v, err := gce.service.BackendServices.Get(gce.projectID, name).Do() return v, mc.Observe(err) } // UpdateGlobalBackendService applies the given BackendService as an update to an existing service. func (gce *GCECloud) UpdateGlobalBackendService(bg *compute.BackendService) error { - mc := newBackendServiceMetricContext("update") + mc := newBackendServiceMetricContext("update", "") op, err := gce.service.BackendServices.Update(gce.projectID, bg.Name, bg).Do() if err != nil { return mc.Observe(err) @@ -50,7 +50,7 @@ func (gce *GCECloud) UpdateGlobalBackendService(bg *compute.BackendService) erro // DeleteGlobalBackendService deletes the given BackendService by name. func (gce *GCECloud) DeleteGlobalBackendService(name string) error { - mc := newBackendServiceMetricContext("delete") + mc := newBackendServiceMetricContext("delete", "") op, err := gce.service.BackendServices.Delete(gce.projectID, name).Do() if err != nil { if isHTTPErrorCode(err, http.StatusNotFound) { @@ -64,7 +64,7 @@ func (gce *GCECloud) DeleteGlobalBackendService(name string) error { // CreateGlobalBackendService creates the given BackendService. func (gce *GCECloud) CreateGlobalBackendService(bg *compute.BackendService) error { - mc := newBackendServiceMetricContext("create") + mc := newBackendServiceMetricContext("create", "") op, err := gce.service.BackendServices.Insert(gce.projectID, bg).Do() if err != nil { return mc.Observe(err) @@ -75,7 +75,7 @@ func (gce *GCECloud) CreateGlobalBackendService(bg *compute.BackendService) erro // ListGlobalBackendServices lists all backend services in the project. func (gce *GCECloud) ListGlobalBackendServices() (*compute.BackendServiceList, error) { - mc := newBackendServiceMetricContext("list") + mc := newBackendServiceMetricContext("list", "") // TODO: use PageToken to list all not just the first 500 v, err := gce.service.BackendServices.List(gce.projectID).Do() return v, mc.Observe(err) @@ -85,7 +85,7 @@ func (gce *GCECloud) ListGlobalBackendServices() (*compute.BackendServiceList, e // name, in the given instanceGroup. The instanceGroupLink is the fully // qualified self link of an instance group. func (gce *GCECloud) GetGlobalBackendServiceHealth(name string, instanceGroupLink string) (*compute.BackendServiceGroupHealth, error) { - mc := newBackendServiceMetricContext("get_health") + mc := newBackendServiceMetricContext("get_health", "") groupRef := &compute.ResourceGroupReference{Group: instanceGroupLink} v, err := gce.service.BackendServices.GetHealth(gce.projectID, name, groupRef).Do() return v, mc.Observe(err) @@ -93,25 +93,25 @@ func (gce *GCECloud) GetGlobalBackendServiceHealth(name string, instanceGroupLin // GetRegionBackendService retrieves a backend by name. func (gce *GCECloud) GetRegionBackendService(name, region string) (*compute.BackendService, error) { - mc := newBackendServiceMetricContext("get") + mc := newBackendServiceMetricContext("get", region) v, err := gce.service.RegionBackendServices.Get(gce.projectID, region, name).Do() return v, mc.Observe(err) } // UpdateRegionBackendService applies the given BackendService as an update to an existing service. -func (gce *GCECloud) UpdateRegionBackendService(bg *compute.BackendService) error { - mc := newBackendServiceMetricContext("update") - op, err := gce.service.RegionBackendServices.Update(gce.projectID, bg.Region, bg.Name, bg).Do() +func (gce *GCECloud) UpdateRegionBackendService(bg *compute.BackendService, region string) error { + mc := newBackendServiceMetricContext("update", region) + op, err := gce.service.RegionBackendServices.Update(gce.projectID, region, bg.Name, bg).Do() if err != nil { return mc.Observe(err) } - return gce.waitForRegionOp(op, bg.Region, mc) + return gce.waitForRegionOp(op, region, mc) } // DeleteRegionBackendService deletes the given BackendService by name. func (gce *GCECloud) DeleteRegionBackendService(name, region string) error { - mc := newBackendServiceMetricContext("delete") + mc := newBackendServiceMetricContext("delete", region) op, err := gce.service.RegionBackendServices.Delete(gce.projectID, region, name).Do() if err != nil { if isHTTPErrorCode(err, http.StatusNotFound) { @@ -124,19 +124,19 @@ func (gce *GCECloud) DeleteRegionBackendService(name, region string) error { } // CreateRegionBackendService creates the given BackendService. -func (gce *GCECloud) CreateRegionBackendService(bg *compute.BackendService) error { - mc := newBackendServiceMetricContext("create") - op, err := gce.service.RegionBackendServices.Insert(gce.projectID, bg.Region, bg).Do() +func (gce *GCECloud) CreateRegionBackendService(bg *compute.BackendService, region string) error { + mc := newBackendServiceMetricContext("create", region) + op, err := gce.service.RegionBackendServices.Insert(gce.projectID, region, bg).Do() if err != nil { return mc.Observe(err) } - return gce.waitForRegionOp(op, bg.Region, mc) + return gce.waitForRegionOp(op, region, mc) } // ListRegionBackendServices lists all backend services in the project. func (gce *GCECloud) ListRegionBackendServices(region string) (*compute.BackendServiceList, error) { - mc := newBackendServiceMetricContext("list") + mc := newBackendServiceMetricContext("list", region) // TODO: use PageToken to list all not just the first 500 v, err := gce.service.RegionBackendServices.List(gce.projectID, region).Do() return v, mc.Observe(err) @@ -146,7 +146,7 @@ func (gce *GCECloud) ListRegionBackendServices(region string) (*compute.BackendS // name, in the given instanceGroup. The instanceGroupLink is the fully // qualified self link of an instance group. func (gce *GCECloud) GetRegionalBackendServiceHealth(name, region string, instanceGroupLink string) (*compute.BackendServiceGroupHealth, error) { - mc := newBackendServiceMetricContext("get_health") + mc := newBackendServiceMetricContext("get_health", region) groupRef := &compute.ResourceGroupReference{Group: instanceGroupLink} v, err := gce.service.RegionBackendServices.GetHealth(gce.projectID, region, name, groupRef).Do() return v, mc.Observe(err) diff --git a/pkg/cloudprovider/providers/gce/gce_forwardingrule.go b/pkg/cloudprovider/providers/gce/gce_forwardingrule.go index 0eedf0559cb..de800547ceb 100644 --- a/pkg/cloudprovider/providers/gce/gce_forwardingrule.go +++ b/pkg/cloudprovider/providers/gce/gce_forwardingrule.go @@ -17,7 +17,6 @@ limitations under the License. package gce import ( - "net/http" "time" compute "google.golang.org/api/compute/v1" @@ -44,8 +43,7 @@ func (gce *GCECloud) CreateGlobalForwardingRule(targetProxyLink, ip, name, portR } op, err := gce.service.GlobalForwardingRules.Insert(gce.projectID, rule).Do() if err != nil { - mc.Observe(err) - return nil, err + return nil, mc.Observe(err) } if err = gce.waitForGlobalOp(op, mc); err != nil { return nil, err @@ -56,13 +54,12 @@ func (gce *GCECloud) CreateGlobalForwardingRule(targetProxyLink, ip, name, portR // SetProxyForGlobalForwardingRule links the given TargetHttp(s)Proxy with the given GlobalForwardingRule. // targetProxyLink is the SelfLink of a TargetHttp(s)Proxy. -func (gce *GCECloud) SetProxyForGlobalForwardingRule(fw *compute.ForwardingRule, targetProxyLink string) error { +func (gce *GCECloud) SetProxyForGlobalForwardingRule(forwardingRuleName, targetProxyLink string) error { mc := newForwardingRuleMetricContext("set_proxy", "") op, err := gce.service.GlobalForwardingRules.SetTarget( - gce.projectID, fw.Name, &compute.TargetReference{Target: targetProxyLink}).Do() + gce.projectID, forwardingRuleName, &compute.TargetReference{Target: targetProxyLink}).Do() if err != nil { - mc.Observe(err) - return err + return mc.Observe(err) } return gce.waitForGlobalOp(op, mc) @@ -73,13 +70,7 @@ func (gce *GCECloud) DeleteGlobalForwardingRule(name string) error { mc := newForwardingRuleMetricContext("delete", "") op, err := gce.service.GlobalForwardingRules.Delete(gce.projectID, name).Do() if err != nil { - if isHTTPErrorCode(err, http.StatusNotFound) { - mc.Observe(nil) - return nil - } - - mc.Observe(err) - return err + return mc.Observe(err) } return gce.waitForGlobalOp(op, mc) @@ -99,3 +90,41 @@ func (gce *GCECloud) ListGlobalForwardingRules() (*compute.ForwardingRuleList, e v, err := gce.service.GlobalForwardingRules.List(gce.projectID).Do() return v, mc.Observe(err) } + +// GetRegionForwardingRule returns the RegionalForwardingRule by name & region. +func (gce *GCECloud) GetRegionForwardingRule(name, region string) (*compute.ForwardingRule, error) { + mc := newForwardingRuleMetricContext("get", region) + v, err := gce.service.ForwardingRules.Get(gce.projectID, region, name).Do() + return v, mc.Observe(err) +} + +// ListRegionForwardingRules lists all RegionalForwardingRules in the project & region. +func (gce *GCECloud) ListRegionForwardingRules(region string) (*compute.ForwardingRuleList, error) { + mc := newForwardingRuleMetricContext("list", region) + // TODO: use PageToken to list all not just the first 500 + v, err := gce.service.ForwardingRules.List(gce.projectID, region).Do() + return v, mc.Observe(err) +} + +// CreateRegionForwardingRule creates and returns a +// RegionalForwardingRule that points to the given BackendService +func (gce *GCECloud) CreateRegionForwardingRule(rule *compute.ForwardingRule, region string) error { + mc := newForwardingRuleMetricContext("create", region) + op, err := gce.service.ForwardingRules.Insert(gce.projectID, region, rule).Do() + if err != nil { + return mc.Observe(err) + } + + return gce.waitForRegionOp(op, region, mc) +} + +// DeleteRegionForwardingRule deletes the RegionalForwardingRule by name & region. +func (gce *GCECloud) DeleteRegionForwardingRule(name, region string) error { + mc := newForwardingRuleMetricContext("delete", region) + op, err := gce.service.ForwardingRules.Delete(gce.projectID, region, name).Do() + if err != nil { + return mc.Observe(err) + } + + return gce.waitForRegionOp(op, region, mc) +} diff --git a/pkg/cloudprovider/providers/gce/gce_healthchecks.go b/pkg/cloudprovider/providers/gce/gce_healthchecks.go index 7bd060b54a7..4f5f90c6a1d 100644 --- a/pkg/cloudprovider/providers/gce/gce_healthchecks.go +++ b/pkg/cloudprovider/providers/gce/gce_healthchecks.go @@ -17,7 +17,6 @@ limitations under the License. package gce import ( - "fmt" "time" "k8s.io/kubernetes/pkg/api/v1" @@ -208,28 +207,12 @@ func GetNodesHealthCheckPort() int32 { return lbNodesHealthCheckPort } -// getNodesHealthCheckPath returns the health check path used by the GCE load +// GetNodesHealthCheckPath returns the health check path used by the GCE load // balancers (l4) for performing health checks on nodes. -func getNodesHealthCheckPath() string { +func GetNodesHealthCheckPath() string { return nodesHealthCheckPath } -// makeNodesHealthCheckName returns name of the health check resource used by -// the GCE load balancers (l4) for performing health checks on nodes. -func makeNodesHealthCheckName(clusterID string) string { - return fmt.Sprintf("k8s-%v-node", clusterID) -} - -// MakeHealthCheckFirewallName returns the firewall name used by the GCE load -// balancers (l4) for performing health checks. -func MakeHealthCheckFirewallName(clusterID, hcName string, isNodesHealthCheck bool) string { - if isNodesHealthCheck { - // TODO: Change below fwName to match the proposed schema: k8s-{clusteriD}-{namespace}-{name}-{shortid}-hc. - return makeNodesHealthCheckName(clusterID) + "-http-hc" - } - return "k8s-" + hcName + "-http-hc" -} - // isAtLeastMinNodesHealthCheckVersion checks if a version is higher than // `minNodesHealthCheckVersion`. func isAtLeastMinNodesHealthCheckVersion(vstring string) bool { diff --git a/pkg/cloudprovider/providers/gce/gce_instancegroup.go b/pkg/cloudprovider/providers/gce/gce_instancegroup.go index c25aeb1af08..f04d5676cca 100644 --- a/pkg/cloudprovider/providers/gce/gce_instancegroup.go +++ b/pkg/cloudprovider/providers/gce/gce_instancegroup.go @@ -81,20 +81,16 @@ func (gce *GCECloud) ListInstancesInInstanceGroup(name string, zone string, stat // AddInstancesToInstanceGroup adds the given instances to the given // instance group. -func (gce *GCECloud) AddInstancesToInstanceGroup(name string, zone string, instanceNames []string) error { +func (gce *GCECloud) AddInstancesToInstanceGroup(name string, zone string, instanceRefs []*compute.InstanceReference) error { mc := newInstanceGroupMetricContext("add_instances", zone) - if len(instanceNames) == 0 { + if len(instanceRefs) == 0 { return nil } - // Adding the same instance twice will result in a 4xx error - instances := []*compute.InstanceReference{} - for _, ins := range instanceNames { - instances = append(instances, &compute.InstanceReference{Instance: makeHostURL(gce.projectID, zone, ins)}) - } + op, err := gce.service.InstanceGroups.AddInstances( gce.projectID, zone, name, &compute.InstanceGroupsAddInstancesRequest{ - Instances: instances, + Instances: instanceRefs, }).Do() if err != nil { return mc.Observe(err) @@ -105,21 +101,16 @@ func (gce *GCECloud) AddInstancesToInstanceGroup(name string, zone string, insta // RemoveInstancesFromInstanceGroup removes the given instances from // the instance group. -func (gce *GCECloud) RemoveInstancesFromInstanceGroup(name string, zone string, instanceNames []string) error { +func (gce *GCECloud) RemoveInstancesFromInstanceGroup(name string, zone string, instanceRefs []*compute.InstanceReference) error { mc := newInstanceGroupMetricContext("remove_instances", zone) - if len(instanceNames) == 0 { + if len(instanceRefs) == 0 { return nil } - instances := []*compute.InstanceReference{} - for _, ins := range instanceNames { - instanceLink := makeHostURL(gce.projectID, zone, ins) - instances = append(instances, &compute.InstanceReference{Instance: instanceLink}) - } op, err := gce.service.InstanceGroups.RemoveInstances( gce.projectID, zone, name, &compute.InstanceGroupsRemoveInstancesRequest{ - Instances: instances, + Instances: instanceRefs, }).Do() if err != nil { return mc.Observe(err) diff --git a/pkg/cloudprovider/providers/gce/gce_instances.go b/pkg/cloudprovider/providers/gce/gce_instances.go index 33437a34628..a2f6125be13 100644 --- a/pkg/cloudprovider/providers/gce/gce_instances.go +++ b/pkg/cloudprovider/providers/gce/gce_instances.go @@ -28,6 +28,7 @@ import ( computealpha "google.golang.org/api/compute/v0.beta" compute "google.golang.org/api/compute/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" @@ -35,6 +36,10 @@ import ( "k8s.io/kubernetes/pkg/cloudprovider" ) +const ( + defaultZone = "" +) + func newInstancesMetricContext(request, zone string) *metricContext { return &metricContext{ start: time.Now(), @@ -42,6 +47,34 @@ func newInstancesMetricContext(request, zone string) *metricContext { } } +func splitNodesByZone(nodes []*v1.Node) map[string][]*v1.Node { + zones := make(map[string][]*v1.Node) + for _, n := range nodes { + z := getZone(n) + if z != defaultZone { + zones[z] = append(zones[z], n) + } + } + return zones +} + +func getZone(n *v1.Node) string { + zone, ok := n.Labels[metav1.LabelZoneFailureDomain] + if !ok { + return defaultZone + } + return zone +} + +// ToInstanceReferences returns instance references by links +func (gce *GCECloud) ToInstanceReferences(zone string, instanceNames []string) (refs []*compute.InstanceReference) { + for _, ins := range instanceNames { + instanceLink := makeHostURL(gce.projectID, zone, ins) + refs = append(refs, &compute.InstanceReference{Instance: instanceLink}) + } + return refs +} + // NodeAddresses is an implementation of Instances.NodeAddresses. func (gce *GCECloud) NodeAddresses(_ types.NodeName) ([]v1.NodeAddress, error) { internalIP, err := metadata.Get("instance/network-interfaces/0/ip") diff --git a/pkg/cloudprovider/providers/gce/gce_targetpool.go b/pkg/cloudprovider/providers/gce/gce_targetpool.go new file mode 100644 index 00000000000..10304bfe93b --- /dev/null +++ b/pkg/cloudprovider/providers/gce/gce_targetpool.go @@ -0,0 +1,84 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package gce + +import ( + "time" + + compute "google.golang.org/api/compute/v1" +) + +func newTargetPoolMetricContext(request, region string) *metricContext { + return &metricContext{ + start: time.Now(), + attributes: []string{"targetpool_" + request, region, unusedMetricLabel}, + } +} + +// GetTargetPool returns the TargetPool by name. +func (gce *GCECloud) GetTargetPool(name, region string) (*compute.TargetPool, error) { + mc := newTargetPoolMetricContext("get", region) + v, err := gce.service.TargetPools.Get(gce.projectID, region, name).Do() + return v, mc.Observe(err) +} + +// CreateTargetPool creates the passed TargetPool +func (gce *GCECloud) CreateTargetPool(tp *compute.TargetPool, region string) (*compute.TargetPool, error) { + mc := newTargetPoolMetricContext("create", region) + op, err := gce.service.TargetPools.Insert(gce.projectID, region, tp).Do() + if err != nil { + return nil, mc.Observe(err) + } + + if err := gce.waitForRegionOp(op, region, mc); err != nil { + return nil, err + } + + return gce.GetTargetPool(tp.Name, region) +} + +// DeleteTargetPool deletes TargetPool by name. +func (gce *GCECloud) DeleteTargetPool(name, region string) error { + mc := newTargetPoolMetricContext("delete", region) + op, err := gce.service.TargetPools.Delete(gce.projectID, region, name).Do() + if err != nil { + return mc.Observe(err) + } + return gce.waitForRegionOp(op, region, mc) +} + +// AddInstancesToTargetPool adds instances by link to the TargetPool +func (gce *GCECloud) AddInstancesToTargetPool(name, region string, instanceRefs []*compute.InstanceReference) error { + add := &compute.TargetPoolsAddInstanceRequest{Instances: instanceRefs} + mc := newTargetPoolMetricContext("add_instances", region) + op, err := gce.service.TargetPools.AddInstance(gce.projectID, region, name, add).Do() + if err != nil { + return mc.Observe(err) + } + return gce.waitForRegionOp(op, region, mc) +} + +// RemoveInstancesToTargetPool removes instances by link to the TargetPool +func (gce *GCECloud) RemoveInstancesFromTargetPool(name, region string, instanceRefs []*compute.InstanceReference) error { + remove := &compute.TargetPoolsRemoveInstanceRequest{Instances: instanceRefs} + mc := newTargetPoolMetricContext("remove_instances", region) + op, err := gce.service.TargetPools.RemoveInstance(gce.projectID, region, name, remove).Do() + if err != nil { + return mc.Observe(err) + } + return gce.waitForRegionOp(op, region, mc) +} diff --git a/pkg/cloudprovider/providers/gce/gce_util.go b/pkg/cloudprovider/providers/gce/gce_util.go index 90b51759f22..bcbd523c889 100644 --- a/pkg/cloudprovider/providers/gce/gce_util.go +++ b/pkg/cloudprovider/providers/gce/gce_util.go @@ -134,3 +134,18 @@ func equalStringSets(x, y []string) bool { yString := sets.NewString(y...) return xString.Equal(yString) } + +func isNotFound(err error) bool { + return isHTTPErrorCode(err, http.StatusNotFound) +} + +func ignoreNotFound(err error) error { + if err == nil || isNotFound(err) { + return nil + } + return err +} + +func isNotFoundOrInUse(err error) bool { + return isNotFound(err) || isInUsedByError(err) +} diff --git a/pkg/cloudprovider/providers/gce/gce_zones.go b/pkg/cloudprovider/providers/gce/gce_zones.go index c8cec5694fb..881fe652fc1 100644 --- a/pkg/cloudprovider/providers/gce/gce_zones.go +++ b/pkg/cloudprovider/providers/gce/gce_zones.go @@ -16,11 +16,41 @@ limitations under the License. package gce -import "k8s.io/kubernetes/pkg/cloudprovider" +import ( + "fmt" + "time" + compute "google.golang.org/api/compute/v1" + + "k8s.io/kubernetes/pkg/cloudprovider" +) + +func newZonesMetricContext(request, region string) *metricContext { + return &metricContext{ + start: time.Now(), + attributes: []string{"zones_" + request, region, unusedMetricLabel}, + } +} + +// GetZone creates a cloudprovider.Zone of the current zone and region func (gce *GCECloud) GetZone() (cloudprovider.Zone, error) { return cloudprovider.Zone{ FailureDomain: gce.localZone, Region: gce.region, }, nil } + +// ListZonesInRegion returns all zones in a GCP region +func (gce *GCECloud) ListZonesInRegion(region string) ([]*compute.Zone, error) { + mc := newZonesMetricContext("list", region) + filter := fmt.Sprintf("region eq %v", gce.getRegionLink(region)) + list, err := gce.service.Zones.List(gce.projectID).Filter(filter).Do() + if err != nil { + return nil, mc.Observe(err) + } + return list.Items, mc.Observe(err) +} + +func (gce *GCECloud) getRegionLink(region string) string { + return fmt.Sprintf("https://www.googleapis.com/compute/v1/projects/%v/regions/%v", gce.projectID, region) +}