Commit 4faf7f1f authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #46663 from nicksardo/gce-internallb

Automatic merge from submit-queue (batch tested with PRs 46550, 46663, 46816, 46820, 46460) [GCE] Support internal load balancers **What this PR does / why we need it**: Allows users to expose K8s services externally of the K8s cluster but within their GCP network. Fixes #33483 **Important User Notes:** - This is a beta feature. ILB could be enabled differently in the future. - Requires nodes having version 1.7.0+ (ILB requires health checking and a health check endpoint on kube-proxy has just been exposed) - This cannot be used for intra-cluster communication. Do not call the load balancer IP from a K8s node/pod. - There is no reservation system for private IPs. You can specify a RFC 1918 address in `loadBalancerIP` field, but it could be lost to another VM or LB if service settings are modified. - If you're running an ingress, your existing loadbalancer backend service must be using BalancingMode type `RATE` - not `UTILIZATION`. - Option 1: With a 1.5.8+ or 1.6.4+ version master, delete all your ingresses, and re-create them. - Option 2: Migrate to a new cluster running 1.7.0. Considering ILB requires nodes with 1.7.0, this isn't a bad idea. - Option 3: Possible migration opportunity, but use at your own risk. More to come later. **Reviewer Notes**: Several files were renamed, so github thinks ~2k lines have changed. Review commits one-by-one to see the actual changes. **Release note**: ```release-note Support creation of GCP Internal Load Balancers from Service objects ```
parents 7bbc615b 025f178b
......@@ -13,6 +13,8 @@ go_library(
srcs = [
"doc.go",
"gce.go",
"gce_addresses.go",
"gce_annotations.go",
"gce_backendservice.go",
"gce_cert.go",
"gce_clusterid.go",
......@@ -24,9 +26,12 @@ go_library(
"gce_instancegroup.go",
"gce_instances.go",
"gce_loadbalancer.go",
"gce_loadbalancer_external.go",
"gce_loadbalancer_internal.go",
"gce_loadbalancer_naming.go",
"gce_op.go",
"gce_routes.go",
"gce_staticip.go",
"gce_targetpool.go",
"gce_targetproxy.go",
"gce_urlmap.go",
"gce_util.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
......
......@@ -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)
}
/*
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 "k8s.io/kubernetes/pkg/api/v1"
type LoadBalancerType string
const (
// ServiceAnnotationLoadBalancerType is the annotation used on a service with type LoadBalancer
// dictates what specific kind of GCP LB should be assembled.
// Currently, only "internal" is supported.
ServiceAnnotationLoadBalancerType = "cloud.google.com/load-balancer-type"
LBTypeInternal LoadBalancerType = "internal"
)
// GetLoadBalancerAnnotationType returns the type of GCP load balancer which should be assembled.
func GetLoadBalancerAnnotationType(service *v1.Service) (LoadBalancerType, bool) {
v := LoadBalancerType("")
if service.Spec.Type != v1.ServiceTypeLoadBalancer {
return v, false
}
l, ok := service.Annotations[ServiceAnnotationLoadBalancerType]
v = LoadBalancerType(l)
if !ok {
return v, false
}
switch v {
case LBTypeInternal:
return v, true
default:
return v, false
}
}
......@@ -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)
......
......@@ -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)
}
......@@ -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 {
......
......@@ -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)
......
......@@ -33,6 +33,11 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/cloudprovider"
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
)
const (
defaultZone = ""
)
func newInstancesMetricContext(request, zone string) *metricContext {
......@@ -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[kubeletapis.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")
......
/*
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 (
"fmt"
"strings"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/api/v1"
)
// Internal Load Balancer
// Instance groups remain legacy named to stay consistent with ingress
func makeInstanceGroupName(clusterID string) string {
return fmt.Sprintf("k8s-ig--%s", clusterID)
}
func makeBackendServiceName(loadBalancerName, clusterID string, shared bool, scheme lbScheme, protocol v1.Protocol, svcAffinity v1.ServiceAffinity) string {
if shared {
affinity := ""
switch svcAffinity {
case v1.ServiceAffinityClientIP:
affinity = "clientip"
default:
affinity = "noaffinity"
}
return fmt.Sprintf("k8s-%s-%s-%s-%s", clusterID, strings.ToLower(string(scheme)), strings.ToLower(string(protocol)), affinity)
}
return loadBalancerName
}
func makeHealthCheckName(loadBalancerName, clusterID string, shared bool) string {
if shared {
return fmt.Sprintf("k8s-%s-node", clusterID)
}
return loadBalancerName
}
func makeHealthCheckFirewallkNameFromHC(healthCheckName string) string {
return healthCheckName + "-hc"
}
func makeHealthCheckFirewallkName(loadBalancerName, clusterID string, shared bool) string {
if shared {
return fmt.Sprintf("k8s-%s-node-hc", clusterID)
}
return loadBalancerName + "-hc"
}
func makeBackendServiceDescription(nm types.NamespacedName, shared bool) string {
if shared {
return ""
}
return fmt.Sprintf(`{"kubernetes.io/service-name":"%s"`, nm.String())
}
// External Load Balancer
// 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)
}
func makeHealthCheckDescription(serviceName string) string {
return fmt.Sprintf(`{"kubernetes.io/service-name":"%s"}`, serviceName)
}
// 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 {
return makeNodesHealthCheckName(clusterID) + "-http-hc"
}
return "k8s-" + hcName + "-http-hc"
}
func makeFirewallName(name string) string {
return fmt.Sprintf("k8s-fw-%s", name)
}
func makeFirewallDescription(serviceName, ipAddress string) string {
return fmt.Sprintf(`{"kubernetes.io/service-name":"%s", "kubernetes.io/service-ip":"%s"}`,
serviceName, ipAddress)
}
/*
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)
}
......@@ -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)
}
......@@ -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)
}
......@@ -717,9 +717,10 @@ func (cont *GCEIngressController) Init() {
// invoking deleteStaticIPs.
func (cont *GCEIngressController) CreateStaticIP(name string) string {
gceCloud := cont.Cloud.Provider.(*gcecloud.GCECloud)
ip, err := gceCloud.ReserveGlobalStaticIP(name, "")
addr := &compute.Address{Name: name}
ip, err := gceCloud.ReserveGlobalAddress(addr)
if err != nil {
if delErr := gceCloud.DeleteGlobalStaticIP(name); delErr != nil {
if delErr := gceCloud.DeleteGlobalAddress(name); delErr != nil {
if cont.isHTTPErrorCode(delErr, http.StatusNotFound) {
Logf("Static ip with name %v was not allocated, nothing to delete", name)
} else {
......
......@@ -5167,20 +5167,15 @@ func CleanupGCEResources(loadBalancerName string) (retErr error) {
!IsGoogleAPIHTTPErrorCode(err, http.StatusNotFound) {
retErr = err
}
if err := gceCloud.DeleteForwardingRule(loadBalancerName); err != nil &&
if err := gceCloud.DeleteRegionForwardingRule(loadBalancerName, gceCloud.Region()); err != nil &&
!IsGoogleAPIHTTPErrorCode(err, http.StatusNotFound) {
retErr = fmt.Errorf("%v\n%v", retErr, err)
}
if err := gceCloud.DeleteGlobalStaticIP(loadBalancerName); err != nil &&
if err := gceCloud.DeleteRegionAddress(loadBalancerName, gceCloud.Region()); err != nil &&
!IsGoogleAPIHTTPErrorCode(err, http.StatusNotFound) {
retErr = fmt.Errorf("%v\n%v", retErr, err)
}
// This function shells out to gcloud, so we can't compare for NotFound errors.
// TODO: Invoke cloudprovider method directly instead.
if err := DeleteGCEStaticIP(loadBalancerName); err != nil {
Logf("%v", err)
}
var hcNames []string
hc, getErr := gceCloud.GetHttpHealthCheck(loadBalancerName)
if getErr != nil && !IsGoogleAPIHTTPErrorCode(getErr, http.StatusNotFound) {
......@@ -5190,7 +5185,7 @@ func CleanupGCEResources(loadBalancerName string) (retErr error) {
if hc != nil {
hcNames = append(hcNames, hc.Name)
}
if err := gceCloud.DeleteTargetPool(loadBalancerName, hcNames...); err != nil &&
if err := gceCloud.DeleteExternalTargetPoolAndChecks(loadBalancerName, gceCloud.Region(), hcNames...); err != nil &&
!IsGoogleAPIHTTPErrorCode(err, http.StatusNotFound) {
retErr = fmt.Errorf("%v\n%v", retErr, err)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment