Commit 16943f6f authored by Jonathan MacMillan's avatar Jonathan MacMillan

[Federation] Convert the ReplicaSet controller to a sync controller.

parent e123311d
...@@ -26,7 +26,6 @@ go_library( ...@@ -26,7 +26,6 @@ go_library(
"//federation/pkg/federation-controller/deployment:go_default_library", "//federation/pkg/federation-controller/deployment:go_default_library",
"//federation/pkg/federation-controller/ingress:go_default_library", "//federation/pkg/federation-controller/ingress:go_default_library",
"//federation/pkg/federation-controller/namespace:go_default_library", "//federation/pkg/federation-controller/namespace:go_default_library",
"//federation/pkg/federation-controller/replicaset:go_default_library",
"//federation/pkg/federation-controller/service:go_default_library", "//federation/pkg/federation-controller/service:go_default_library",
"//federation/pkg/federation-controller/service/dns:go_default_library", "//federation/pkg/federation-controller/service/dns:go_default_library",
"//federation/pkg/federation-controller/sync:go_default_library", "//federation/pkg/federation-controller/sync:go_default_library",
......
...@@ -40,7 +40,6 @@ import ( ...@@ -40,7 +40,6 @@ import (
deploymentcontroller "k8s.io/kubernetes/federation/pkg/federation-controller/deployment" deploymentcontroller "k8s.io/kubernetes/federation/pkg/federation-controller/deployment"
ingresscontroller "k8s.io/kubernetes/federation/pkg/federation-controller/ingress" ingresscontroller "k8s.io/kubernetes/federation/pkg/federation-controller/ingress"
namespacecontroller "k8s.io/kubernetes/federation/pkg/federation-controller/namespace" namespacecontroller "k8s.io/kubernetes/federation/pkg/federation-controller/namespace"
replicasetcontroller "k8s.io/kubernetes/federation/pkg/federation-controller/replicaset"
servicecontroller "k8s.io/kubernetes/federation/pkg/federation-controller/service" servicecontroller "k8s.io/kubernetes/federation/pkg/federation-controller/service"
servicednscontroller "k8s.io/kubernetes/federation/pkg/federation-controller/service/dns" servicednscontroller "k8s.io/kubernetes/federation/pkg/federation-controller/service/dns"
synccontroller "k8s.io/kubernetes/federation/pkg/federation-controller/sync" synccontroller "k8s.io/kubernetes/federation/pkg/federation-controller/sync"
...@@ -167,14 +166,6 @@ func StartControllers(s *options.CMServer, restClientCfg *restclient.Config) err ...@@ -167,14 +166,6 @@ func StartControllers(s *options.CMServer, restClientCfg *restclient.Config) err
} }
} }
if controllerEnabled(s.Controllers, serverResources, replicasetcontroller.ControllerName, replicasetcontroller.RequiredResources, true) {
glog.V(3).Infof("Loading client config for replica set controller %q", replicasetcontroller.UserAgentName)
replicaSetClientset := federationclientset.NewForConfigOrDie(restclient.AddUserAgent(restClientCfg, replicasetcontroller.UserAgentName))
replicaSetController := replicasetcontroller.NewReplicaSetController(replicaSetClientset)
glog.V(3).Infof("Running replica set controller")
go replicaSetController.Run(s.ConcurrentReplicaSetSyncs, wait.NeverStop)
}
if controllerEnabled(s.Controllers, serverResources, deploymentcontroller.ControllerName, deploymentcontroller.RequiredResources, true) { if controllerEnabled(s.Controllers, serverResources, deploymentcontroller.ControllerName, deploymentcontroller.RequiredResources, true) {
glog.V(3).Infof("Loading client config for deployment controller %q", deploymentcontroller.UserAgentName) glog.V(3).Infof("Loading client config for deployment controller %q", deploymentcontroller.UserAgentName)
deploymentClientset := federationclientset.NewForConfigOrDie(restclient.AddUserAgent(restClientCfg, deploymentcontroller.UserAgentName)) deploymentClientset := federationclientset.NewForConfigOrDie(restclient.AddUserAgent(restClientCfg, deploymentcontroller.UserAgentName))
......
...@@ -5,6 +5,7 @@ licenses(["notice"]) ...@@ -5,6 +5,7 @@ licenses(["notice"])
load( load(
"@io_bazel_rules_go//go:def.bzl", "@io_bazel_rules_go//go:def.bzl",
"go_library", "go_library",
"go_test",
) )
go_library( go_library(
...@@ -14,15 +15,21 @@ go_library( ...@@ -14,15 +15,21 @@ go_library(
"configmap.go", "configmap.go",
"daemonset.go", "daemonset.go",
"registry.go", "registry.go",
"replicaset.go",
"scheduling.go", "scheduling.go",
"secret.go", "secret.go",
], ],
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//federation/apis/federation:go_default_library",
"//federation/apis/federation/v1beta1:go_default_library", "//federation/apis/federation/v1beta1:go_default_library",
"//federation/client/clientset_generated/federation_clientset: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:go_default_library",
"//federation/pkg/federation-controller/util/planner:go_default_library",
"//federation/pkg/federation-controller/util/podanalyzer:go_default_library",
"//federation/pkg/federation-controller/util/replicapreferences:go_default_library",
"//pkg/client/clientset_generated/clientset:go_default_library", "//pkg/client/clientset_generated/clientset:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1: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/apis/meta/v1:go_default_library",
...@@ -48,3 +55,16 @@ filegroup( ...@@ -48,3 +55,16 @@ filegroup(
], ],
tags = ["automanaged"], tags = ["automanaged"],
) )
go_test(
name = "go_default_test",
srcs = ["replicaset_test.go"],
library = ":go_default_library",
tags = ["automanaged"],
deps = [
"//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",
],
)
...@@ -197,8 +197,17 @@ func (c *FederatedTypeCRUDTester) CheckPropagationForClients(obj pkgruntime.Obje ...@@ -197,8 +197,17 @@ func (c *FederatedTypeCRUDTester) CheckPropagationForClients(obj pkgruntime.Obje
func (c *FederatedTypeCRUDTester) waitForResource(client clientset.Interface, obj pkgruntime.Object) error { func (c *FederatedTypeCRUDTester) waitForResource(client clientset.Interface, obj pkgruntime.Object) error {
namespacedName := c.adapter.NamespacedName(obj) namespacedName := c.adapter.NamespacedName(obj)
err := wait.PollImmediate(c.waitInterval, c.clusterWaitTimeout, func() (bool, error) { err := wait.PollImmediate(c.waitInterval, c.clusterWaitTimeout, func() (bool, error) {
equivalenceFunc := c.adapter.Equivalent
if c.adapter.IsSchedulingAdapter() {
schedulingAdapter, ok := c.adapter.(federatedtypes.SchedulingAdapter)
if !ok {
c.tl.Fatalf("Adapter for kind %q does not properly implement SchedulingAdapter.", c.adapter.Kind())
}
equivalenceFunc = schedulingAdapter.EquivalentIgnoringSchedule
}
clusterObj, err := c.adapter.ClusterGet(client, namespacedName) clusterObj, err := c.adapter.ClusterGet(client, namespacedName)
if err == nil && c.adapter.Equivalent(clusterObj, obj) { if err == nil && equivalenceFunc(clusterObj, obj) {
return true, nil return true, nil
} }
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
......
/*
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 (
"fmt"
"testing"
"time"
apiv1 "k8s.io/api/core/v1"
extensionsv1 "k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/stretchr/testify/assert"
)
const (
pods = "pods"
replicasets = "replicasets"
k8s1 = "k8s-1"
k8s2 = "k8s-2"
)
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.")
return nil, nil
}
podsByReplicaSet := make(map[*extensionsv1.ReplicaSet][]*apiv1.Pod)
podsGetter := func(clusterName string, replicaSet *extensionsv1.ReplicaSet) (*apiv1.PodList, error) {
pods, ok := podsByReplicaSet[replicaSet]
if !ok {
t.Fatalf("No pods found in test data for replica set named %v", replicaSet.Name)
return nil, fmt.Errorf("Not found")
}
var podListPods []apiv1.Pod
for _, pod := range pods {
podListPods = append(podListPods, *pod)
}
return &apiv1.PodList{Items: podListPods}, nil
}
readyCondition := apiv1.PodCondition{Type: apiv1.PodReady}
unschedulableCondition := apiv1.PodCondition{
Type: apiv1.PodScheduled,
Status: apiv1.ConditionFalse,
Reason: apiv1.PodReasonUnschedulable,
LastTransitionTime: metav1.NewTime(time.Now().Add(-1 * time.Hour)),
}
one := int64(1)
two := int64(2)
tests := map[string]struct {
rs1Replicas int32
rs2Replicas int32
rs1ReadyReplicas int32
rs2ReadyReplicas int32
podsGetter func(clusterName string, replicaSet *extensionsv1.ReplicaSet) (*apiv1.PodList, error)
pod1Phase apiv1.PodPhase
pod1Condition apiv1.PodCondition
pod2Phase apiv1.PodPhase
pod2Condition apiv1.PodCondition
cluster1Replicas *int64
cluster2Replicas *int64
cluster1UnschedulableReplicas *int64
cluster2UnschedulableReplicas *int64
}{
"All replica sets have an equal number of requested and ready replicas.": {rs1Replicas: 2, rs2Replicas: 2, rs1ReadyReplicas: 2, rs2ReadyReplicas: 2, podsGetter: uncalledPodsGetter, cluster1Replicas: &two, cluster2Replicas: &two},
"One replica set has a pending schedulable pod": {rs1Replicas: 2, rs2Replicas: 2, rs1ReadyReplicas: 1, rs2ReadyReplicas: 2, podsGetter: podsGetter, pod1Phase: apiv1.PodRunning, pod1Condition: readyCondition, pod2Phase: apiv1.PodPending, cluster1Replicas: &one, cluster2Replicas: &two},
"One replica set has an unschedulable pod": {rs1Replicas: 2, rs2Replicas: 2, rs1ReadyReplicas: 1, rs2ReadyReplicas: 2, podsGetter: podsGetter, pod1Phase: apiv1.PodRunning, pod1Condition: readyCondition, pod2Phase: apiv1.PodPending, pod2Condition: unschedulableCondition, cluster1Replicas: &one, cluster2Replicas: &two, cluster1UnschedulableReplicas: &one},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
clusters := []string{"one", "two"}
replicaSetsByCluster := make(map[string]*extensionsv1.ReplicaSet)
replicaSetGetter := func(clusterName string, key string) (interface{}, bool, error) {
rs, ok := replicaSetsByCluster[clusterName]
if !ok {
t.Fatalf("No replica set found in test data for %v", clusterName)
return nil, false, fmt.Errorf("Not found")
}
return rs, true, nil
}
rs1 := newReplicaSetWithReplicas("one", tt.rs1Replicas)
rs2 := newReplicaSetWithReplicas("two", tt.rs2Replicas)
rs1.Spec.Replicas = &tt.rs1Replicas
rs2.Spec.Replicas = &tt.rs2Replicas
rs1.Status.ReadyReplicas = tt.rs1ReadyReplicas
rs2.Status.ReadyReplicas = tt.rs2ReadyReplicas
replicaSetsByCluster["one"] = rs1
replicaSetsByCluster["two"] = rs2
pod1 := newPod("one")
pod2 := newPod("two")
podThree := newPod("three")
podFour := newPod("four")
pod1.Status.Phase = tt.pod1Phase
pod2.Status.Phase = tt.pod2Phase
pod1.Status.Conditions = []apiv1.PodCondition{tt.pod1Condition}
pod2.Status.Conditions = []apiv1.PodCondition{tt.pod2Condition}
podsByReplicaSet[rs1] = []*apiv1.Pod{pod1, pod2}
podsByReplicaSet[rs2] = []*apiv1.Pod{podThree, podFour}
current, estimatedCapacity, err := clustersReplicaState(clusters, "", replicaSetGetter, tt.podsGetter)
assert.Nil(t, err)
wantedCurrent := make(map[string]int64)
if tt.cluster1Replicas != nil {
wantedCurrent["one"] = *tt.cluster1Replicas
}
if tt.cluster2Replicas != nil {
wantedCurrent["two"] = *tt.cluster2Replicas
}
assert.Equal(t, wantedCurrent, current)
wantedEstimatedCapacity := make(map[string]int64)
if tt.cluster1UnschedulableReplicas != nil {
wantedEstimatedCapacity["one"] = *tt.cluster1UnschedulableReplicas
}
if tt.cluster2UnschedulableReplicas != nil {
wantedEstimatedCapacity["two"] = *tt.cluster2UnschedulableReplicas
}
assert.Equal(t, wantedEstimatedCapacity, estimatedCapacity)
})
}
}
func newReplicaSetWithReplicas(name string, replicas int32) *extensionsv1.ReplicaSet {
return &extensionsv1.ReplicaSet{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: metav1.NamespaceDefault,
SelfLink: "/api/v1/namespaces/default/replicasets/name",
},
Spec: extensionsv1.ReplicaSetSpec{
Replicas: &replicas,
},
}
}
func newPod(name string) *apiv1.Pod {
return &apiv1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: metav1.NamespaceDefault,
},
}
}
...@@ -44,4 +44,8 @@ type SchedulingAdapter interface { ...@@ -44,4 +44,8 @@ type SchedulingAdapter interface {
GetSchedule(obj pkgruntime.Object, key string, clusters []*federationapi.Cluster, informer fedutil.FederatedInformer) (*SchedulingInfo, error) GetSchedule(obj pkgruntime.Object, key string, clusters []*federationapi.Cluster, informer fedutil.FederatedInformer) (*SchedulingInfo, error)
ScheduleObject(cluster *federationapi.Cluster, clusterObj pkgruntime.Object, federationObjCopy pkgruntime.Object, schedulingInfo *SchedulingInfo) (pkgruntime.Object, bool, error) ScheduleObject(cluster *federationapi.Cluster, clusterObj pkgruntime.Object, federationObjCopy pkgruntime.Object, schedulingInfo *SchedulingInfo) (pkgruntime.Object, bool, error)
UpdateFederatedStatus(obj pkgruntime.Object, status SchedulingStatus) error UpdateFederatedStatus(obj pkgruntime.Object, status SchedulingStatus) error
// EquivalentIgnoringSchedule returns whether obj1 and obj2 are
// equivalent ignoring differences due to scheduling.
EquivalentIgnoringSchedule(obj1, obj2 pkgruntime.Object) bool
} }
...@@ -28,7 +28,6 @@ filegroup( ...@@ -28,7 +28,6 @@ filegroup(
"//federation/pkg/federation-controller/deployment:all-srcs", "//federation/pkg/federation-controller/deployment:all-srcs",
"//federation/pkg/federation-controller/ingress:all-srcs", "//federation/pkg/federation-controller/ingress:all-srcs",
"//federation/pkg/federation-controller/namespace:all-srcs", "//federation/pkg/federation-controller/namespace:all-srcs",
"//federation/pkg/federation-controller/replicaset:all-srcs",
"//federation/pkg/federation-controller/service:all-srcs", "//federation/pkg/federation-controller/service:all-srcs",
"//federation/pkg/federation-controller/sync:all-srcs", "//federation/pkg/federation-controller/sync:all-srcs",
"//federation/pkg/federation-controller/util:all-srcs", "//federation/pkg/federation-controller/util:all-srcs",
......
...@@ -20,7 +20,6 @@ go_library( ...@@ -20,7 +20,6 @@ go_library(
"//federation/pkg/federation-controller/util/deletionhelper: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/eventsink:go_default_library",
"//federation/pkg/federation-controller/util/planner:go_default_library", "//federation/pkg/federation-controller/util/planner:go_default_library",
"//federation/pkg/federation-controller/util/podanalyzer:go_default_library",
"//federation/pkg/federation-controller/util/replicapreferences:go_default_library", "//federation/pkg/federation-controller/util/replicapreferences:go_default_library",
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/client/clientset_generated/clientset:go_default_library", "//pkg/client/clientset_generated/clientset:go_default_library",
...@@ -30,6 +29,7 @@ go_library( ...@@ -30,6 +29,7 @@ go_library(
"//vendor/k8s.io/api/extensions/v1beta1: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/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1: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:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema: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/util/wait:go_default_library",
......
...@@ -29,6 +29,7 @@ import ( ...@@ -29,6 +29,7 @@ import (
extensionsv1 "k8s.io/api/extensions/v1beta1" extensionsv1 "k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
...@@ -44,7 +45,6 @@ import ( ...@@ -44,7 +45,6 @@ import (
"k8s.io/kubernetes/federation/pkg/federation-controller/util/deletionhelper" "k8s.io/kubernetes/federation/pkg/federation-controller/util/deletionhelper"
"k8s.io/kubernetes/federation/pkg/federation-controller/util/eventsink" "k8s.io/kubernetes/federation/pkg/federation-controller/util/eventsink"
"k8s.io/kubernetes/federation/pkg/federation-controller/util/planner" "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" "k8s.io/kubernetes/federation/pkg/federation-controller/util/replicapreferences"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
...@@ -352,6 +352,62 @@ func (fdc *DeploymentController) worker() { ...@@ -352,6 +352,62 @@ func (fdc *DeploymentController) worker() {
} }
} }
type podAnalysisResult struct {
// Total number of pods created.
total int
// Number of pods that are running and ready.
runningAndReady int
// Number of pods that have been in unschedulable state for UnshedulableThreshold seconds.
unschedulable int
// TODO: Handle other scenarios like pod waiting too long for scheduler etc.
}
const (
// TODO: make it configurable
unschedulableThreshold = 60 * time.Second
)
// A function that calculates how many pods from the list are in one of
// the meaningful (from the replica set perspective) states. This function is
// a temporary workaround against the current lack of ownerRef in pods.
// TODO(perotinus): Unify this with the ReplicaSet controller.
func analyzePods(selectorv1 *metav1.LabelSelector, allPods []fedutil.FederatedObject, currentTime time.Time) (map[string]podAnalysisResult, error) {
selector, err := metav1.LabelSelectorAsSelector(selectorv1)
if err != nil {
return nil, fmt.Errorf("invalid selector: %v", err)
}
result := make(map[string]podAnalysisResult)
for _, fedObject := range allPods {
pod, isPod := fedObject.Object.(*apiv1.Pod)
if !isPod {
return nil, fmt.Errorf("invalid arg content - not a *pod")
}
if !selector.Empty() && selector.Matches(labels.Set(pod.Labels)) {
status := result[fedObject.ClusterName]
status.total++
for _, condition := range pod.Status.Conditions {
if pod.Status.Phase == apiv1.PodRunning {
if condition.Type == apiv1.PodReady {
status.runningAndReady++
}
} else {
if condition.Type == apiv1.PodScheduled &&
condition.Status == apiv1.ConditionFalse &&
condition.Reason == apiv1.PodReasonUnschedulable &&
condition.LastTransitionTime.Add(unschedulableThreshold).Before(currentTime) {
status.unschedulable++
}
}
}
result[fedObject.ClusterName] = status
}
}
return result, nil
}
func (fdc *DeploymentController) schedule(fd *extensionsv1.Deployment, clusters []*fedv1.Cluster, func (fdc *DeploymentController) schedule(fd *extensionsv1.Deployment, clusters []*fedv1.Cluster,
current map[string]int64, estimatedCapacity map[string]int64) map[string]int64 { current map[string]int64, estimatedCapacity map[string]int64) map[string]int64 {
// TODO: integrate real scheduler // TODO: integrate real scheduler
...@@ -471,10 +527,7 @@ func (fdc *DeploymentController) reconcileDeployment(key string) (reconciliation ...@@ -471,10 +527,7 @@ func (fdc *DeploymentController) reconcileDeployment(key string) (reconciliation
if err != nil { if err != nil {
return statusError, err return statusError, err
} }
podStatus, err := podanalyzer.AnalysePods(fd.Spec.Selector, allPods, time.Now()) podStatus, err := analyzePods(fd.Spec.Selector, allPods, time.Now())
if err != nil {
return statusError, err
}
current := make(map[string]int64) current := make(map[string]int64)
estimatedCapacity := make(map[string]int64) estimatedCapacity := make(map[string]int64)
for _, cluster := range clusters { for _, cluster := range clusters {
...@@ -484,8 +537,8 @@ func (fdc *DeploymentController) reconcileDeployment(key string) (reconciliation ...@@ -484,8 +537,8 @@ func (fdc *DeploymentController) reconcileDeployment(key string) (reconciliation
} }
if exists { if exists {
ld := ldObj.(*extensionsv1.Deployment) ld := ldObj.(*extensionsv1.Deployment)
current[cluster.Name] = int64(podStatus[cluster.Name].RunningAndReady) // include pending as well? current[cluster.Name] = int64(podStatus[cluster.Name].runningAndReady) // include pending as well?
unschedulable := int64(podStatus[cluster.Name].Unschedulable) unschedulable := int64(podStatus[cluster.Name].unschedulable)
if unschedulable > 0 { if unschedulable > 0 {
estimatedCapacity[cluster.Name] = int64(*ld.Spec.Replicas) - unschedulable estimatedCapacity[cluster.Name] = int64(*ld.Spec.Replicas) - unschedulable
} }
......
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 = ["replicasetcontroller.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/podanalyzer: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/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 = ["replicasetcontroller_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/watch:go_default_library",
"//vendor/k8s.io/client-go/testing:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
...@@ -42,18 +42,28 @@ go_library( ...@@ -42,18 +42,28 @@ go_library(
go_test( go_test(
name = "go_default_test", name = "go_default_test",
srcs = ["controller_test.go"], srcs = [
"controller_test.go",
"replicasetcontroller_test.go",
],
library = ":go_default_library", library = ":go_default_library",
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//federation/apis/federation/v1beta1:go_default_library", "//federation/apis/federation/v1beta1:go_default_library",
"//federation/client/clientset_generated/federation_clientset/fake:go_default_library",
"//federation/pkg/federatedtypes:go_default_library", "//federation/pkg/federatedtypes:go_default_library",
"//federation/pkg/federation-controller/util:go_default_library", "//federation/pkg/federation-controller/util:go_default_library",
"//federation/pkg/federation-controller/util/test: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/github.com/stretchr/testify/require:go_default_library", "//vendor/github.com/stretchr/testify/require:go_default_library",
"//vendor/k8s.io/api/core/v1: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/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/client-go/testing:go_default_library",
], ],
) )
......
...@@ -84,10 +84,11 @@ type FederationSyncController struct { ...@@ -84,10 +84,11 @@ type FederationSyncController struct {
deletionHelper *deletionhelper.DeletionHelper deletionHelper *deletionhelper.DeletionHelper
reviewDelay time.Duration reviewDelay time.Duration
clusterAvailableDelay time.Duration clusterAvailableDelay time.Duration
smallDelay time.Duration clusterUnavailableDelay time.Duration
updateTimeout time.Duration smallDelay time.Duration
updateTimeout time.Duration
adapter federatedtypes.FederatedTypeAdapter adapter federatedtypes.FederatedTypeAdapter
} }
...@@ -112,14 +113,15 @@ func newFederationSyncController(client federationclientset.Interface, adapter f ...@@ -112,14 +113,15 @@ func newFederationSyncController(client federationclientset.Interface, adapter f
recorder := broadcaster.NewRecorder(api.Scheme, clientv1.EventSource{Component: fmt.Sprintf("federation-%v-controller", adapter.Kind())}) recorder := broadcaster.NewRecorder(api.Scheme, clientv1.EventSource{Component: fmt.Sprintf("federation-%v-controller", adapter.Kind())})
s := &FederationSyncController{ s := &FederationSyncController{
reviewDelay: time.Second * 10, reviewDelay: time.Second * 10,
clusterAvailableDelay: time.Second * 20, clusterAvailableDelay: time.Second * 20,
smallDelay: time.Second * 3, clusterUnavailableDelay: time.Second * 60,
updateTimeout: time.Second * 30, smallDelay: time.Second * 3,
workQueue: workqueue.New(), updateTimeout: time.Second * 30,
backoff: flowcontrol.NewBackOff(5*time.Second, time.Minute), workQueue: workqueue.New(),
eventRecorder: recorder, backoff: flowcontrol.NewBackOff(5*time.Second, time.Minute),
adapter: adapter, eventRecorder: recorder,
adapter: adapter,
} }
// Build delivereres for triggering reconciliations. // Build delivereres for triggering reconciliations.
...@@ -169,6 +171,10 @@ func newFederationSyncController(client federationclientset.Interface, adapter f ...@@ -169,6 +171,10 @@ func newFederationSyncController(client federationclientset.Interface, adapter f
// When new cluster becomes available process all the target resources again. // When new cluster becomes available process all the target resources again.
s.clusterDeliverer.DeliverAt(allClustersKey, nil, time.Now().Add(s.clusterAvailableDelay)) s.clusterDeliverer.DeliverAt(allClustersKey, nil, time.Now().Add(s.clusterAvailableDelay))
}, },
// When a cluster becomes unavailable process all the target resources again.
ClusterUnavailable: func(cluster *federationapi.Cluster, _ []interface{}) {
s.clusterDeliverer.DeliverAt(allClustersKey, nil, time.Now().Add(s.clusterUnavailableDelay))
},
}, },
) )
...@@ -205,6 +211,7 @@ func newFederationSyncController(client federationclientset.Interface, adapter f ...@@ -205,6 +211,7 @@ func newFederationSyncController(client federationclientset.Interface, adapter f
// minimizeLatency reduces delays and timeouts to make the controller more responsive (useful for testing). // minimizeLatency reduces delays and timeouts to make the controller more responsive (useful for testing).
func (s *FederationSyncController) minimizeLatency() { func (s *FederationSyncController) minimizeLatency() {
s.clusterAvailableDelay = time.Second s.clusterAvailableDelay = time.Second
s.clusterUnavailableDelay = time.Second
s.reviewDelay = 50 * time.Millisecond s.reviewDelay = 50 * time.Millisecond
s.smallDelay = 20 * time.Millisecond s.smallDelay = 20 * time.Millisecond
s.updateTimeout = 5 * time.Second s.updateTimeout = 5 * time.Second
...@@ -328,6 +335,10 @@ func (s *FederationSyncController) reconcile(namespacedName types.NamespacedName ...@@ -328,6 +335,10 @@ func (s *FederationSyncController) reconcile(namespacedName types.NamespacedName
kind := s.adapter.Kind() kind := s.adapter.Kind()
key := namespacedName.String() key := namespacedName.String()
glog.V(4).Infof("Starting to reconcile %v %v", kind, key)
startTime := time.Now()
defer glog.V(4).Infof("Finished reconciling %v %v (duration: %v)", kind, key, time.Now().Sub(startTime))
obj, err := s.objFromCache(kind, key) obj, err := s.objFromCache(kind, key)
if err != nil { if err != nil {
return statusError return statusError
......
...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and ...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package replicaset package sync
import ( import (
"flag" "flag"
...@@ -29,7 +29,8 @@ import ( ...@@ -29,7 +29,8 @@ import (
core "k8s.io/client-go/testing" core "k8s.io/client-go/testing"
fedv1 "k8s.io/kubernetes/federation/apis/federation/v1beta1" fedv1 "k8s.io/kubernetes/federation/apis/federation/v1beta1"
fedclientfake "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset/fake" fedclientfake "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset/fake"
"k8s.io/kubernetes/federation/pkg/federation-controller/util/test" "k8s.io/kubernetes/federation/pkg/federatedtypes"
testutil "k8s.io/kubernetes/federation/pkg/federation-controller/util/test"
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
kubeclientfake "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake" kubeclientfake "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
...@@ -48,11 +49,6 @@ func TestReplicaSetController(t *testing.T) { ...@@ -48,11 +49,6 @@ func TestReplicaSetController(t *testing.T) {
flag.Set("v", "5") flag.Set("v", "5")
flag.Parse() flag.Parse()
replicaSetReviewDelay = 10 * time.Millisecond
clusterAvailableDelay = 20 * time.Millisecond
clusterUnavailableDelay = 60 * time.Millisecond
allReplicaSetReviewDelay = 120 * time.Millisecond
fedclientset := fedclientfake.NewSimpleClientset() fedclientset := fedclientfake.NewSimpleClientset()
fedrswatch := watch.NewFake() fedrswatch := watch.NewFake()
fedclientset.PrependWatchReactor(replicasets, core.DefaultWatchReactor(fedrswatch, nil)) fedclientset.PrependWatchReactor(replicasets, core.DefaultWatchReactor(fedrswatch, nil))
...@@ -81,20 +77,19 @@ func TestReplicaSetController(t *testing.T) { ...@@ -81,20 +77,19 @@ func TestReplicaSetController(t *testing.T) {
return nil, fmt.Errorf("Unknown cluster: %v", cluster.Name) return nil, fmt.Errorf("Unknown cluster: %v", cluster.Name)
} }
} }
replicaSetController := NewReplicaSetController(fedclientset) replicaSetController := newFederationSyncController(fedclientset, federatedtypes.NewReplicaSetAdapter(fedclientset))
rsFedinformer := testutil.ToFederatedInformerForTestOnly(replicaSetController.fedReplicaSetInformer) replicaSetController.minimizeLatency()
rsFedinformer := testutil.ToFederatedInformerForTestOnly(replicaSetController.informer)
rsFedinformer.SetClientFactory(fedInformerClientFactory) rsFedinformer.SetClientFactory(fedInformerClientFactory)
podFedinformer := testutil.ToFederatedInformerForTestOnly(replicaSetController.fedPodInformer)
podFedinformer.SetClientFactory(fedInformerClientFactory)
stopChan := make(chan struct{}) stopChan := make(chan struct{})
defer close(stopChan) defer close(stopChan)
go replicaSetController.Run(1, stopChan) go replicaSetController.Run(stopChan)
rs := newReplicaSetWithReplicas("rs", 9) rs := newReplicaSetWithReplicas("rs", 9)
rs, _ = fedclientset.Extensions().ReplicaSets(metav1.NamespaceDefault).Create(rs) rs, _ = fedclientset.Extensions().ReplicaSets(metav1.NamespaceDefault).Create(rs)
fedrswatch.Add(rs) fedrswatch.Add(rs)
time.Sleep(1 * time.Second) time.Sleep(2 * time.Second)
rs1, _ := kube1clientset.Extensions().ReplicaSets(metav1.NamespaceDefault).Get(rs.Name, metav1.GetOptions{}) rs1, _ := kube1clientset.Extensions().ReplicaSets(metav1.NamespaceDefault).Get(rs.Name, metav1.GetOptions{})
kube1rswatch.Add(rs1) kube1rswatch.Add(rs1)
...@@ -114,7 +109,7 @@ func TestReplicaSetController(t *testing.T) { ...@@ -114,7 +109,7 @@ func TestReplicaSetController(t *testing.T) {
rs2, _ = kube2clientset.Extensions().ReplicaSets(metav1.NamespaceDefault).UpdateStatus(rs2) rs2, _ = kube2clientset.Extensions().ReplicaSets(metav1.NamespaceDefault).UpdateStatus(rs2)
kube2rswatch.Modify(rs2) kube2rswatch.Modify(rs2)
time.Sleep(1 * time.Second) time.Sleep(2 * time.Second)
rs, _ = fedclientset.Extensions().ReplicaSets(metav1.NamespaceDefault).Get(rs.Name, metav1.GetOptions{}) rs, _ = fedclientset.Extensions().ReplicaSets(metav1.NamespaceDefault).Get(rs.Name, metav1.GetOptions{})
assert.Equal(t, *rs.Spec.Replicas, *rs1.Spec.Replicas+*rs2.Spec.Replicas) assert.Equal(t, *rs.Spec.Replicas, *rs1.Spec.Replicas+*rs2.Spec.Replicas)
assert.Equal(t, rs.Status.Replicas, rs1.Status.Replicas+rs2.Status.Replicas) assert.Equal(t, rs.Status.Replicas, rs1.Status.Replicas+rs2.Status.Replicas)
...@@ -126,7 +121,7 @@ func TestReplicaSetController(t *testing.T) { ...@@ -126,7 +121,7 @@ func TestReplicaSetController(t *testing.T) {
rs.Spec.Replicas = &replicas rs.Spec.Replicas = &replicas
rs, _ = fedclientset.Extensions().ReplicaSets(metav1.NamespaceDefault).Update(rs) rs, _ = fedclientset.Extensions().ReplicaSets(metav1.NamespaceDefault).Update(rs)
fedrswatch.Modify(rs) fedrswatch.Modify(rs)
time.Sleep(1 * time.Second) time.Sleep(2 * time.Second)
rs1, _ = kube1clientset.Extensions().ReplicaSets(metav1.NamespaceDefault).Get(rs.Name, metav1.GetOptions{}) rs1, _ = kube1clientset.Extensions().ReplicaSets(metav1.NamespaceDefault).Get(rs.Name, metav1.GetOptions{})
rs1.Status.Replicas = *rs1.Spec.Replicas rs1.Status.Replicas = *rs1.Spec.Replicas
......
...@@ -12,12 +12,7 @@ go_library( ...@@ -12,12 +12,7 @@ go_library(
name = "go_default_library", name = "go_default_library",
srcs = ["pod_helper.go"], srcs = ["pod_helper.go"],
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = ["//vendor/k8s.io/api/core/v1:go_default_library"],
"//federation/pkg/federation-controller/util:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
],
) )
go_test( go_test(
...@@ -26,7 +21,6 @@ go_test( ...@@ -26,7 +21,6 @@ go_test(
library = ":go_default_library", library = ":go_default_library",
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//federation/pkg/federation-controller/util:go_default_library",
"//vendor/github.com/stretchr/testify/assert: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/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library", "//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
......
...@@ -17,13 +17,9 @@ limitations under the License. ...@@ -17,13 +17,9 @@ limitations under the License.
package podanalyzer package podanalyzer
import ( import (
"fmt"
"time" "time"
api_v1 "k8s.io/api/core/v1" api_v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
) )
type PodAnalysisResult struct { type PodAnalysisResult struct {
...@@ -42,41 +38,26 @@ const ( ...@@ -42,41 +38,26 @@ const (
UnschedulableThreshold = 60 * time.Second UnschedulableThreshold = 60 * time.Second
) )
// A function that calculates how many pods from the list are in one of // AnalyzePods calculates how many pods from the list are in one of
// the meaningful (from the replica set perspective) states. This function is // the meaningful (from the replica set perspective) states. This function is
// a temporary workaround against the current lack of ownerRef in pods. // a temporary workaround against the current lack of ownerRef in pods.
func AnalysePods(selectorv1 *metav1.LabelSelector, allPods []util.FederatedObject, currentTime time.Time) (map[string]PodAnalysisResult, error) { func AnalyzePods(pods *api_v1.PodList, currentTime time.Time) PodAnalysisResult {
selector, err := metav1.LabelSelectorAsSelector(selectorv1) result := PodAnalysisResult{}
if err != nil { for _, pod := range pods.Items {
return nil, fmt.Errorf("invalid selector: %v", err) result.Total++
} for _, condition := range pod.Status.Conditions {
result := make(map[string]PodAnalysisResult) if pod.Status.Phase == api_v1.PodRunning {
if condition.Type == api_v1.PodReady {
for _, fedObject := range allPods { result.RunningAndReady++
pod, isPod := fedObject.Object.(*api_v1.Pod)
if !isPod {
return nil, fmt.Errorf("invalid arg content - not a *pod")
}
if !selector.Empty() && selector.Matches(labels.Set(pod.Labels)) {
status := result[fedObject.ClusterName]
status.Total++
for _, condition := range pod.Status.Conditions {
if pod.Status.Phase == api_v1.PodRunning {
if condition.Type == api_v1.PodReady {
status.RunningAndReady++
}
} else {
if condition.Type == api_v1.PodScheduled &&
condition.Status == api_v1.ConditionFalse &&
condition.Reason == api_v1.PodReasonUnschedulable &&
condition.LastTransitionTime.Add(UnschedulableThreshold).Before(currentTime) {
status.Unschedulable++
}
} }
} else if condition.Type == api_v1.PodScheduled &&
condition.Status == api_v1.ConditionFalse &&
condition.Reason == api_v1.PodReasonUnschedulable &&
condition.LastTransitionTime.Add(UnschedulableThreshold).Before(currentTime) {
result.Unschedulable++
} }
result[fedObject.ClusterName] = status
} }
} }
return result, nil return result
} }
...@@ -23,16 +23,13 @@ import ( ...@@ -23,16 +23,13 @@ import (
api_v1 "k8s.io/api/core/v1" api_v1 "k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1" "k8s.io/api/extensions/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestAnalyze(t *testing.T) { func TestAnalyze(t *testing.T) {
now := time.Now() now := time.Now()
replicaSet := newReplicaSet(map[string]string{"A": "B"}) podRunning := newPod("p1",
replicaSet2 := newReplicaSet(map[string]string{"C": "D"})
podRunning := newPod("p1", replicaSet,
api_v1.PodStatus{ api_v1.PodStatus{
Phase: api_v1.PodRunning, Phase: api_v1.PodRunning,
Conditions: []api_v1.PodCondition{ Conditions: []api_v1.PodCondition{
...@@ -42,7 +39,7 @@ func TestAnalyze(t *testing.T) { ...@@ -42,7 +39,7 @@ func TestAnalyze(t *testing.T) {
}, },
}, },
}) })
podUnschedulable := newPod("pU", replicaSet, podUnschedulable := newPod("pU",
api_v1.PodStatus{ api_v1.PodStatus{
Phase: api_v1.PodPending, Phase: api_v1.PodPending,
Conditions: []api_v1.PodCondition{ Conditions: []api_v1.PodCondition{
...@@ -54,42 +51,25 @@ func TestAnalyze(t *testing.T) { ...@@ -54,42 +51,25 @@ func TestAnalyze(t *testing.T) {
}, },
}, },
}) })
podOther := newPod("pO", replicaSet, podOther := newPod("pO",
api_v1.PodStatus{
Phase: api_v1.PodPending,
Conditions: []api_v1.PodCondition{},
})
podOtherRS := newPod("pO", replicaSet2,
api_v1.PodStatus{ api_v1.PodStatus{
Phase: api_v1.PodPending, Phase: api_v1.PodPending,
Conditions: []api_v1.PodCondition{}, Conditions: []api_v1.PodCondition{},
}) })
federatedObjects := []util.FederatedObject{ result := AnalyzePods(&api_v1.PodList{Items: []api_v1.Pod{*podRunning, *podRunning, *podRunning, *podUnschedulable, *podUnschedulable}}, now)
{ClusterName: "c1", Object: podRunning},
{ClusterName: "c1", Object: podRunning},
{ClusterName: "c1", Object: podRunning},
{ClusterName: "c1", Object: podUnschedulable},
{ClusterName: "c1", Object: podUnschedulable},
{ClusterName: "c2", Object: podOther},
{ClusterName: "c2", Object: podOtherRS},
}
raport, err := AnalysePods(replicaSet.Spec.Selector, federatedObjects, now)
assert.NoError(t, err)
assert.Equal(t, 2, len(raport))
c1Raport := raport["c1"]
c2Raport := raport["c2"]
assert.Equal(t, PodAnalysisResult{ assert.Equal(t, PodAnalysisResult{
Total: 5, Total: 5,
RunningAndReady: 3, RunningAndReady: 3,
Unschedulable: 2, Unschedulable: 2,
}, c1Raport) }, result)
result = AnalyzePods(&api_v1.PodList{Items: []api_v1.Pod{*podOther}}, now)
assert.Equal(t, PodAnalysisResult{ assert.Equal(t, PodAnalysisResult{
Total: 1, Total: 1,
RunningAndReady: 0, RunningAndReady: 0,
Unschedulable: 0, Unschedulable: 0,
}, c2Raport) }, result)
} }
func newReplicaSet(selectorMap map[string]string) *v1beta1.ReplicaSet { func newReplicaSet(selectorMap map[string]string) *v1beta1.ReplicaSet {
...@@ -97,7 +77,7 @@ func newReplicaSet(selectorMap map[string]string) *v1beta1.ReplicaSet { ...@@ -97,7 +77,7 @@ func newReplicaSet(selectorMap map[string]string) *v1beta1.ReplicaSet {
rs := &v1beta1.ReplicaSet{ rs := &v1beta1.ReplicaSet{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "foobar", Name: "foobar",
Namespace: "default", Namespace: metav1.NamespaceDefault,
}, },
Spec: v1beta1.ReplicaSetSpec{ Spec: v1beta1.ReplicaSetSpec{
Replicas: &replicas, Replicas: &replicas,
...@@ -107,12 +87,11 @@ func newReplicaSet(selectorMap map[string]string) *v1beta1.ReplicaSet { ...@@ -107,12 +87,11 @@ func newReplicaSet(selectorMap map[string]string) *v1beta1.ReplicaSet {
return rs return rs
} }
func newPod(name string, rs *v1beta1.ReplicaSet, status api_v1.PodStatus) *api_v1.Pod { func newPod(name string, status api_v1.PodStatus) *api_v1.Pod {
return &api_v1.Pod{ return &api_v1.Pod{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: rs.Namespace, Namespace: metav1.NamespaceDefault,
Labels: rs.Spec.Selector.MatchLabels,
}, },
Status: status, Status: status,
} }
......
...@@ -29,7 +29,6 @@ go_library( ...@@ -29,7 +29,6 @@ go_library(
"//federation/client/clientset_generated/federation_clientset:go_default_library", "//federation/client/clientset_generated/federation_clientset:go_default_library",
"//federation/client/clientset_generated/federation_clientset/typed/core/v1:go_default_library", "//federation/client/clientset_generated/federation_clientset/typed/core/v1:go_default_library",
"//federation/pkg/federatedtypes:go_default_library", "//federation/pkg/federatedtypes:go_default_library",
"//federation/pkg/federation-controller/replicaset:go_default_library",
"//federation/pkg/federation-controller/util:go_default_library", "//federation/pkg/federation-controller/util:go_default_library",
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/v1:go_default_library", "//pkg/api/v1:go_default_library",
......
...@@ -37,7 +37,7 @@ import ( ...@@ -37,7 +37,7 @@ import (
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/util/uuid" "k8s.io/apimachinery/pkg/util/uuid"
"k8s.io/kubernetes/federation/apis/federation" "k8s.io/kubernetes/federation/apis/federation"
fedreplicsetcontroller "k8s.io/kubernetes/federation/pkg/federation-controller/replicaset" federatedtypes "k8s.io/kubernetes/federation/pkg/federatedtypes"
) )
const ( const (
...@@ -513,7 +513,7 @@ func newReplicaSetObj(namespace string, replicas int32, pref *federation.Replica ...@@ -513,7 +513,7 @@ func newReplicaSetObj(namespace string, replicas int32, pref *federation.Replica
if pref != nil { if pref != nil {
prefBytes, _ := json.Marshal(pref) prefBytes, _ := json.Marshal(pref)
prefString := string(prefBytes) prefString := string(prefBytes)
rs.Annotations[fedreplicsetcontroller.FedReplicaSetPreferencesAnnotation] = prefString rs.Annotations[federatedtypes.FedReplicaSetPreferencesAnnotation] = prefString
} }
return rs return rs
......
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