Commit fac6318c authored by Quinton Hoole's avatar Quinton Hoole

Federated Ingress: unify UID's across Cluster Ingress Controllers

Fixes #31180
parent ac8aae58
...@@ -162,7 +162,7 @@ func (d *DelayingDeliverer) DeliverAfter(key string, value interface{}, delay ti ...@@ -162,7 +162,7 @@ func (d *DelayingDeliverer) DeliverAfter(key string, value interface{}, delay ti
d.DeliverAt(key, value, time.Now().Add(delay)) d.DeliverAt(key, value, time.Now().Add(delay))
} }
// Gets target chanel of the deliverer. // Gets target channel of the deliverer.
func (d *DelayingDeliverer) GetTargetChannel() chan *DelayingDelivererItem { func (d *DelayingDeliverer) GetTargetChannel() chan *DelayingDelivererItem {
return d.targetChannel return d.targetChannel
} }
......
...@@ -85,9 +85,9 @@ type FederationView interface { ...@@ -85,9 +85,9 @@ type FederationView interface {
ClustersSynced() bool ClustersSynced() bool
} }
// A structure that combines an informer running agains federated api server and listening for cluster updates // A structure that combines an informer running against federated api server and listening for cluster updates
// with multiple Kubernetes API informers (called target informers) running against federation members. Whenever a new // with multiple Kubernetes API informers (called target informers) running against federation members. Whenever a new
// cluster is added to the federation an informer is created for it using TargetInformerFactory. Infomrers are stoped // cluster is added to the federation an informer is created for it using TargetInformerFactory. Informers are stopped
// when a cluster is either put offline of deleted. It is assumed that some controller keeps an eye on the cluster list // when a cluster is either put offline of deleted. It is assumed that some controller keeps an eye on the cluster list
// and thus the clusters in ETCD are up to date. // and thus the clusters in ETCD are up to date.
type FederatedInformer interface { type FederatedInformer interface {
...@@ -186,18 +186,22 @@ func NewFederatedInformer( ...@@ -186,18 +186,22 @@ func NewFederatedInformer(
if clusterLifecycle.ClusterAvailable != nil { if clusterLifecycle.ClusterAvailable != nil {
clusterLifecycle.ClusterAvailable(curCluster) clusterLifecycle.ClusterAvailable(curCluster)
} }
} else {
glog.Errorf("Cluster %v not added. Not of correct type, or cluster not ready.", cur)
} }
}, },
UpdateFunc: func(old, cur interface{}) { UpdateFunc: func(old, cur interface{}) {
oldCluster, ok := old.(*federation_api.Cluster) oldCluster, ok := old.(*federation_api.Cluster)
if !ok { if !ok {
glog.Errorf("Internal error: Cluster %v not updated. Old cluster not of correct type.", old)
return return
} }
curCluster, ok := cur.(*federation_api.Cluster) curCluster, ok := cur.(*federation_api.Cluster)
if !ok { if !ok {
glog.Errorf("Internal error: Cluster %v not updated. New cluster not of correct type.", cur)
return return
} }
if isClusterReady(oldCluster) != isClusterReady(curCluster) || !reflect.DeepEqual(oldCluster.Spec, curCluster.Spec) { if isClusterReady(oldCluster) != isClusterReady(curCluster) || !reflect.DeepEqual(oldCluster.Spec, curCluster.Spec) || !reflect.DeepEqual(oldCluster.ObjectMeta.Annotations, curCluster.ObjectMeta.Annotations) {
var data []interface{} var data []interface{}
if clusterLifecycle.ClusterUnavailable != nil { if clusterLifecycle.ClusterUnavailable != nil {
data = getClusterData(oldCluster.Name) data = getClusterData(oldCluster.Name)
...@@ -213,6 +217,8 @@ func NewFederatedInformer( ...@@ -213,6 +217,8 @@ func NewFederatedInformer(
clusterLifecycle.ClusterAvailable(curCluster) clusterLifecycle.ClusterAvailable(curCluster)
} }
} }
} else {
glog.V(4).Infof("Cluster %v not updated to %v as ready status and specs are identical", oldCluster, curCluster)
} }
}, },
}, },
...@@ -258,11 +264,14 @@ type federatedStoreImpl struct { ...@@ -258,11 +264,14 @@ type federatedStoreImpl struct {
} }
func (f *federatedInformerImpl) Stop() { func (f *federatedInformerImpl) Stop() {
glog.V(4).Infof("Stopping federated informer.")
f.Lock() f.Lock()
defer f.Unlock() defer f.Unlock()
glog.V(4).Infof("... Closing cluster informer channel.")
close(f.clusterInformer.stopChan) close(f.clusterInformer.stopChan)
for _, informer := range f.targetInformers { for key, informer := range f.targetInformers {
glog.V(4).Infof("... Closing informer channel for %q.", key)
close(informer.stopChan) close(informer.stopChan)
} }
} }
...@@ -291,14 +300,16 @@ func (f *federatedInformerImpl) GetClientsetForCluster(clusterName string) (kube ...@@ -291,14 +300,16 @@ func (f *federatedInformerImpl) GetClientsetForCluster(clusterName string) (kube
func (f *federatedInformerImpl) getClientsetForClusterUnlocked(clusterName string) (kube_release_1_4.Interface, error) { func (f *federatedInformerImpl) getClientsetForClusterUnlocked(clusterName string) (kube_release_1_4.Interface, error) {
// No locking needed. Will happen in f.GetCluster. // No locking needed. Will happen in f.GetCluster.
glog.V(4).Infof("Getting clientset for cluster %q", clusterName)
if cluster, found, err := f.getReadyClusterUnlocked(clusterName); found && err == nil { if cluster, found, err := f.getReadyClusterUnlocked(clusterName); found && err == nil {
glog.V(4).Infof("Got clientset for cluster %q", clusterName)
return f.clientFactory(cluster) return f.clientFactory(cluster)
} else { } else {
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
return nil, fmt.Errorf("cluster %s not found", clusterName) return nil, fmt.Errorf("cluster %q not found", clusterName)
} }
// GetReadyClusers returns all clusters for which the sub-informers are run. // GetReadyClusers returns all clusters for which the sub-informers are run.
...@@ -441,7 +452,7 @@ func (fs *federatedStoreImpl) GetFromAllClusters(key string) ([]FederatedObject, ...@@ -441,7 +452,7 @@ func (fs *federatedStoreImpl) GetFromAllClusters(key string) ([]FederatedObject,
return result, nil return result, nil
} }
// GetKey for returns the key under which the item would be put in the store. // GetKeyFor returns the key under which the item would be put in the store.
func (fs *federatedStoreImpl) GetKeyFor(item interface{}) string { func (fs *federatedStoreImpl) GetKeyFor(item interface{}) string {
// TODO: support other keying functions. // TODO: support other keying functions.
key, _ := framework.DeletionHandlingMetaNamespaceKeyFunc(item) key, _ := framework.DeletionHandlingMetaNamespaceKeyFunc(item)
......
...@@ -64,10 +64,14 @@ func (wd *WatcherDispatcher) Add(obj runtime.Object) { ...@@ -64,10 +64,14 @@ func (wd *WatcherDispatcher) Add(obj runtime.Object) {
func (wd *WatcherDispatcher) Modify(obj runtime.Object) { func (wd *WatcherDispatcher) Modify(obj runtime.Object) {
wd.Lock() wd.Lock()
defer wd.Unlock() defer wd.Unlock()
glog.V(4).Infof("->WatcherDispatcher.Modify(%v)", obj)
wd.eventsSoFar = append(wd.eventsSoFar, &watch.Event{Type: watch.Modified, Object: obj}) wd.eventsSoFar = append(wd.eventsSoFar, &watch.Event{Type: watch.Modified, Object: obj})
for _, watcher := range wd.watchers { for i, watcher := range wd.watchers {
if !watcher.IsStopped() { if !watcher.IsStopped() {
glog.V(4).Infof("->Watcher(%d).Modify(%v)", i, obj)
watcher.Modify(obj) watcher.Modify(obj)
} else {
glog.V(4).Infof("->Watcher(%d) is stopped. Not calling Modify(%v)", i, obj)
} }
} }
} }
...@@ -173,7 +177,7 @@ func GetObjectFromChan(c chan runtime.Object) runtime.Object { ...@@ -173,7 +177,7 @@ func GetObjectFromChan(c chan runtime.Object) runtime.Object {
select { select {
case obj := <-c: case obj := <-c:
return obj return obj
case <-time.After(10 * time.Second): case <-time.After(20 * time.Second):
pprof.Lookup("goroutine").WriteTo(os.Stderr, 1) pprof.Lookup("goroutine").WriteTo(os.Stderr, 1)
return nil return nil
} }
......
/*
Copyright 2016 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 util
import (
"reflect"
"k8s.io/kubernetes/pkg/api/v1"
)
/*
ObjectMetaIsEquivalent determines whether two ObjectMeta's (typically one from a federated API object,
and the other from a cluster object) are equivalent.
*/
func ObjectMetaIsEquivalent(m1, m2 v1.ObjectMeta) bool {
// First make all of the read-only fields equal, then perform a deep equality comparison
m1.SelfLink = m2.SelfLink // Might be different in different cluster contexts.
m1.UID = m2.UID // Definitely different in different cluster contexts
m1.ResourceVersion = m2.ResourceVersion // Definitely different in different cluster contexts
m1.Generation = m2.Generation // Might be different in different cluster contexts.
m1.CreationTimestamp = m2.CreationTimestamp // Definitely different in different cluster contexts.
m1.DeletionTimestamp = m2.DeletionTimestamp // Might be different in different cluster contexts.
m1.OwnerReferences = nil // Might be different in different cluster contexts.
m2.OwnerReferences = nil
m1.Finalizers = nil // Might be different in different cluster contexts.
m2.Finalizers = nil
return reflect.DeepEqual(m1, m2)
}
...@@ -20,6 +20,8 @@ import ( ...@@ -20,6 +20,8 @@ import (
"sync" "sync"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"github.com/golang/glog"
) )
// Interface can be implemented by anything that knows how to watch and report changes. // Interface can be implemented by anything that knows how to watch and report changes.
...@@ -100,6 +102,7 @@ func (f *FakeWatcher) Stop() { ...@@ -100,6 +102,7 @@ func (f *FakeWatcher) Stop() {
f.Lock() f.Lock()
defer f.Unlock() defer f.Unlock()
if !f.Stopped { if !f.Stopped {
glog.V(4).Infof("Stopping fake watcher.")
close(f.result) close(f.result)
f.Stopped = true f.Stopped = true
} }
......
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