Don't wrongly identify endpoint addresses only due to equal IP

Before this patch the endpoint IP was used to identify endpoint addresses. This
leads to wrong unification of endpoints of different pods having the same IP (e.g.
non container IP in case of Mesos). This patch takes the EndpointAddress.targetRef.UID
into consideration as well.
This commit is contained in:
Dr. Stefan Schimanski 2015-06-26 12:23:21 +02:00
parent 67d45821f8
commit 55daf3b80e

View File

@ -24,6 +24,7 @@ import (
"sort" "sort"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util"
) )
@ -33,31 +34,35 @@ import (
// form for things like comparison. The result is a newly allocated slice. // form for things like comparison. The result is a newly allocated slice.
func RepackSubsets(subsets []api.EndpointSubset) []api.EndpointSubset { func RepackSubsets(subsets []api.EndpointSubset) []api.EndpointSubset {
// First map each unique port definition to the sets of hosts that // First map each unique port definition to the sets of hosts that
// offer it. The sets of hosts must be de-duped, using IP as the key. // offer it. The sets of hosts must be de-duped, using IP+UID as the key.
type ipString string type addressKey struct {
allAddrs := map[ipString]*api.EndpointAddress{} ip string
uid types.UID
}
allAddrs := map[addressKey]*api.EndpointAddress{}
portsToAddrs := map[api.EndpointPort]addressSet{} portsToAddrs := map[api.EndpointPort]addressSet{}
for i := range subsets { for i := range subsets {
for j := range subsets[i].Ports { for j := range subsets[i].Ports {
epp := &subsets[i].Ports[j] epp := &subsets[i].Ports[j]
for k := range subsets[i].Addresses { for k := range subsets[i].Addresses {
epa := &subsets[i].Addresses[k] epa := &subsets[i].Addresses[k]
ipstr := ipString(epa.IP) ak := addressKey{ip: epa.IP}
// Accumulate the most "complete" address we can. if epa.TargetRef != nil {
if allAddrs[ipstr] == nil { ak.uid = epa.TargetRef.UID
}
// Accumulate the address.
if allAddrs[ak] == nil {
// Make a copy so we don't write to the // Make a copy so we don't write to the
// input args of this function. // input args of this function.
p := &api.EndpointAddress{} p := &api.EndpointAddress{}
*p = *epa *p = *epa
allAddrs[ipstr] = p allAddrs[ak] = p
} else if allAddrs[ipstr].TargetRef == nil {
allAddrs[ipstr].TargetRef = epa.TargetRef
} }
// Remember that this port maps to this address. // Remember that this port maps to this address.
if _, found := portsToAddrs[*epp]; !found { if _, found := portsToAddrs[*epp]; !found {
portsToAddrs[*epp] = addressSet{} portsToAddrs[*epp] = addressSet{}
} }
portsToAddrs[*epp].Insert(allAddrs[ipstr]) portsToAddrs[*epp].Insert(allAddrs[ak])
} }
} }
} }
@ -104,18 +109,32 @@ func hashAddresses(addrs addressSet) string {
for k := range addrs { for k := range addrs {
slice = append(slice, k) slice = append(slice, k)
} }
sort.Sort(addrPtrsByIP(slice)) sort.Sort(addrPtrsByIpAndUID(slice))
hasher := md5.New() hasher := md5.New()
util.DeepHashObject(hasher, slice) util.DeepHashObject(hasher, slice)
return hex.EncodeToString(hasher.Sum(nil)[0:]) return hex.EncodeToString(hasher.Sum(nil)[0:])
} }
type addrPtrsByIP []*api.EndpointAddress func LessEndpointAddress(a, b *api.EndpointAddress) bool {
ipComparison := bytes.Compare([]byte(a.IP), []byte(b.IP))
if ipComparison != 0 {
return ipComparison < 0
}
if (b.TargetRef == nil) {
return false
}
if (a.TargetRef == nil) {
return true
}
return a.TargetRef.UID < b.TargetRef.UID
}
func (sl addrPtrsByIP) Len() int { return len(sl) } type addrPtrsByIpAndUID []*api.EndpointAddress
func (sl addrPtrsByIP) Swap(i, j int) { sl[i], sl[j] = sl[j], sl[i] }
func (sl addrPtrsByIP) Less(i, j int) bool { func (sl addrPtrsByIpAndUID) Len() int { return len(sl) }
return bytes.Compare([]byte(sl[i].IP), []byte(sl[j].IP)) < 0 func (sl addrPtrsByIpAndUID) Swap(i, j int) { sl[i], sl[j] = sl[j], sl[i] }
func (sl addrPtrsByIpAndUID) Less(i, j int) bool {
return LessEndpointAddress(sl[i], sl[j])
} }
// SortSubsets sorts an array of EndpointSubset objects in place. For ease of // SortSubsets sorts an array of EndpointSubset objects in place. For ease of
@ -123,7 +142,7 @@ func (sl addrPtrsByIP) Less(i, j int) bool {
func SortSubsets(subsets []api.EndpointSubset) []api.EndpointSubset { func SortSubsets(subsets []api.EndpointSubset) []api.EndpointSubset {
for i := range subsets { for i := range subsets {
ss := &subsets[i] ss := &subsets[i]
sort.Sort(addrsByIP(ss.Addresses)) sort.Sort(addrsByIpAndUID(ss.Addresses))
sort.Sort(portsByHash(ss.Ports)) sort.Sort(portsByHash(ss.Ports))
} }
sort.Sort(subsetsByHash(subsets)) sort.Sort(subsetsByHash(subsets))
@ -146,12 +165,12 @@ func (sl subsetsByHash) Less(i, j int) bool {
return bytes.Compare(h1, h2) < 0 return bytes.Compare(h1, h2) < 0
} }
type addrsByIP []api.EndpointAddress type addrsByIpAndUID []api.EndpointAddress
func (sl addrsByIP) Len() int { return len(sl) } func (sl addrsByIpAndUID) Len() int { return len(sl) }
func (sl addrsByIP) Swap(i, j int) { sl[i], sl[j] = sl[j], sl[i] } func (sl addrsByIpAndUID) Swap(i, j int) { sl[i], sl[j] = sl[j], sl[i] }
func (sl addrsByIP) Less(i, j int) bool { func (sl addrsByIpAndUID) Less(i, j int) bool {
return bytes.Compare([]byte(sl[i].IP), []byte(sl[j].IP)) < 0 return LessEndpointAddress(&sl[i], &sl[j])
} }
type portsByHash []api.EndpointPort type portsByHash []api.EndpointPort