Allow a user specified global static ip via annotation.

This commit is contained in:
Prashanth Balasubramanian 2016-03-09 19:29:23 -08:00
parent 4409bed106
commit 3ee943d434
6 changed files with 235 additions and 41 deletions

View file

@ -22,6 +22,7 @@ import (
compute "google.golang.org/api/compute/v1"
"k8s.io/contrib/ingress/controllers/gce/utils"
"k8s.io/kubernetes/pkg/util/sets"
)
var testIPManager = testIP{}
@ -148,6 +149,17 @@ func (f *FakeLoadBalancers) DeleteGlobalForwardingRule(name string) error {
return nil
}
// GetForwardingRulesWithIPs returns all forwarding rules that match the given ips.
func (f *FakeLoadBalancers) GetForwardingRulesWithIPs(ip []string) (fwRules []*compute.ForwardingRule) {
ipSet := sets.NewString(ip...)
for i := range f.Fw {
if ipSet.Has(f.Fw[i].IPAddress) {
fwRules = append(fwRules, f.Fw[i])
}
}
return fwRules
}
// UrlMaps fakes
// GetUrlMap fakes getting url maps from the cloud.

View file

@ -22,6 +22,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"reflect"
"strings"
compute "google.golang.org/api/compute/v1"
@ -130,6 +131,11 @@ func (l *L7s) Add(ri *L7RuntimeInfo) (err error) {
if err != nil {
return err
}
} else {
if !reflect.DeepEqual(lb.runtimeInfo, ri) {
glog.Infof("LB %v runtime info changed, old %+v new %+v", lb.Name, lb.runtimeInfo, ri)
lb.runtimeInfo = ri
}
}
// Add the lb to the pool, in case we create an UrlMap but run out
// of quota in creating the ForwardingRule we still need to cleanup
@ -242,6 +248,9 @@ type L7RuntimeInfo struct {
// AllowHTTP will not setup :80, if TLS is nil and AllowHTTP is set,
// no loadbalancer is created.
AllowHTTP bool
// The name of a Global Static IP. If specified, the IP associated with
// this name is used in the Forwarding Rules for this loadbalancer.
StaticIPName string
}
// L7 represents a single L7 loadbalancer.
@ -413,15 +422,50 @@ func (l *L7) checkForwardingRule(name, proxyLink, ip, portRange string) (fw *com
return fw, nil
}
// getEffectiveIP returns a string with the IP to use in the HTTP and HTTPS
// forwarding rules, and a boolean indicating if this is an IP the controller
// should manage or not.
func (l *L7) getEffectiveIP() (string, bool) {
// A note on IP management:
// User specifies a different IP on startup:
// - We create a forwarding rule with the given IP.
// - If this ip doesn't exist in GCE, we create another one in the hope
// that they will rectify it later on.
// - In the happy case, no static ip is created or deleted by this controller.
// Controller allocates a staticIP/ephemeralIP, but user changes it:
// - We still delete the old static IP, but only when we tear down the
// Ingress in Cleanup(). Till then the static IP stays around, but
// the forwarding rules get deleted/created with the new IP.
// - There will be a period of downtime as we flip IPs.
// User specifies the same static IP to 2 Ingresses:
// - GCE will throw a 400, and the controller will keep trying to use
// the IP in the hope that the user manually resolves the conflict
// or deletes/modifies the Ingress.
// TODO: Handle the last case better.
if l.runtimeInfo.StaticIPName != "" {
// Existing static IPs allocated to forwarding rules will get orphaned
// till the Ingress is torn down.
if ip, err := l.cloud.GetGlobalStaticIP(l.runtimeInfo.StaticIPName); err != nil || ip == nil {
glog.Warningf("The given static IP name %v doesn't translate to an existing global static IP, ignoring it and allocating a new IP: %v",
l.runtimeInfo.StaticIPName, err)
} else {
return ip.Address, false
}
}
if l.ip != nil {
return l.ip.Address, true
}
return "", true
}
func (l *L7) checkHttpForwardingRule() (err error) {
if l.tp == nil {
return fmt.Errorf("Cannot create forwarding rule without proxy.")
}
var address string
if l.ip != nil {
address = l.ip.Address
}
name := l.namer.Truncate(fmt.Sprintf("%v-%v", forwardingRulePrefix, l.Name))
address, _ := l.getEffectiveIP()
fw, err := l.checkForwardingRule(name, l.tp.SelfLink, address, httpDefaultPortRange)
if err != nil {
return err
@ -435,11 +479,8 @@ func (l *L7) checkHttpsForwardingRule() (err error) {
glog.V(3).Infof("No https target proxy for %v, not created https forwarding rule", l.Name)
return nil
}
var address string
if l.ip != nil {
address = l.ip.Address
}
name := l.namer.Truncate(fmt.Sprintf("%v-%v", httpsForwardingRulePrefix, l.Name))
address, _ := l.getEffectiveIP()
fws, err := l.checkForwardingRule(name, l.tps.SelfLink, address, httpsDefaultPortRange)
if err != nil {
return err
@ -448,10 +489,16 @@ func (l *L7) checkHttpsForwardingRule() (err error) {
return nil
}
// checkStaticIP reserves a static IP allocated to the Forwarding Rule.
func (l *L7) checkStaticIP() (err error) {
if l.fw == nil || l.fw.IPAddress == "" {
return fmt.Errorf("Will not create static IP without a forwarding rule.")
}
// Don't manage staticIPs if the user has specified an IP.
if address, manageStaticIP := l.getEffectiveIP(); !manageStaticIP {
glog.V(3).Infof("Not managing user specified static IP %v", address)
return nil
}
staticIPName := l.namer.Truncate(fmt.Sprintf("%v-%v", forwardingRulePrefix, l.Name))
ip, _ := l.cloud.GetGlobalStaticIP(staticIPName)
if ip == nil {