mirror of https://github.com/k3s-io/k3s
205 lines
7.2 KiB
Go
205 lines
7.2 KiB
Go
|
/*
|
||
|
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 (
|
||
|
"context"
|
||
|
"flag"
|
||
|
"fmt"
|
||
|
"net"
|
||
|
"sort"
|
||
|
"strings"
|
||
|
|
||
|
"k8s.io/api/core/v1"
|
||
|
"k8s.io/klog"
|
||
|
|
||
|
"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud"
|
||
|
cloudprovider "k8s.io/cloud-provider"
|
||
|
utilnet "k8s.io/utils/net"
|
||
|
)
|
||
|
|
||
|
type cidrs struct {
|
||
|
ipn utilnet.IPNetSet
|
||
|
isSet bool
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
lbSrcRngsFlag cidrs
|
||
|
)
|
||
|
|
||
|
func init() {
|
||
|
var err error
|
||
|
// LB L7 proxies and all L3/4/7 health checkers have client addresses within these known CIDRs.
|
||
|
lbSrcRngsFlag.ipn, err = utilnet.ParseIPNets([]string{"130.211.0.0/22", "35.191.0.0/16", "209.85.152.0/22", "209.85.204.0/22"}...)
|
||
|
if err != nil {
|
||
|
panic("Incorrect default GCE L7 source ranges")
|
||
|
}
|
||
|
|
||
|
flag.Var(&lbSrcRngsFlag, "cloud-provider-gce-lb-src-cidrs", "CIDRs opened in GCE firewall for LB traffic proxy & health checks")
|
||
|
}
|
||
|
|
||
|
// String is the method to format the flag's value, part of the flag.Value interface.
|
||
|
func (c *cidrs) String() string {
|
||
|
s := c.ipn.StringSlice()
|
||
|
sort.Strings(s)
|
||
|
return strings.Join(s, ",")
|
||
|
}
|
||
|
|
||
|
// Set supports a value of CSV or the flag repeated multiple times
|
||
|
func (c *cidrs) Set(value string) error {
|
||
|
// On first Set(), clear the original defaults
|
||
|
if !c.isSet {
|
||
|
c.isSet = true
|
||
|
c.ipn = make(utilnet.IPNetSet)
|
||
|
} else {
|
||
|
return fmt.Errorf("GCE LB CIDRs have already been set")
|
||
|
}
|
||
|
|
||
|
for _, cidr := range strings.Split(value, ",") {
|
||
|
_, ipnet, err := net.ParseCIDR(cidr)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
c.ipn.Insert(ipnet)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// LoadBalancerSrcRanges contains the ranges of ips used by the GCE load balancers (l4 & L7)
|
||
|
// for proxying client requests and performing health checks.
|
||
|
func LoadBalancerSrcRanges() []string {
|
||
|
return lbSrcRngsFlag.ipn.StringSlice()
|
||
|
}
|
||
|
|
||
|
// GetLoadBalancer is an implementation of LoadBalancer.GetLoadBalancer
|
||
|
func (g *Cloud) GetLoadBalancer(ctx context.Context, clusterName string, svc *v1.Service) (*v1.LoadBalancerStatus, bool, error) {
|
||
|
loadBalancerName := g.GetLoadBalancerName(ctx, clusterName, svc)
|
||
|
fwd, err := g.GetRegionForwardingRule(loadBalancerName, g.region)
|
||
|
if err == nil {
|
||
|
status := &v1.LoadBalancerStatus{}
|
||
|
status.Ingress = []v1.LoadBalancerIngress{{IP: fwd.IPAddress}}
|
||
|
|
||
|
return status, true, nil
|
||
|
}
|
||
|
return nil, false, ignoreNotFound(err)
|
||
|
}
|
||
|
|
||
|
// GetLoadBalancerName is an implementation of LoadBalancer.GetLoadBalancerName.
|
||
|
func (g *Cloud) GetLoadBalancerName(ctx context.Context, clusterName string, svc *v1.Service) string {
|
||
|
// TODO: replace DefaultLoadBalancerName to generate more meaningful loadbalancer names.
|
||
|
return cloudprovider.DefaultLoadBalancerName(svc)
|
||
|
}
|
||
|
|
||
|
// EnsureLoadBalancer is an implementation of LoadBalancer.EnsureLoadBalancer.
|
||
|
func (g *Cloud) EnsureLoadBalancer(ctx context.Context, clusterName string, svc *v1.Service, nodes []*v1.Node) (*v1.LoadBalancerStatus, error) {
|
||
|
loadBalancerName := g.GetLoadBalancerName(ctx, clusterName, svc)
|
||
|
desiredScheme := getSvcScheme(svc)
|
||
|
clusterID, err := g.ClusterID.GetID()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
klog.V(4).Infof("EnsureLoadBalancer(%v, %v, %v, %v, %v): ensure %v loadbalancer", clusterName, svc.Namespace, svc.Name, loadBalancerName, g.region, desiredScheme)
|
||
|
|
||
|
existingFwdRule, err := g.GetRegionForwardingRule(loadBalancerName, g.region)
|
||
|
if err != nil && !isNotFound(err) {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if existingFwdRule != nil {
|
||
|
existingScheme := cloud.LbScheme(strings.ToUpper(existingFwdRule.LoadBalancingScheme))
|
||
|
|
||
|
// If the loadbalancer type changes between INTERNAL and EXTERNAL, the old load balancer should be deleted.
|
||
|
if existingScheme != desiredScheme {
|
||
|
klog.V(4).Infof("EnsureLoadBalancer(%v, %v, %v, %v, %v): deleting existing %v loadbalancer", clusterName, svc.Namespace, svc.Name, loadBalancerName, g.region, existingScheme)
|
||
|
switch existingScheme {
|
||
|
case cloud.SchemeInternal:
|
||
|
err = g.ensureInternalLoadBalancerDeleted(clusterName, clusterID, svc)
|
||
|
default:
|
||
|
err = g.ensureExternalLoadBalancerDeleted(clusterName, clusterID, svc)
|
||
|
}
|
||
|
klog.V(4).Infof("EnsureLoadBalancer(%v, %v, %v, %v, %v): done deleting existing %v loadbalancer. err: %v", clusterName, svc.Namespace, svc.Name, loadBalancerName, g.region, existingScheme, err)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
// Assume the ensureDeleted function successfully deleted the forwarding rule.
|
||
|
existingFwdRule = nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var status *v1.LoadBalancerStatus
|
||
|
switch desiredScheme {
|
||
|
case cloud.SchemeInternal:
|
||
|
status, err = g.ensureInternalLoadBalancer(clusterName, clusterID, svc, existingFwdRule, nodes)
|
||
|
default:
|
||
|
status, err = g.ensureExternalLoadBalancer(clusterName, clusterID, svc, existingFwdRule, nodes)
|
||
|
}
|
||
|
klog.V(4).Infof("EnsureLoadBalancer(%v, %v, %v, %v, %v): done ensuring loadbalancer. err: %v", clusterName, svc.Namespace, svc.Name, loadBalancerName, g.region, err)
|
||
|
return status, err
|
||
|
}
|
||
|
|
||
|
// UpdateLoadBalancer is an implementation of LoadBalancer.UpdateLoadBalancer.
|
||
|
func (g *Cloud) UpdateLoadBalancer(ctx context.Context, clusterName string, svc *v1.Service, nodes []*v1.Node) error {
|
||
|
loadBalancerName := g.GetLoadBalancerName(ctx, clusterName, svc)
|
||
|
scheme := getSvcScheme(svc)
|
||
|
clusterID, err := g.ClusterID.GetID()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
klog.V(4).Infof("UpdateLoadBalancer(%v, %v, %v, %v, %v): updating with %d nodes", clusterName, svc.Namespace, svc.Name, loadBalancerName, g.region, len(nodes))
|
||
|
|
||
|
switch scheme {
|
||
|
case cloud.SchemeInternal:
|
||
|
err = g.updateInternalLoadBalancer(clusterName, clusterID, svc, nodes)
|
||
|
default:
|
||
|
err = g.updateExternalLoadBalancer(clusterName, svc, nodes)
|
||
|
}
|
||
|
klog.V(4).Infof("UpdateLoadBalancer(%v, %v, %v, %v, %v): done updating. err: %v", clusterName, svc.Namespace, svc.Name, loadBalancerName, g.region, err)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// EnsureLoadBalancerDeleted is an implementation of LoadBalancer.EnsureLoadBalancerDeleted.
|
||
|
func (g *Cloud) EnsureLoadBalancerDeleted(ctx context.Context, clusterName string, svc *v1.Service) error {
|
||
|
loadBalancerName := g.GetLoadBalancerName(ctx, clusterName, svc)
|
||
|
scheme := getSvcScheme(svc)
|
||
|
clusterID, err := g.ClusterID.GetID()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
klog.V(4).Infof("EnsureLoadBalancerDeleted(%v, %v, %v, %v, %v): deleting loadbalancer", clusterName, svc.Namespace, svc.Name, loadBalancerName, g.region)
|
||
|
|
||
|
switch scheme {
|
||
|
case cloud.SchemeInternal:
|
||
|
err = g.ensureInternalLoadBalancerDeleted(clusterName, clusterID, svc)
|
||
|
default:
|
||
|
err = g.ensureExternalLoadBalancerDeleted(clusterName, clusterID, svc)
|
||
|
}
|
||
|
klog.V(4).Infof("EnsureLoadBalancerDeleted(%v, %v, %v, %v, %v): done deleting loadbalancer. err: %v", clusterName, svc.Namespace, svc.Name, loadBalancerName, g.region, err)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func getSvcScheme(svc *v1.Service) cloud.LbScheme {
|
||
|
if typ, ok := GetLoadBalancerAnnotationType(svc); ok && typ == LBTypeInternal {
|
||
|
return cloud.SchemeInternal
|
||
|
}
|
||
|
return cloud.SchemeExternal
|
||
|
}
|