Merge pull request #31028 from mwielgus/secret-fix

Automatic merge from submit-queue

Handle secret namespace and data properly in federated secret controller

This PR fixes what was missed in #30669 review. It uses both namespace and secret name for keying and propagates secret data to underlying clusters.

cc: @quinton-hoole @kshafiee @kubernetes/sig-cluster-federation
This commit is contained in:
Kubernetes Submit Queue 2016-08-19 15:47:11 -07:00 committed by GitHub
commit 9bc8240f1a
2 changed files with 52 additions and 22 deletions

View File

@ -17,6 +17,7 @@ limitations under the License.
package secret package secret
import ( import (
"fmt"
"reflect" "reflect"
"time" "time"
@ -159,8 +160,8 @@ func (secretcontroller *SecretController) Run(stopChan <-chan struct{}) {
secretcontroller.secretFederatedInformer.Stop() secretcontroller.secretFederatedInformer.Stop()
}() }()
secretcontroller.secretDeliverer.StartWithHandler(func(item *util.DelayingDelivererItem) { secretcontroller.secretDeliverer.StartWithHandler(func(item *util.DelayingDelivererItem) {
secret := item.Value.(string) secret := item.Value.(*secretItem)
secretcontroller.reconcileSecret(secret) secretcontroller.reconcileSecret(secret.namespace, secret.name)
}) })
secretcontroller.clusterDeliverer.StartWithHandler(func(_ *util.DelayingDelivererItem) { secretcontroller.clusterDeliverer.StartWithHandler(func(_ *util.DelayingDelivererItem) {
secretcontroller.reconcileSecretsOnClusterChange() secretcontroller.reconcileSecretsOnClusterChange()
@ -175,20 +176,32 @@ func (secretcontroller *SecretController) Run(stopChan <-chan struct{}) {
}() }()
} }
func getSecretKey(namespace, name string) string {
return fmt.Sprintf("%s/%s", namespace, name)
}
// Internal structure for data in delaying deliverer.
type secretItem struct {
namespace string
name string
}
func (secretcontroller *SecretController) deliverSecretObj(obj interface{}, delay time.Duration, failed bool) { func (secretcontroller *SecretController) deliverSecretObj(obj interface{}, delay time.Duration, failed bool) {
secret := obj.(*api_v1.Secret) secret := obj.(*api_v1.Secret)
secretcontroller.deliverSecret(secret.Name, delay, failed) secretcontroller.deliverSecret(secret.Namespace, secret.Name, delay, failed)
} }
// Adds backoff to delay if this delivery is related to some failure. Resets backoff if there was no failure. // Adds backoff to delay if this delivery is related to some failure. Resets backoff if there was no failure.
func (secretcontroller *SecretController) deliverSecret(secret string, delay time.Duration, failed bool) { func (secretcontroller *SecretController) deliverSecret(namespace string, name string, delay time.Duration, failed bool) {
key := getSecretKey(namespace, name)
if failed { if failed {
secretcontroller.secretBackoff.Next(secret, time.Now()) secretcontroller.secretBackoff.Next(key, time.Now())
delay = delay + secretcontroller.secretBackoff.Get(secret) delay = delay + secretcontroller.secretBackoff.Get(key)
} else { } else {
secretcontroller.secretBackoff.Reset(secret) secretcontroller.secretBackoff.Reset(key)
} }
secretcontroller.secretDeliverer.DeliverAfter(secret, secret, delay) secretcontroller.secretDeliverer.DeliverAfter(key,
&secretItem{namespace: namespace, name: name}, delay)
} }
// Check whether all data stores are in sync. False is returned if any of the informer/stores is not yet // Check whether all data stores are in sync. False is returned if any of the informer/stores is not yet
@ -216,20 +229,22 @@ func (secretcontroller *SecretController) reconcileSecretsOnClusterChange() {
} }
for _, obj := range secretcontroller.secretInformerStore.List() { for _, obj := range secretcontroller.secretInformerStore.List() {
secret := obj.(*api_v1.Secret) secret := obj.(*api_v1.Secret)
secretcontroller.deliverSecret(secret.Name, secretcontroller.smallDelay, false) secretcontroller.deliverSecret(secret.Namespace, secret.Name, secretcontroller.smallDelay, false)
} }
} }
func (secretcontroller *SecretController) reconcileSecret(secret string) { func (secretcontroller *SecretController) reconcileSecret(namespace string, secretName string) {
if !secretcontroller.isSynced() { if !secretcontroller.isSynced() {
secretcontroller.deliverSecret(secret, secretcontroller.clusterAvailableDelay, false) secretcontroller.deliverSecret(namespace, secretName, secretcontroller.clusterAvailableDelay, false)
return return
} }
baseSecretObj, exist, err := secretcontroller.secretInformerStore.GetByKey(secret) key := getSecretKey(namespace, secretName)
baseSecretObj, exist, err := secretcontroller.secretInformerStore.GetByKey(key)
if err != nil { if err != nil {
glog.Errorf("Failed to query main secret store for %v: %v", secret, err) glog.Errorf("Failed to query main secret store for %v: %v", key, err)
secretcontroller.deliverSecret(secret, 0, true) secretcontroller.deliverSecret(namespace, secretName, 0, true)
return return
} }
@ -242,21 +257,23 @@ func (secretcontroller *SecretController) reconcileSecret(secret string) {
clusters, err := secretcontroller.secretFederatedInformer.GetReadyClusters() clusters, err := secretcontroller.secretFederatedInformer.GetReadyClusters()
if err != nil { if err != nil {
glog.Errorf("Failed to get cluster list: %v", err) glog.Errorf("Failed to get cluster list: %v", err)
secretcontroller.deliverSecret(secret, secretcontroller.clusterAvailableDelay, false) secretcontroller.deliverSecret(namespace, secretName, secretcontroller.clusterAvailableDelay, false)
return return
} }
operations := make([]util.FederatedOperation, 0) operations := make([]util.FederatedOperation, 0)
for _, cluster := range clusters { for _, cluster := range clusters {
clusterSecretObj, found, err := secretcontroller.secretFederatedInformer.GetTargetStore().GetByKey(cluster.Name, secret) clusterSecretObj, found, err := secretcontroller.secretFederatedInformer.GetTargetStore().GetByKey(cluster.Name, key)
if err != nil { if err != nil {
glog.Errorf("Failed to get %s from %s: %v", secret, cluster.Name, err) glog.Errorf("Failed to get %s from %s: %v", key, cluster.Name, err)
secretcontroller.deliverSecret(secret, 0, true) secretcontroller.deliverSecret(namespace, secretName, 0, true)
return return
} }
desiredSecret := &api_v1.Secret{ desiredSecret := &api_v1.Secret{
ObjectMeta: baseSecret.ObjectMeta, ObjectMeta: baseSecret.ObjectMeta,
Data: baseSecret.Data,
Type: baseSecret.Type,
} }
if !found { if !found {
@ -285,11 +302,11 @@ func (secretcontroller *SecretController) reconcileSecret(secret string) {
} }
err = secretcontroller.federatedUpdater.Update(operations, secretcontroller.updateTimeout) err = secretcontroller.federatedUpdater.Update(operations, secretcontroller.updateTimeout)
if err != nil { if err != nil {
glog.Errorf("Failed to execute updates for %s: %v", secret, err) glog.Errorf("Failed to execute updates for %s: %v", key, err)
secretcontroller.deliverSecret(secret, 0, true) secretcontroller.deliverSecret(namespace, secretName, 0, true)
return return
} }
// Evertyhing is in order but lets be double sure // Evertyhing is in order but lets be double sure
secretcontroller.deliverSecret(secret, secretcontroller.secretReviewDelay, false) secretcontroller.deliverSecret(namespace, secretName, secretcontroller.secretReviewDelay, false)
} }

View File

@ -18,6 +18,7 @@ package secret
import ( import (
"fmt" "fmt"
"reflect"
"testing" "testing"
"time" "time"
@ -77,15 +78,23 @@ func TestSecretController(t *testing.T) {
secret1 := api_v1.Secret{ secret1 := api_v1.Secret{
ObjectMeta: api_v1.ObjectMeta{ ObjectMeta: api_v1.ObjectMeta{
Name: "test-secret", Name: "test-secret",
Namespace: "mynamespace",
}, },
Data: map[string][]byte{
"A": []byte("ala ma kota"),
"B": []byte("quick brown fox"),
},
Type: api_v1.SecretTypeOpaque,
} }
// Test add federated secret. // Test add federated secret.
secretWatch.Add(&secret1) secretWatch.Add(&secret1)
createdSecret := GetSecretFromChan(cluster1CreateChan) createdSecret := GetSecretFromChan(cluster1CreateChan)
assert.NotNil(t, createdSecret) assert.NotNil(t, createdSecret)
assert.Equal(t, secret1.Namespace, createdSecret.Namespace)
assert.Equal(t, secret1.Name, createdSecret.Name) assert.Equal(t, secret1.Name, createdSecret.Name)
assert.True(t, reflect.DeepEqual(&secret1, createdSecret))
// Test update federated secret. // Test update federated secret.
secret1.Annotations = map[string]string{ secret1.Annotations = map[string]string{
@ -95,12 +104,16 @@ func TestSecretController(t *testing.T) {
updatedSecret := GetSecretFromChan(cluster1UpdateChan) updatedSecret := GetSecretFromChan(cluster1UpdateChan)
assert.NotNil(t, updatedSecret) assert.NotNil(t, updatedSecret)
assert.Equal(t, secret1.Name, updatedSecret.Name) assert.Equal(t, secret1.Name, updatedSecret.Name)
assert.Equal(t, secret1.Namespace, updatedSecret.Namespace)
assert.True(t, reflect.DeepEqual(&secret1, updatedSecret))
// Test add cluster // Test add cluster
clusterWatch.Add(cluster2) clusterWatch.Add(cluster2)
createdSecret2 := GetSecretFromChan(cluster2CreateChan) createdSecret2 := GetSecretFromChan(cluster2CreateChan)
assert.NotNil(t, createdSecret2) assert.NotNil(t, createdSecret2)
assert.Equal(t, secret1.Name, createdSecret2.Name) assert.Equal(t, secret1.Name, createdSecret2.Name)
assert.Equal(t, secret1.Namespace, createdSecret2.Namespace)
assert.True(t, reflect.DeepEqual(&secret1, createdSecret2))
close(stop) close(stop)
} }