Ejemplo n.º 1
0
func (configmapcontroller *ConfigMapController) reconcileConfigMap(configmap types.NamespacedName) {

	if !configmapcontroller.isSynced() {
		glog.V(4).Infof("Configmap controller not synced")
		configmapcontroller.deliverConfigMap(configmap, configmapcontroller.clusterAvailableDelay, false)
		return
	}

	key := configmap.String()
	baseConfigMapObj, exist, err := configmapcontroller.configmapInformerStore.GetByKey(key)
	if err != nil {
		glog.Errorf("Failed to query main configmap store for %v: %v", key, err)
		configmapcontroller.deliverConfigMap(configmap, 0, true)
		return
	}

	if !exist {
		// Not federated configmap, ignoring.
		glog.V(8).Infof("Skipping not federated config map: %s", key)
		return
	}
	baseConfigMap := baseConfigMapObj.(*apiv1.ConfigMap)

	clusters, err := configmapcontroller.configmapFederatedInformer.GetReadyClusters()
	if err != nil {
		glog.Errorf("Failed to get cluster list: %v, retrying shortly", err)
		configmapcontroller.deliverConfigMap(configmap, configmapcontroller.clusterAvailableDelay, false)
		return
	}

	operations := make([]util.FederatedOperation, 0)
	for _, cluster := range clusters {
		clusterConfigMapObj, found, err := configmapcontroller.configmapFederatedInformer.GetTargetStore().GetByKey(cluster.Name, key)
		if err != nil {
			glog.Errorf("Failed to get %s from %s: %v, retrying shortly", key, cluster.Name, err)
			configmapcontroller.deliverConfigMap(configmap, 0, true)
			return
		}

		// Do not modify data.
		desiredConfigMap := &apiv1.ConfigMap{
			ObjectMeta: util.DeepCopyRelevantObjectMeta(baseConfigMap.ObjectMeta),
			Data:       baseConfigMap.Data,
		}

		if !found {
			configmapcontroller.eventRecorder.Eventf(baseConfigMap, api.EventTypeNormal, "CreateInCluster",
				"Creating configmap in cluster %s", cluster.Name)

			operations = append(operations, util.FederatedOperation{
				Type:        util.OperationTypeAdd,
				Obj:         desiredConfigMap,
				ClusterName: cluster.Name,
			})
		} else {
			clusterConfigMap := clusterConfigMapObj.(*apiv1.ConfigMap)

			// Update existing configmap, if needed.
			if !util.ConfigMapEquivalent(desiredConfigMap, clusterConfigMap) {
				configmapcontroller.eventRecorder.Eventf(baseConfigMap, api.EventTypeNormal, "UpdateInCluster",
					"Updating configmap in cluster %s", cluster.Name)
				operations = append(operations, util.FederatedOperation{
					Type:        util.OperationTypeUpdate,
					Obj:         desiredConfigMap,
					ClusterName: cluster.Name,
				})
			}
		}
	}

	if len(operations) == 0 {
		// Everything is in order
		glog.V(8).Infof("No operations needed for %s", key)
		return
	}
	err = configmapcontroller.federatedUpdater.UpdateWithOnError(operations, configmapcontroller.updateTimeout,
		func(op util.FederatedOperation, operror error) {
			configmapcontroller.eventRecorder.Eventf(baseConfigMap, api.EventTypeNormal, "UpdateInClusterFailed",
				"ConfigMap update in cluster %s failed: %v", op.ClusterName, operror)
		})

	if err != nil {
		glog.Errorf("Failed to execute updates for %s: %v, retrying shortly", key, err)
		configmapcontroller.deliverConfigMap(configmap, 0, true)
		return
	}
}
func TestConfigMapController(t *testing.T) {
	cluster1 := NewCluster("cluster1", apiv1.ConditionTrue)
	cluster2 := NewCluster("cluster2", apiv1.ConditionTrue)

	fakeClient := &fakefedclientset.Clientset{}
	RegisterFakeList("clusters", &fakeClient.Fake, &federationapi.ClusterList{Items: []federationapi.Cluster{*cluster1}})
	RegisterFakeList("configmaps", &fakeClient.Fake, &apiv1.ConfigMapList{Items: []apiv1.ConfigMap{}})
	configmapWatch := RegisterFakeWatch("configmaps", &fakeClient.Fake)
	clusterWatch := RegisterFakeWatch("clusters", &fakeClient.Fake)

	cluster1Client := &fakekubeclientset.Clientset{}
	cluster1Watch := RegisterFakeWatch("configmaps", &cluster1Client.Fake)
	RegisterFakeList("configmaps", &cluster1Client.Fake, &apiv1.ConfigMapList{Items: []apiv1.ConfigMap{}})
	cluster1CreateChan := RegisterFakeCopyOnCreate("configmaps", &cluster1Client.Fake, cluster1Watch)
	cluster1UpdateChan := RegisterFakeCopyOnUpdate("configmaps", &cluster1Client.Fake, cluster1Watch)

	cluster2Client := &fakekubeclientset.Clientset{}
	cluster2Watch := RegisterFakeWatch("configmaps", &cluster2Client.Fake)
	RegisterFakeList("configmaps", &cluster2Client.Fake, &apiv1.ConfigMapList{Items: []apiv1.ConfigMap{}})
	cluster2CreateChan := RegisterFakeCopyOnCreate("configmaps", &cluster2Client.Fake, cluster2Watch)

	configmapController := NewConfigMapController(fakeClient)
	informer := ToFederatedInformerForTestOnly(configmapController.configmapFederatedInformer)
	informer.SetClientFactory(func(cluster *federationapi.Cluster) (kubeclientset.Interface, error) {
		switch cluster.Name {
		case cluster1.Name:
			return cluster1Client, nil
		case cluster2.Name:
			return cluster2Client, nil
		default:
			return nil, fmt.Errorf("Unknown cluster")
		}
	})

	configmapController.clusterAvailableDelay = time.Second
	configmapController.configmapReviewDelay = 50 * time.Millisecond
	configmapController.smallDelay = 20 * time.Millisecond
	configmapController.updateTimeout = 5 * time.Second

	stop := make(chan struct{})
	configmapController.Run(stop)

	configmap1 := &apiv1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "test-configmap",
			Namespace: "ns",
			SelfLink:  "/api/v1/namespaces/ns/configmaps/test-configmap",
		},
		Data: map[string]string{
			"A": "ala ma kota",
			"B": "quick brown fox",
		},
	}

	// Test add federated configmap.
	configmapWatch.Add(configmap1)
	createdConfigMap := GetConfigMapFromChan(cluster1CreateChan)
	assert.NotNil(t, createdConfigMap)
	assert.Equal(t, configmap1.Namespace, createdConfigMap.Namespace)
	assert.Equal(t, configmap1.Name, createdConfigMap.Name)
	assert.True(t, util.ConfigMapEquivalent(configmap1, createdConfigMap))

	// Wait for the configmap to appear in the informer store
	err := WaitForStoreUpdate(
		configmapController.configmapFederatedInformer.GetTargetStore(),
		cluster1.Name, types.NamespacedName{Namespace: configmap1.Namespace, Name: configmap1.Name}.String(), wait.ForeverTestTimeout)
	assert.Nil(t, err, "configmap should have appeared in the informer store")

	// Test update federated configmap.
	configmap1.Annotations = map[string]string{
		"A": "B",
	}
	configmapWatch.Modify(configmap1)
	updatedConfigMap := GetConfigMapFromChan(cluster1UpdateChan)
	assert.NotNil(t, updatedConfigMap)
	assert.Equal(t, configmap1.Name, updatedConfigMap.Name)
	assert.Equal(t, configmap1.Namespace, updatedConfigMap.Namespace)
	assert.True(t, util.ConfigMapEquivalent(configmap1, updatedConfigMap))

	// Test update federated configmap.
	configmap1.Data = map[string]string{
		"config": "myconfigurationfile",
	}
	configmapWatch.Modify(configmap1)
	updatedConfigMap2 := GetConfigMapFromChan(cluster1UpdateChan)
	assert.NotNil(t, updatedConfigMap)
	assert.Equal(t, configmap1.Name, updatedConfigMap.Name)
	assert.Equal(t, configmap1.Namespace, updatedConfigMap.Namespace)
	assert.True(t, util.ConfigMapEquivalent(configmap1, updatedConfigMap2))

	// Test add cluster
	clusterWatch.Add(cluster2)
	createdConfigMap2 := GetConfigMapFromChan(cluster2CreateChan)
	assert.NotNil(t, createdConfigMap2)
	assert.Equal(t, configmap1.Name, createdConfigMap2.Name)
	assert.Equal(t, configmap1.Namespace, createdConfigMap2.Namespace)
	assert.True(t, util.ConfigMapEquivalent(configmap1, createdConfigMap2))

	close(stop)
}