Commit 406c79cf authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #46260 from perotinus/depsyncconv2

Automatic merge from submit-queue (batch tested with PRs 47619, 47951, 46260, 48277) [Federation] Convert the deployment controller to a sync controller. This is based off of the work done for the ReplicaSet controller. It extracts out a schedulingAdapter that handles the shared logic between the two controllers. Targets #40989 **Release note**: ```release-note NONE ```
parents a7a84124 90ee0c4e
......@@ -23,7 +23,6 @@ go_library(
"//federation/pkg/dnsprovider/providers/google/clouddns:go_default_library",
"//federation/pkg/federatedtypes:go_default_library",
"//federation/pkg/federation-controller/cluster:go_default_library",
"//federation/pkg/federation-controller/deployment:go_default_library",
"//federation/pkg/federation-controller/ingress:go_default_library",
"//federation/pkg/federation-controller/namespace:go_default_library",
"//federation/pkg/federation-controller/service:go_default_library",
......
......@@ -37,7 +37,6 @@ import (
"k8s.io/kubernetes/federation/cmd/federation-controller-manager/app/options"
"k8s.io/kubernetes/federation/pkg/federatedtypes"
clustercontroller "k8s.io/kubernetes/federation/pkg/federation-controller/cluster"
deploymentcontroller "k8s.io/kubernetes/federation/pkg/federation-controller/deployment"
ingresscontroller "k8s.io/kubernetes/federation/pkg/federation-controller/ingress"
namespacecontroller "k8s.io/kubernetes/federation/pkg/federation-controller/namespace"
servicecontroller "k8s.io/kubernetes/federation/pkg/federation-controller/service"
......@@ -166,15 +165,6 @@ func StartControllers(s *options.CMServer, restClientCfg *restclient.Config) err
}
}
if controllerEnabled(s.Controllers, serverResources, deploymentcontroller.ControllerName, deploymentcontroller.RequiredResources, true) {
glog.V(3).Infof("Loading client config for deployment controller %q", deploymentcontroller.UserAgentName)
deploymentClientset := federationclientset.NewForConfigOrDie(restclient.AddUserAgent(restClientCfg, deploymentcontroller.UserAgentName))
deploymentController := deploymentcontroller.NewDeploymentController(deploymentClientset)
glog.V(3).Infof("Running deployment controller")
// TODO: rename s.ConcurrentReplicaSetSyncs
go deploymentController.Run(s.ConcurrentReplicaSetSyncs, wait.NeverStop)
}
if controllerEnabled(s.Controllers, serverResources, ingresscontroller.ControllerName, ingresscontroller.RequiredResources, true) {
glog.V(3).Infof("Loading client config for ingress controller %q", ingresscontroller.UserAgentName)
ingClientset := federationclientset.NewForConfigOrDie(restclient.AddUserAgent(restClientCfg, ingresscontroller.UserAgentName))
......
......@@ -14,6 +14,7 @@ go_library(
"adapter.go",
"configmap.go",
"daemonset.go",
"deployment.go",
"registry.go",
"replicaset.go",
"scheduling.go",
......@@ -32,6 +33,7 @@ go_library(
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
......@@ -58,7 +60,7 @@ filegroup(
go_test(
name = "go_default_test",
srcs = ["replicaset_test.go"],
srcs = ["scheduling_test.go"],
library = ":go_default_library",
tags = ["automanaged"],
deps = [
......@@ -66,5 +68,6 @@ go_test(
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
],
)
/*
Copyright 2017 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 federatedtypes
import (
apiv1 "k8s.io/api/core/v1"
extensionsv1 "k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
pkgruntime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/watch"
federationclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
fedutil "k8s.io/kubernetes/federation/pkg/federation-controller/util"
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
)
const (
DeploymentKind = "deployment"
DeploymentControllerName = "deployments"
FedDeploymentPreferencesAnnotation = "federation.kubernetes.io/deployment-preferences"
)
func init() {
RegisterFederatedType(DeploymentKind, DeploymentControllerName, []schema.GroupVersionResource{extensionsv1.SchemeGroupVersion.WithResource(DeploymentControllerName)}, NewDeploymentAdapter)
}
type DeploymentAdapter struct {
*schedulingAdapter
client federationclientset.Interface
}
func NewDeploymentAdapter(client federationclientset.Interface) FederatedTypeAdapter {
schedulingAdapter := schedulingAdapter{
preferencesAnnotationName: FedDeploymentPreferencesAnnotation,
updateStatusFunc: func(obj pkgruntime.Object, status SchedulingStatus) error {
deployment := obj.(*extensionsv1.Deployment)
if status.Replicas != deployment.Status.Replicas || status.UpdatedReplicas != deployment.Status.UpdatedReplicas ||
status.ReadyReplicas != deployment.Status.ReadyReplicas || status.AvailableReplicas != deployment.Status.AvailableReplicas {
deployment.Status = extensionsv1.DeploymentStatus{
Replicas: status.Replicas,
UpdatedReplicas: status.UpdatedReplicas,
ReadyReplicas: status.ReadyReplicas,
AvailableReplicas: status.AvailableReplicas,
}
_, err := client.Extensions().Deployments(deployment.Namespace).UpdateStatus(deployment)
return err
}
return nil
},
}
return &DeploymentAdapter{&schedulingAdapter, client}
}
func (a *DeploymentAdapter) Kind() string {
return DeploymentKind
}
func (a *DeploymentAdapter) ObjectType() pkgruntime.Object {
return &extensionsv1.Deployment{}
}
func (a *DeploymentAdapter) IsExpectedType(obj interface{}) bool {
_, ok := obj.(*extensionsv1.Deployment)
return ok
}
func (a *DeploymentAdapter) Copy(obj pkgruntime.Object) pkgruntime.Object {
deployment := obj.(*extensionsv1.Deployment)
return fedutil.DeepCopyDeployment(deployment)
}
func (a *DeploymentAdapter) Equivalent(obj1, obj2 pkgruntime.Object) bool {
deployment1 := obj1.(*extensionsv1.Deployment)
deployment2 := obj2.(*extensionsv1.Deployment)
return fedutil.DeploymentEquivalent(deployment1, deployment2)
}
func (a *DeploymentAdapter) NamespacedName(obj pkgruntime.Object) types.NamespacedName {
deployment := obj.(*extensionsv1.Deployment)
return types.NamespacedName{Namespace: deployment.Namespace, Name: deployment.Name}
}
func (a *DeploymentAdapter) ObjectMeta(obj pkgruntime.Object) *metav1.ObjectMeta {
return &obj.(*extensionsv1.Deployment).ObjectMeta
}
func (a *DeploymentAdapter) FedCreate(obj pkgruntime.Object) (pkgruntime.Object, error) {
deployment := obj.(*extensionsv1.Deployment)
return a.client.Extensions().Deployments(deployment.Namespace).Create(deployment)
}
func (a *DeploymentAdapter) FedDelete(namespacedName types.NamespacedName, options *metav1.DeleteOptions) error {
return a.client.Extensions().Deployments(namespacedName.Namespace).Delete(namespacedName.Name, options)
}
func (a *DeploymentAdapter) FedGet(namespacedName types.NamespacedName) (pkgruntime.Object, error) {
return a.client.Extensions().Deployments(namespacedName.Namespace).Get(namespacedName.Name, metav1.GetOptions{})
}
func (a *DeploymentAdapter) FedList(namespace string, options metav1.ListOptions) (pkgruntime.Object, error) {
return a.client.Extensions().Deployments(namespace).List(options)
}
func (a *DeploymentAdapter) FedUpdate(obj pkgruntime.Object) (pkgruntime.Object, error) {
deployment := obj.(*extensionsv1.Deployment)
return a.client.Extensions().Deployments(deployment.Namespace).Update(deployment)
}
func (a *DeploymentAdapter) FedWatch(namespace string, options metav1.ListOptions) (watch.Interface, error) {
return a.client.Extensions().Deployments(namespace).Watch(options)
}
func (a *DeploymentAdapter) ClusterCreate(client kubeclientset.Interface, obj pkgruntime.Object) (pkgruntime.Object, error) {
deployment := obj.(*extensionsv1.Deployment)
return client.Extensions().Deployments(deployment.Namespace).Create(deployment)
}
func (a *DeploymentAdapter) ClusterDelete(client kubeclientset.Interface, nsName types.NamespacedName, options *metav1.DeleteOptions) error {
return client.Extensions().Deployments(nsName.Namespace).Delete(nsName.Name, options)
}
func (a *DeploymentAdapter) ClusterGet(client kubeclientset.Interface, namespacedName types.NamespacedName) (pkgruntime.Object, error) {
return client.Extensions().Deployments(namespacedName.Namespace).Get(namespacedName.Name, metav1.GetOptions{})
}
func (a *DeploymentAdapter) ClusterList(client kubeclientset.Interface, namespace string, options metav1.ListOptions) (pkgruntime.Object, error) {
return client.Extensions().Deployments(namespace).List(options)
}
func (a *DeploymentAdapter) ClusterUpdate(client kubeclientset.Interface, obj pkgruntime.Object) (pkgruntime.Object, error) {
deployment := obj.(*extensionsv1.Deployment)
return client.Extensions().Deployments(deployment.Namespace).Update(deployment)
}
func (a *DeploymentAdapter) ClusterWatch(client kubeclientset.Interface, namespace string, options metav1.ListOptions) (watch.Interface, error) {
return client.Extensions().Deployments(namespace).Watch(options)
}
func (a *DeploymentAdapter) EquivalentIgnoringSchedule(obj1, obj2 pkgruntime.Object) bool {
deployment1 := obj1.(*extensionsv1.Deployment)
deployment2 := a.Copy(obj2).(*extensionsv1.Deployment)
deployment2.Spec.Replicas = deployment1.Spec.Replicas
return fedutil.DeploymentEquivalent(deployment1, deployment2)
}
func (a *DeploymentAdapter) NewTestObject(namespace string) pkgruntime.Object {
replicas := int32(3)
zero := int64(0)
return &extensionsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "test-deployment-",
Namespace: namespace,
},
Spec: extensionsv1.DeploymentSpec{
Replicas: &replicas,
Template: apiv1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{"foo": "bar"},
},
Spec: apiv1.PodSpec{
TerminationGracePeriodSeconds: &zero,
Containers: []apiv1.Container{
{
Name: "nginx",
Image: "nginx",
},
},
},
},
},
}
}
......@@ -17,15 +17,31 @@ limitations under the License.
package federatedtypes
import (
"bytes"
"fmt"
"reflect"
"sort"
"time"
apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
pkgruntime "k8s.io/apimachinery/pkg/runtime"
fedapi "k8s.io/kubernetes/federation/apis/federation"
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
fedutil "k8s.io/kubernetes/federation/pkg/federation-controller/util"
"k8s.io/kubernetes/federation/pkg/federation-controller/util/planner"
"k8s.io/kubernetes/federation/pkg/federation-controller/util/podanalyzer"
"k8s.io/kubernetes/federation/pkg/federation-controller/util/replicapreferences"
"github.com/golang/glog"
)
// SchedulingStatus contains the status of the objects that are being
// scheduled into joined clusters.
type SchedulingStatus struct {
Replicas int32
UpdatedReplicas int32
FullyLabeledReplicas int32
ReadyReplicas int32
AvailableReplicas int32
......@@ -49,3 +65,171 @@ type SchedulingAdapter interface {
// equivalent ignoring differences due to scheduling.
EquivalentIgnoringSchedule(obj1, obj2 pkgruntime.Object) bool
}
// schedulingAdapter is meant to be embedded in other type adapters that require
// workload scheduling.
type schedulingAdapter struct {
preferencesAnnotationName string
updateStatusFunc func(pkgruntime.Object, SchedulingStatus) error
}
func (a *schedulingAdapter) IsSchedulingAdapter() bool {
return true
}
func (a *schedulingAdapter) GetSchedule(obj pkgruntime.Object, key string, clusters []*federationapi.Cluster, informer fedutil.FederatedInformer) (*SchedulingInfo, error) {
var clusterNames []string
for _, cluster := range clusters {
clusterNames = append(clusterNames, cluster.Name)
}
// Schedule the pods across the existing clusters.
objectGetter := func(clusterName, key string) (interface{}, bool, error) {
return informer.GetTargetStore().GetByKey(clusterName, key)
}
podsGetter := func(clusterName string, obj pkgruntime.Object) (*apiv1.PodList, error) {
clientset, err := informer.GetClientsetForCluster(clusterName)
if err != nil {
return nil, err
}
selectorObj := reflect.ValueOf(obj).Elem().FieldByName("Spec").FieldByName("Selector").Interface().(*metav1.LabelSelector)
selector, err := metav1.LabelSelectorAsSelector(selectorObj)
if err != nil {
return nil, fmt.Errorf("invalid selector: %v", err)
}
metadata, err := meta.Accessor(obj)
if err != nil {
return nil, err
}
return clientset.Core().Pods(metadata.GetNamespace()).List(metav1.ListOptions{LabelSelector: selector.String()})
}
currentReplicasPerCluster, estimatedCapacity, err := clustersReplicaState(clusterNames, key, objectGetter, podsGetter)
if err != nil {
return nil, err
}
fedPref, err := replicapreferences.GetAllocationPreferences(obj, a.preferencesAnnotationName)
if err != nil {
glog.Info("Invalid workload-type specific preference, using default. object: %v, err: %v", obj, err)
}
if fedPref == nil {
fedPref = &fedapi.ReplicaAllocationPreferences{
Clusters: map[string]fedapi.ClusterPreferences{
"*": {Weight: 1},
},
}
}
plnr := planner.NewPlanner(fedPref)
return &SchedulingInfo{
Schedule: schedule(plnr, obj, key, clusterNames, currentReplicasPerCluster, estimatedCapacity),
Status: SchedulingStatus{},
}, nil
}
func (a *schedulingAdapter) ScheduleObject(cluster *federationapi.Cluster, clusterObj pkgruntime.Object, federationObjCopy pkgruntime.Object, schedulingInfo *SchedulingInfo) (pkgruntime.Object, bool, error) {
replicas, ok := schedulingInfo.Schedule[cluster.Name]
if !ok {
replicas = 0
}
specReplicas := int32(replicas)
reflect.ValueOf(federationObjCopy).Elem().FieldByName("Spec").FieldByName("Replicas").Set(reflect.ValueOf(&specReplicas))
if clusterObj != nil {
schedulingStatusVal := reflect.ValueOf(schedulingInfo).Elem().FieldByName("Status")
objStatusVal := reflect.ValueOf(clusterObj).Elem().FieldByName("Status")
for i := 0; i < schedulingStatusVal.NumField(); i++ {
schedulingStatusField := schedulingStatusVal.Field(i)
schedulingStatusFieldName := schedulingStatusVal.Type().Field(i).Name
objStatusField := objStatusVal.FieldByName(schedulingStatusFieldName)
if objStatusField.IsValid() {
current := schedulingStatusField.Int()
additional := objStatusField.Int()
schedulingStatusField.SetInt(current + additional)
}
}
}
return federationObjCopy, replicas > 0, nil
}
func (a *schedulingAdapter) UpdateFederatedStatus(obj pkgruntime.Object, status SchedulingStatus) error {
return a.updateStatusFunc(obj, status)
}
func schedule(planner *planner.Planner, obj pkgruntime.Object, key string, clusterNames []string, currentReplicasPerCluster map[string]int64, estimatedCapacity map[string]int64) map[string]int64 {
// TODO: integrate real scheduler
replicas := reflect.ValueOf(obj).Elem().FieldByName("Spec").FieldByName("Replicas").Elem().Int()
scheduleResult, overflow := planner.Plan(replicas, clusterNames, currentReplicasPerCluster, estimatedCapacity, key)
// Ensure that all current clusters end up in the scheduling result.
result := make(map[string]int64)
for clusterName := range currentReplicasPerCluster {
result[clusterName] = 0
}
for clusterName, replicas := range scheduleResult {
result[clusterName] = replicas
}
for clusterName, replicas := range overflow {
result[clusterName] += replicas
}
if glog.V(4) {
buf := bytes.NewBufferString(fmt.Sprintf("Schedule - %q\n", key))
sort.Strings(clusterNames)
for _, clusterName := range clusterNames {
cur := currentReplicasPerCluster[clusterName]
target := scheduleResult[clusterName]
fmt.Fprintf(buf, "%s: current: %d target: %d", clusterName, cur, target)
if over, found := overflow[clusterName]; found {
fmt.Fprintf(buf, " overflow: %d", over)
}
if capacity, found := estimatedCapacity[clusterName]; found {
fmt.Fprintf(buf, " capacity: %d", capacity)
}
fmt.Fprintf(buf, "\n")
}
glog.V(4).Infof(buf.String())
}
return result
}
// clusterReplicaState returns information about the scheduling state of the pods running in the federated clusters.
func clustersReplicaState(
clusterNames []string,
key string,
objectGetter func(clusterName string, key string) (interface{}, bool, error),
podsGetter func(clusterName string, obj pkgruntime.Object) (*apiv1.PodList, error)) (currentReplicasPerCluster map[string]int64, estimatedCapacity map[string]int64, err error) {
currentReplicasPerCluster = make(map[string]int64)
estimatedCapacity = make(map[string]int64)
for _, clusterName := range clusterNames {
obj, exists, err := objectGetter(clusterName, key)
if err != nil {
return nil, nil, err
}
if !exists {
continue
}
replicas := reflect.ValueOf(obj).Elem().FieldByName("Spec").FieldByName("Replicas").Elem().Int()
readyReplicas := reflect.ValueOf(obj).Elem().FieldByName("Status").FieldByName("ReadyReplicas").Int()
if replicas == readyReplicas {
currentReplicasPerCluster[clusterName] = readyReplicas
} else {
pods, err := podsGetter(clusterName, obj.(pkgruntime.Object))
if err != nil {
return nil, nil, err
}
podStatus := podanalyzer.AnalyzePods(pods, time.Now())
currentReplicasPerCluster[clusterName] = int64(podStatus.RunningAndReady) // include pending as well?
unschedulable := int64(podStatus.Unschedulable)
if unschedulable > 0 {
estimatedCapacity[clusterName] = replicas - unschedulable
}
}
}
return currentReplicasPerCluster, estimatedCapacity, nil
}
......@@ -24,21 +24,22 @@ import (
apiv1 "k8s.io/api/core/v1"
extensionsv1 "k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
pkgruntime "k8s.io/apimachinery/pkg/runtime"
"github.com/stretchr/testify/assert"
)
func TestClusterReplicaState(t *testing.T) {
uncalledPodsGetter := func(clusterName string, replicaSet *extensionsv1.ReplicaSet) (*apiv1.PodList, error) {
t.Fatal("podsGetter should not be called when replica sets are all ready.")
uncalledPodsGetter := func(clusterName string, obj pkgruntime.Object) (*apiv1.PodList, error) {
t.Fatal("podsGetter should not be called when workload objects are all ready.")
return nil, nil
}
podsByReplicaSet := make(map[*extensionsv1.ReplicaSet][]*apiv1.Pod)
podsGetter := func(clusterName string, replicaSet *extensionsv1.ReplicaSet) (*apiv1.PodList, error) {
pods, ok := podsByReplicaSet[replicaSet]
podsByReplicaSet := make(map[pkgruntime.Object][]*apiv1.Pod)
podsGetter := func(clusterName string, obj pkgruntime.Object) (*apiv1.PodList, error) {
pods, ok := podsByReplicaSet[obj]
if !ok {
t.Fatalf("No pods found in test data for replica set named %v", replicaSet.Name)
t.Fatalf("No pods found in test data for replica set %v", obj)
return nil, fmt.Errorf("Not found")
}
var podListPods []apiv1.Pod
......@@ -64,7 +65,7 @@ func TestClusterReplicaState(t *testing.T) {
rs2Replicas int32
rs1ReadyReplicas int32
rs2ReadyReplicas int32
podsGetter func(clusterName string, replicaSet *extensionsv1.ReplicaSet) (*apiv1.PodList, error)
podsGetter func(clusterName string, obj pkgruntime.Object) (*apiv1.PodList, error)
pod1Phase apiv1.PodPhase
pod1Condition apiv1.PodCondition
pod2Phase apiv1.PodPhase
......
......@@ -25,7 +25,6 @@ filegroup(
srcs = [
":package-srcs",
"//federation/pkg/federation-controller/cluster:all-srcs",
"//federation/pkg/federation-controller/deployment:all-srcs",
"//federation/pkg/federation-controller/ingress:all-srcs",
"//federation/pkg/federation-controller/namespace:all-srcs",
"//federation/pkg/federation-controller/service:all-srcs",
......
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["deploymentcontroller.go"],
tags = ["automanaged"],
deps = [
"//federation/apis/federation:go_default_library",
"//federation/apis/federation/v1beta1:go_default_library",
"//federation/client/clientset_generated/federation_clientset:go_default_library",
"//federation/pkg/federation-controller/util:go_default_library",
"//federation/pkg/federation-controller/util/deletionhelper:go_default_library",
"//federation/pkg/federation-controller/util/eventsink:go_default_library",
"//federation/pkg/federation-controller/util/planner:go_default_library",
"//federation/pkg/federation-controller/util/replicapreferences:go_default_library",
"//pkg/api:go_default_library",
"//pkg/client/clientset_generated/clientset:go_default_library",
"//pkg/controller:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
"//vendor/k8s.io/client-go/tools/record:go_default_library",
"//vendor/k8s.io/client-go/util/flowcontrol:go_default_library",
"//vendor/k8s.io/client-go/util/workqueue:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["deploymentcontroller_test.go"],
library = ":go_default_library",
tags = ["automanaged"],
deps = [
"//federation/apis/federation/v1beta1:go_default_library",
"//federation/client/clientset_generated/federation_clientset/fake:go_default_library",
"//federation/pkg/federation-controller/util/test:go_default_library",
"//pkg/client/clientset_generated/clientset:go_default_library",
"//pkg/client/clientset_generated/clientset/fake:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
......@@ -44,6 +44,7 @@ go_test(
name = "go_default_test",
srcs = [
"controller_test.go",
"deploymentcontroller_test.go",
"replicasetcontroller_test.go",
],
library = ":go_default_library",
......@@ -62,6 +63,8 @@ go_test(
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/client-go/testing:go_default_library",
],
......
......@@ -14,13 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package deployment
package sync
import (
"flag"
"fmt"
"testing"
"time"
apiv1 "k8s.io/api/core/v1"
extensionsv1 "k8s.io/api/extensions/v1beta1"
......@@ -30,6 +29,7 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
fedv1 "k8s.io/kubernetes/federation/apis/federation/v1beta1"
fakefedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset/fake"
"k8s.io/kubernetes/federation/pkg/federatedtypes"
. "k8s.io/kubernetes/federation/pkg/federation-controller/util/test"
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
fakekubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
......@@ -39,7 +39,6 @@ import (
const (
deployments = "deployments"
pods = "pods"
)
func TestDeploymentController(t *testing.T) {
......@@ -47,11 +46,6 @@ func TestDeploymentController(t *testing.T) {
flag.Set("v", "5")
flag.Parse()
deploymentReviewDelay = 500 * time.Millisecond
clusterAvailableDelay = 100 * time.Millisecond
clusterUnavailableDelay = 100 * time.Millisecond
allDeploymentReviewDelay = 500 * time.Millisecond
cluster1 := NewCluster("cluster1", apiv1.ConditionTrue)
cluster2 := NewCluster("cluster2", apiv1.ConditionTrue)
......@@ -65,18 +59,15 @@ func TestDeploymentController(t *testing.T) {
cluster1Client := &fakekubeclientset.Clientset{}
cluster1Watch := RegisterFakeWatch(deployments, &cluster1Client.Fake)
_ = RegisterFakeWatch(pods, &cluster1Client.Fake)
RegisterFakeList(deployments, &cluster1Client.Fake, &extensionsv1.DeploymentList{Items: []extensionsv1.Deployment{}})
cluster1CreateChan := RegisterFakeCopyOnCreate(deployments, &cluster1Client.Fake, cluster1Watch)
cluster1UpdateChan := RegisterFakeCopyOnUpdate(deployments, &cluster1Client.Fake, cluster1Watch)
cluster2Client := &fakekubeclientset.Clientset{}
cluster2Watch := RegisterFakeWatch(deployments, &cluster2Client.Fake)
_ = RegisterFakeWatch(pods, &cluster2Client.Fake)
RegisterFakeList(deployments, &cluster2Client.Fake, &extensionsv1.DeploymentList{Items: []extensionsv1.Deployment{}})
cluster2CreateChan := RegisterFakeCopyOnCreate(deployments, &cluster2Client.Fake, cluster2Watch)
deploymentController := NewDeploymentController(fakeClient)
deploymentController := newFederationSyncController(fakeClient, federatedtypes.NewDeploymentAdapter(fakeClient))
deploymentController.minimizeLatency()
clientFactory := func(cluster *fedv1.Cluster) (kubeclientset.Interface, error) {
switch cluster.Name {
case cluster1.Name:
......@@ -87,11 +78,10 @@ func TestDeploymentController(t *testing.T) {
return nil, fmt.Errorf("Unknown cluster")
}
}
ToFederatedInformerForTestOnly(deploymentController.fedDeploymentInformer).SetClientFactory(clientFactory)
ToFederatedInformerForTestOnly(deploymentController.fedPodInformer).SetClientFactory(clientFactory)
ToFederatedInformerForTestOnly(deploymentController.informer).SetClientFactory(clientFactory)
stop := make(chan struct{})
go deploymentController.Run(5, stop)
go deploymentController.Run(stop)
// Create deployment. Expect to see it in cluster1.
dep1 := newDeploymentWithReplicas("depA", 6)
......@@ -113,7 +103,7 @@ func TestDeploymentController(t *testing.T) {
}
assert.NoError(t, CheckObjectFromChan(cluster1CreateChan, checkDeployment(dep1, *dep1.Spec.Replicas)))
err := WaitForStoreUpdate(
deploymentController.fedDeploymentInformer.GetTargetStore(),
deploymentController.informer.GetTargetStore(),
cluster1.Name, types.NamespacedName{Namespace: dep1.Namespace, Name: dep1.Name}.String(), wait.ForeverTestTimeout)
assert.Nil(t, err, "deployment should have appeared in the informer store")
......@@ -132,7 +122,7 @@ func TestDeploymentController(t *testing.T) {
// Add new deployment with non-default replica placement preferences.
dep2 := newDeploymentWithReplicas("deployment2", 9)
dep2.Annotations = make(map[string]string)
dep2.Annotations[FedDeploymentPreferencesAnnotation] = `{"rebalance": true,
dep2.Annotations[federatedtypes.FedDeploymentPreferencesAnnotation] = `{"rebalance": true,
"clusters": {
"cluster1": {"weight": 2},
"cluster2": {"weight": 1}
......
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