Commit ab95891e authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #30895 from mwielgus/rs-raporter

Automatic merge from submit-queue Federated replica set pod analyser A helper function that analyses a list of pods and checks how many of them (per cluster) are running or are unschedulable. This function should be replaced by a smarter/more effective informer that would count these values on the fly. Unfortunately this needs the ownerRef feature which may not be ready/enabled in 1.4. WIP because tests are not there yet. Will be added in the evening (PL time). Ref: #29741 cc: @quinton-hoole @jianhuiz @kubernetes/sig-cluster-federation
parents 2707c46a 03fd876d
/*
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 replicaset
import (
"fmt"
"time"
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
api "k8s.io/kubernetes/pkg/api"
unversioned "k8s.io/kubernetes/pkg/api/unversioned"
api_v1 "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
"k8s.io/kubernetes/pkg/labels"
)
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.
func AnalysePods(replicaSet *v1beta1.ReplicaSet, allPods []util.FederatedObject, currentTime time.Time) (map[string]PodAnalysisResult, error) {
selector, err := labelSelectorAsSelector(replicaSet.Spec.Selector)
if err != nil {
return nil, fmt.Errorf("invalid selector: %v", err)
}
result := make(map[string]PodAnalysisResult)
for _, fedObject := range allPods {
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 == "Unschedulable" &&
condition.LastTransitionTime.Add(UnschedulableThreshold).Before(currentTime) {
status.Unschedulable++
}
}
}
result[fedObject.ClusterName] = status
}
}
return result, nil
}
func labelSelectorAsSelector(ps *v1beta1.LabelSelector) (labels.Selector, error) {
unversionedSelector := unversioned.LabelSelector{}
if err := api.Scheme.Convert(ps, &unversionedSelector, nil); err != nil {
return nil, err
}
return unversioned.LabelSelectorAsSelector(&unversionedSelector)
}
/*
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 replicaset
import (
"testing"
"time"
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
"k8s.io/kubernetes/pkg/api/unversioned"
api_v1 "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
"github.com/stretchr/testify/assert"
)
func TestAnalyze(t *testing.T) {
now := time.Now()
replicaSet := newReplicaSet(map[string]string{"A": "B"})
replicaSet2 := newReplicaSet(map[string]string{"C": "D"})
podRunning := newPod("p1", replicaSet,
api_v1.PodStatus{
Phase: api_v1.PodRunning,
Conditions: []api_v1.PodCondition{
{
Type: api_v1.PodReady,
Status: api_v1.ConditionTrue,
},
},
})
podUnschedulable := newPod("pU", replicaSet,
api_v1.PodStatus{
Phase: api_v1.PodPending,
Conditions: []api_v1.PodCondition{
{
Type: api_v1.PodScheduled,
Status: api_v1.ConditionFalse,
Reason: "Unschedulable",
LastTransitionTime: unversioned.Time{Time: now.Add(-10 * time.Minute)},
},
},
})
podOther := newPod("pO", replicaSet,
api_v1.PodStatus{
Phase: api_v1.PodPending,
Conditions: []api_v1.PodCondition{},
})
podOtherRS := newPod("pO", replicaSet2,
api_v1.PodStatus{
Phase: api_v1.PodPending,
Conditions: []api_v1.PodCondition{},
})
federatedObjects := []util.FederatedObject{
{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, federatedObjects, now)
assert.NoError(t, err)
assert.Equal(t, 2, len(raport))
c1Raport := raport["c1"]
c2Raport := raport["c2"]
assert.Equal(t, PodAnalysisResult{
Total: 5,
RunningAndReady: 3,
Unschedulable: 2,
}, c1Raport)
assert.Equal(t, PodAnalysisResult{
Total: 1,
RunningAndReady: 0,
Unschedulable: 0,
}, c2Raport)
}
func newReplicaSet(selectorMap map[string]string) *v1beta1.ReplicaSet {
replicas := int32(3)
rs := &v1beta1.ReplicaSet{
ObjectMeta: api_v1.ObjectMeta{
Name: "foobar",
Namespace: "default",
},
Spec: v1beta1.ReplicaSetSpec{
Replicas: &replicas,
Selector: &v1beta1.LabelSelector{MatchLabels: selectorMap},
},
}
return rs
}
func newPod(name string, rs *v1beta1.ReplicaSet, status api_v1.PodStatus) *api_v1.Pod {
return &api_v1.Pod{
ObjectMeta: api_v1.ObjectMeta{
Name: name,
Namespace: rs.Namespace,
Labels: rs.Spec.Selector.MatchLabels,
},
Status: status,
}
}
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