2014-12-19 09:27:01 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2014 The Kubernetes Authors .
2014-12-19 09:27:01 +00:00
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 .
* /
2015-10-10 03:58:57 +00:00
package node
2014-12-19 09:27:01 +00:00
import (
"testing"
"time"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
2015-09-17 22:21:55 +00:00
"k8s.io/kubernetes/pkg/api/unversioned"
2016-01-08 21:38:02 +00:00
"k8s.io/kubernetes/pkg/apis/extensions"
2015-10-20 02:25:31 +00:00
"k8s.io/kubernetes/pkg/client/cache"
2016-02-16 22:16:45 +00:00
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
2016-02-12 21:07:45 +00:00
fakecloud "k8s.io/kubernetes/pkg/cloudprovider/providers/fake"
2016-03-11 02:43:55 +00:00
"k8s.io/kubernetes/pkg/util/diff"
2016-03-09 05:54:59 +00:00
"k8s.io/kubernetes/pkg/util/flowcontrol"
2016-02-12 21:07:45 +00:00
"k8s.io/kubernetes/pkg/util/wait"
2014-12-19 09:27:01 +00:00
)
2015-03-31 11:17:12 +00:00
const (
2015-04-07 19:36:09 +00:00
testNodeMonitorGracePeriod = 40 * time . Second
testNodeStartupGracePeriod = 60 * time . Second
2015-03-31 11:17:12 +00:00
testNodeMonitorPeriod = 5 * time . Second
)
2015-03-20 17:35:41 +00:00
func TestMonitorNodeStatusEvictPods ( t * testing . T ) {
2015-09-17 22:21:55 +00:00
fakeNow := unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC )
2015-03-31 11:17:12 +00:00
evictionTimeout := 10 * time . Minute
2015-03-31 15:15:39 +00:00
2016-05-16 09:20:23 +00:00
// Because of the logic that prevents NC from evicting anything when all Nodes are NotReady
// we need second healthy node in tests. Because of how the tests are written we need to update
// the status of this Node.
healthyNodeNewStatus := api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionTrue ,
// Node status has just been updated, and is NotReady for 10min.
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 9 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
}
2015-03-20 17:35:41 +00:00
table := [ ] struct {
2016-05-16 09:20:23 +00:00
fakeNodeHandler * FakeNodeHandler
daemonSets [ ] extensions . DaemonSet
timeToPass time . Duration
newNodeStatus api . NodeStatus
secondNodeNewStatus api . NodeStatus
expectedEvictPods bool
description string
2015-03-20 17:35:41 +00:00
} {
// Node created recently, with no status (happens only at cluster startup).
{
fakeNodeHandler : & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
2015-03-23 01:10:35 +00:00
CreationTimestamp : fakeNow ,
2015-03-20 17:35:41 +00:00
} ,
} ,
2016-05-16 09:20:23 +00:00
{
ObjectMeta : api . ObjectMeta {
Name : "node1" ,
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionTrue ,
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
} ,
2015-03-20 17:35:41 +00:00
} ,
2016-01-29 06:34:08 +00:00
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) } } ) ,
2015-03-20 17:35:41 +00:00
} ,
2016-05-16 09:20:23 +00:00
daemonSets : nil ,
timeToPass : 0 ,
newNodeStatus : api . NodeStatus { } ,
secondNodeNewStatus : healthyNodeNewStatus ,
expectedEvictPods : false ,
description : "Node created recently, with no status." ,
2015-03-20 17:35:41 +00:00
} ,
2015-03-23 01:10:35 +00:00
// Node created long time ago, and kubelet posted NotReady for a short period of time.
2015-03-20 17:35:41 +00:00
{
fakeNodeHandler : & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
2015-09-17 22:21:55 +00:00
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
2015-03-20 17:35:41 +00:00
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
2015-03-31 15:15:39 +00:00
Type : api . NodeReady ,
Status : api . ConditionFalse ,
2015-09-17 22:21:55 +00:00
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
2015-03-20 17:35:41 +00:00
} ,
} ,
} ,
} ,
2016-05-16 09:20:23 +00:00
{
ObjectMeta : api . ObjectMeta {
Name : "node1" ,
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionTrue ,
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
} ,
2015-03-20 17:35:41 +00:00
} ,
2016-01-29 06:34:08 +00:00
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) } } ) ,
2015-03-20 17:35:41 +00:00
} ,
2016-01-08 21:38:02 +00:00
daemonSets : nil ,
2015-03-31 11:17:12 +00:00
timeToPass : evictionTimeout ,
2015-03-31 15:15:39 +00:00
newNodeStatus : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionFalse ,
// Node status has just been updated, and is NotReady for 10min.
2015-09-17 22:21:55 +00:00
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 9 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
2015-03-31 15:15:39 +00:00
} ,
} ,
} ,
2016-05-16 09:20:23 +00:00
secondNodeNewStatus : healthyNodeNewStatus ,
expectedEvictPods : false ,
description : "Node created long time ago, and kubelet posted NotReady for a short period of time." ,
2015-03-20 17:35:41 +00:00
} ,
2016-01-08 21:38:02 +00:00
// Pod is ds-managed, and kubelet posted NotReady for a long period of time.
{
fakeNodeHandler : & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionFalse ,
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
} ,
2016-05-16 09:20:23 +00:00
{
ObjectMeta : api . ObjectMeta {
Name : "node1" ,
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionTrue ,
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
} ,
2016-01-08 21:38:02 +00:00
} ,
2016-01-29 06:34:08 +00:00
Clientset : fake . NewSimpleClientset (
2016-01-08 21:38:02 +00:00
& api . PodList {
Items : [ ] api . Pod {
{
ObjectMeta : api . ObjectMeta {
Name : "pod0" ,
Namespace : "default" ,
Labels : map [ string ] string { "daemon" : "yes" } ,
} ,
Spec : api . PodSpec {
NodeName : "node0" ,
} ,
} ,
} ,
} ,
) ,
} ,
daemonSets : [ ] extensions . DaemonSet {
{
ObjectMeta : api . ObjectMeta {
Name : "ds0" ,
Namespace : "default" ,
} ,
Spec : extensions . DaemonSetSpec {
2016-02-02 05:34:42 +00:00
Selector : & unversioned . LabelSelector {
2016-01-08 21:38:02 +00:00
MatchLabels : map [ string ] string { "daemon" : "yes" } ,
} ,
} ,
} ,
} ,
timeToPass : time . Hour ,
newNodeStatus : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionFalse ,
// Node status has just been updated, and is NotReady for 1hr.
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 59 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
2016-05-16 09:20:23 +00:00
secondNodeNewStatus : healthyNodeNewStatus ,
expectedEvictPods : false ,
description : "Pod is ds-managed, and kubelet posted NotReady for a long period of time." ,
2016-01-08 21:38:02 +00:00
} ,
2015-03-23 01:10:35 +00:00
// Node created long time ago, and kubelet posted NotReady for a long period of time.
2015-03-20 17:35:41 +00:00
{
fakeNodeHandler : & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
2015-09-17 22:21:55 +00:00
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
2015-03-20 17:35:41 +00:00
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
2015-03-31 15:15:39 +00:00
Type : api . NodeReady ,
Status : api . ConditionFalse ,
2015-09-17 22:21:55 +00:00
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
2015-03-20 17:35:41 +00:00
} ,
} ,
} ,
} ,
2016-05-16 09:20:23 +00:00
{
ObjectMeta : api . ObjectMeta {
Name : "node1" ,
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionTrue ,
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
} ,
2015-03-20 17:35:41 +00:00
} ,
2016-01-29 06:34:08 +00:00
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) } } ) ,
2015-03-20 17:35:41 +00:00
} ,
2016-01-08 21:38:02 +00:00
daemonSets : nil ,
2015-03-31 15:15:39 +00:00
timeToPass : time . Hour ,
newNodeStatus : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionFalse ,
// Node status has just been updated, and is NotReady for 1hr.
2015-09-17 22:21:55 +00:00
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 59 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
2015-03-31 15:15:39 +00:00
} ,
} ,
} ,
2016-05-16 09:20:23 +00:00
secondNodeNewStatus : healthyNodeNewStatus ,
expectedEvictPods : true ,
description : "Node created long time ago, and kubelet posted NotReady for a long period of time." ,
2015-03-20 17:35:41 +00:00
} ,
2015-03-23 01:10:35 +00:00
// Node created long time ago, node controller posted Unknown for a short period of time.
2015-03-20 17:35:41 +00:00
{
fakeNodeHandler : & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
2015-09-17 22:21:55 +00:00
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
2015-03-20 17:35:41 +00:00
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
2015-03-31 15:15:39 +00:00
Type : api . NodeReady ,
Status : api . ConditionUnknown ,
2015-09-17 22:21:55 +00:00
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
2015-03-20 17:35:41 +00:00
} ,
} ,
} ,
} ,
2016-05-16 09:20:23 +00:00
{
ObjectMeta : api . ObjectMeta {
Name : "node1" ,
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionTrue ,
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
} ,
2015-03-20 17:35:41 +00:00
} ,
2016-01-29 06:34:08 +00:00
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) } } ) ,
2015-03-20 17:35:41 +00:00
} ,
2016-01-08 21:38:02 +00:00
daemonSets : nil ,
2015-03-31 11:17:12 +00:00
timeToPass : evictionTimeout - testNodeMonitorGracePeriod ,
2015-03-31 15:15:39 +00:00
newNodeStatus : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionUnknown ,
// Node status was updated by nodecontroller 10min ago
2015-09-17 22:21:55 +00:00
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
2015-03-31 15:15:39 +00:00
} ,
} ,
} ,
2016-05-16 09:20:23 +00:00
secondNodeNewStatus : healthyNodeNewStatus ,
expectedEvictPods : false ,
description : "Node created long time ago, node controller posted Unknown for a short period of time." ,
2015-03-20 17:35:41 +00:00
} ,
2015-03-23 01:10:35 +00:00
// Node created long time ago, node controller posted Unknown for a long period of time.
2015-03-20 17:35:41 +00:00
{
fakeNodeHandler : & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
2015-09-17 22:21:55 +00:00
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
2015-03-20 17:35:41 +00:00
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
2015-03-31 15:15:39 +00:00
Type : api . NodeReady ,
Status : api . ConditionUnknown ,
2015-09-17 22:21:55 +00:00
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
2015-03-20 17:35:41 +00:00
} ,
} ,
} ,
} ,
2016-05-16 09:20:23 +00:00
{
ObjectMeta : api . ObjectMeta {
Name : "node1" ,
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionTrue ,
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
} ,
} ,
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) } } ) ,
} ,
daemonSets : nil ,
timeToPass : 60 * time . Minute ,
newNodeStatus : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionUnknown ,
// Node status was updated by nodecontroller 1hr ago
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
secondNodeNewStatus : healthyNodeNewStatus ,
expectedEvictPods : true ,
description : "Node created long time ago, node controller posted Unknown for a long period of time." ,
} ,
// NetworkSegmentation: Node created long time ago, node controller posted Unknown for a long period of time on both Nodes.
{
fakeNodeHandler : & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionUnknown ,
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
} ,
{
ObjectMeta : api . ObjectMeta {
Name : "node1" ,
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionUnknown ,
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
} ,
} ,
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) } } ) ,
} ,
daemonSets : nil ,
timeToPass : 60 * time . Minute ,
newNodeStatus : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionUnknown ,
// Node status was updated by nodecontroller 1hr ago
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
secondNodeNewStatus : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionUnknown ,
// Node status was updated by nodecontroller 1hr ago
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
expectedEvictPods : false ,
description : "Network Segmentation: Node created long time ago, node controller posted Unknown for a long period of time on both Nodes." ,
} ,
// NetworkSegmentation: Node created long time ago, node controller posted Unknown for a long period
// of on first Node, eviction should stop even though -master Node is healthy.
{
fakeNodeHandler : & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionUnknown ,
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
} ,
{
ObjectMeta : api . ObjectMeta {
Name : "node-master" ,
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionTrue ,
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
} ,
2015-03-20 17:35:41 +00:00
} ,
2016-01-29 06:34:08 +00:00
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) } } ) ,
2015-03-20 17:35:41 +00:00
} ,
2016-01-08 21:38:02 +00:00
daemonSets : nil ,
2015-03-31 15:15:39 +00:00
timeToPass : 60 * time . Minute ,
newNodeStatus : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionUnknown ,
// Node status was updated by nodecontroller 1hr ago
2015-09-17 22:21:55 +00:00
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
2015-03-31 15:15:39 +00:00
} ,
} ,
} ,
2016-05-16 09:20:23 +00:00
secondNodeNewStatus : healthyNodeNewStatus ,
expectedEvictPods : false ,
description : "NetworkSegmentation: Node created long time ago, node controller posted Unknown for a long period of on first Node, eviction should stop even though -master Node is healthy" ,
2015-03-20 17:35:41 +00:00
} ,
}
for _ , item := range table {
2015-08-04 12:44:14 +00:00
nodeController := NewNodeController ( nil , item . fakeNodeHandler ,
2016-03-09 05:54:59 +00:00
evictionTimeout , flowcontrol . NewFakeAlwaysRateLimiter ( ) , flowcontrol . NewFakeAlwaysRateLimiter ( ) , testNodeMonitorGracePeriod ,
2016-05-20 11:21:52 +00:00
testNodeStartupGracePeriod , testNodeMonitorPeriod , nil , nil , 0 , false )
2015-09-17 22:21:55 +00:00
nodeController . now = func ( ) unversioned . Time { return fakeNow }
2016-01-08 21:38:02 +00:00
for _ , ds := range item . daemonSets {
nodeController . daemonSetStore . Add ( & ds )
}
2015-04-10 22:30:11 +00:00
if err := nodeController . monitorNodeStatus ( ) ; err != nil {
2015-03-20 17:35:41 +00:00
t . Errorf ( "unexpected error: %v" , err )
}
2015-03-31 15:15:39 +00:00
if item . timeToPass > 0 {
2015-09-17 22:21:55 +00:00
nodeController . now = func ( ) unversioned . Time { return unversioned . Time { Time : fakeNow . Add ( item . timeToPass ) } }
2015-03-31 15:15:39 +00:00
item . fakeNodeHandler . Existing [ 0 ] . Status = item . newNodeStatus
2016-05-16 09:20:23 +00:00
item . fakeNodeHandler . Existing [ 1 ] . Status = item . secondNodeNewStatus
2015-03-31 15:15:39 +00:00
}
2015-04-10 22:30:11 +00:00
if err := nodeController . monitorNodeStatus ( ) ; err != nil {
2015-03-31 15:15:39 +00:00
t . Errorf ( "unexpected error: %v" , err )
}
2015-05-19 11:23:59 +00:00
2015-08-21 01:11:40 +00:00
nodeController . podEvictor . Try ( func ( value TimedValue ) ( bool , time . Duration ) {
2016-07-11 11:23:53 +00:00
remaining , _ := deletePods ( item . fakeNodeHandler , nodeController . recorder , value . Value , nodeController . daemonSetStore )
2015-08-21 01:11:40 +00:00
if remaining {
nodeController . terminationEvictor . Add ( value . Value )
}
return true , 0
} )
nodeController . podEvictor . Try ( func ( value TimedValue ) ( bool , time . Duration ) {
2016-07-11 11:23:53 +00:00
terminatePods ( item . fakeNodeHandler , nodeController . recorder , value . Value , value . AddedAt , nodeController . maximumGracePeriod )
2015-08-21 01:11:40 +00:00
return true , 0
} )
2015-03-20 17:35:41 +00:00
podEvicted := false
2015-07-06 21:37:46 +00:00
for _ , action := range item . fakeNodeHandler . Actions ( ) {
2016-04-13 22:33:15 +00:00
if action . GetVerb ( ) == "delete" && action . GetResource ( ) . Resource == "pods" {
2015-03-20 17:35:41 +00:00
podEvicted = true
}
}
2015-05-19 11:23:59 +00:00
2015-03-20 17:35:41 +00:00
if item . expectedEvictPods != podEvicted {
2015-03-31 11:17:12 +00:00
t . Errorf ( "expected pod eviction: %+v, got %+v for %+v" , item . expectedEvictPods ,
podEvicted , item . description )
2015-03-20 17:35:41 +00:00
}
}
}
2016-02-12 21:07:45 +00:00
// TestCloudProviderNoRateLimit tests that monitorNodes() immediately deletes
// pods and the node when kubelet has not reported, and the cloudprovider says
// the node is gone.
func TestCloudProviderNoRateLimit ( t * testing . T ) {
fnh := & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionUnknown ,
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
} ,
} ,
} ,
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) , * newPod ( "pod1" , "node0" ) } } ) ,
deleteWaitChan : make ( chan struct { } ) ,
}
nodeController := NewNodeController ( nil , fnh , 10 * time . Minute ,
2016-03-09 05:54:59 +00:00
flowcontrol . NewFakeAlwaysRateLimiter ( ) , flowcontrol . NewFakeAlwaysRateLimiter ( ) ,
2016-02-12 21:07:45 +00:00
testNodeMonitorGracePeriod , testNodeStartupGracePeriod ,
2016-05-20 11:21:52 +00:00
testNodeMonitorPeriod , nil , nil , 0 , false )
2016-02-12 21:07:45 +00:00
nodeController . cloud = & fakecloud . FakeCloud { }
nodeController . now = func ( ) unversioned . Time { return unversioned . Date ( 2016 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) }
nodeController . nodeExistsInCloudProvider = func ( nodeName string ) ( bool , error ) {
return false , nil
}
// monitorNodeStatus should allow this node to be immediately deleted
if err := nodeController . monitorNodeStatus ( ) ; err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
select {
case <- fnh . deleteWaitChan :
case <- time . After ( wait . ForeverTestTimeout ) :
t . Errorf ( "Timed out waiting %v for node to be deleted" , wait . ForeverTestTimeout )
}
if len ( fnh . DeletedNodes ) != 1 || fnh . DeletedNodes [ 0 ] . Name != "node0" {
t . Errorf ( "Node was not deleted" )
}
if nodeOnQueue := nodeController . podEvictor . Remove ( "node0" ) ; nodeOnQueue {
t . Errorf ( "Node was queued for eviction. Should have been immediately deleted." )
}
}
2015-03-20 17:35:41 +00:00
func TestMonitorNodeStatusUpdateStatus ( t * testing . T ) {
2015-09-17 22:21:55 +00:00
fakeNow := unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC )
2015-01-16 22:28:20 +00:00
table := [ ] struct {
fakeNodeHandler * FakeNodeHandler
2015-03-31 15:15:39 +00:00
timeToPass time . Duration
newNodeStatus api . NodeStatus
expectedEvictPods bool
2015-01-16 22:28:20 +00:00
expectedRequestCount int
2015-03-12 03:00:52 +00:00
expectedNodes [ ] * api . Node
2015-01-16 22:28:20 +00:00
} {
2015-03-23 01:10:35 +00:00
// Node created long time ago, without status:
// Expect Unknown status posted from node controller.
2015-01-16 22:28:20 +00:00
{
fakeNodeHandler : & FakeNodeHandler {
2015-03-12 03:00:52 +00:00
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
2015-09-17 22:21:55 +00:00
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
2015-03-12 03:00:52 +00:00
} ,
} ,
} ,
2016-01-29 06:34:08 +00:00
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) } } ) ,
2015-01-30 20:50:47 +00:00
} ,
2015-03-12 03:00:52 +00:00
expectedRequestCount : 2 , // List+Update
2015-01-16 22:28:20 +00:00
expectedNodes : [ ] * api . Node {
{
2015-03-12 03:00:52 +00:00
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
2015-09-17 22:21:55 +00:00
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
2015-03-12 03:00:52 +00:00
} ,
2015-01-30 20:50:47 +00:00
Status : api . NodeStatus {
2015-02-04 21:56:59 +00:00
Conditions : [ ] api . NodeCondition {
{
2015-03-12 03:00:52 +00:00
Type : api . NodeReady ,
2015-03-20 17:35:41 +00:00
Status : api . ConditionUnknown ,
2015-09-11 10:08:09 +00:00
Reason : "NodeStatusNeverUpdated" ,
2015-10-22 19:47:43 +00:00
Message : "Kubelet never posted node status." ,
LastHeartbeatTime : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : fakeNow ,
} ,
{
Type : api . NodeOutOfDisk ,
Status : api . ConditionUnknown ,
Reason : "NodeStatusNeverUpdated" ,
Message : "Kubelet never posted node status." ,
2015-09-17 22:21:55 +00:00
LastHeartbeatTime : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
2015-03-23 01:10:35 +00:00
LastTransitionTime : fakeNow ,
2015-02-17 20:03:14 +00:00
} ,
2015-02-04 21:56:59 +00:00
} ,
2015-03-12 03:00:52 +00:00
} ,
} ,
} ,
} ,
2015-03-23 01:10:35 +00:00
// Node created recently, without status.
// Expect no action from node controller (within startup grace period).
2015-03-12 03:00:52 +00:00
{
fakeNodeHandler : & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
2015-03-23 01:10:35 +00:00
CreationTimestamp : fakeNow ,
2015-03-12 03:00:52 +00:00
} ,
} ,
} ,
2016-01-29 06:34:08 +00:00
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) } } ) ,
2015-03-12 03:00:52 +00:00
} ,
expectedRequestCount : 1 , // List
expectedNodes : nil ,
} ,
2015-03-23 01:10:35 +00:00
// Node created long time ago, with status updated by kubelet exceeds grace period.
// Expect Unknown status posted from node controller.
2015-03-12 03:00:52 +00:00
{
fakeNodeHandler : & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
2015-09-17 22:21:55 +00:00
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
2015-03-12 03:00:52 +00:00
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
2015-03-23 01:10:35 +00:00
Type : api . NodeReady ,
2015-03-23 18:33:55 +00:00
Status : api . ConditionTrue ,
2015-03-23 01:10:35 +00:00
// Node status hasn't been updated for 1hr.
2015-09-17 22:21:55 +00:00
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
2015-03-12 03:00:52 +00:00
} ,
2015-10-22 19:47:43 +00:00
{
Type : api . NodeOutOfDisk ,
Status : api . ConditionFalse ,
// Node status hasn't been updated for 1hr.
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
2015-03-12 03:00:52 +00:00
} ,
2015-03-24 17:24:07 +00:00
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
} ,
} ,
2015-03-25 13:44:40 +00:00
Spec : api . NodeSpec {
ExternalID : "node0" ,
} ,
2015-01-30 20:50:47 +00:00
} ,
2015-01-16 22:28:20 +00:00
} ,
2016-01-29 06:34:08 +00:00
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) } } ) ,
2015-03-12 03:00:52 +00:00
} ,
2015-03-31 15:15:39 +00:00
expectedRequestCount : 3 , // (List+)List+Update
timeToPass : time . Hour ,
newNodeStatus : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionTrue ,
// Node status hasn't been updated for 1hr.
2015-09-17 22:21:55 +00:00
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
2015-03-31 15:15:39 +00:00
} ,
2015-10-22 19:47:43 +00:00
{
Type : api . NodeOutOfDisk ,
Status : api . ConditionFalse ,
// Node status hasn't been updated for 1hr.
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
2015-03-31 15:15:39 +00:00
} ,
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
} ,
} ,
2015-03-12 03:00:52 +00:00
expectedNodes : [ ] * api . Node {
2015-01-16 22:28:20 +00:00
{
2015-03-12 03:00:52 +00:00
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
2015-09-17 22:21:55 +00:00
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
2015-03-12 03:00:52 +00:00
} ,
2015-01-30 20:50:47 +00:00
Status : api . NodeStatus {
2015-02-04 21:56:59 +00:00
Conditions : [ ] api . NodeCondition {
{
2015-03-12 03:00:52 +00:00
Type : api . NodeReady ,
2015-03-20 17:35:41 +00:00
Status : api . ConditionUnknown ,
2015-10-22 19:47:43 +00:00
Reason : "NodeStatusUnknown" ,
Message : "Kubelet stopped posting node status." ,
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Time { Time : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) . Add ( time . Hour ) } ,
} ,
{
Type : api . NodeOutOfDisk ,
Status : api . ConditionUnknown ,
Reason : "NodeStatusUnknown" ,
Message : "Kubelet stopped posting node status." ,
2015-09-17 22:21:55 +00:00
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Time { Time : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) . Add ( time . Hour ) } ,
2015-02-17 20:03:14 +00:00
} ,
2015-02-04 21:56:59 +00:00
} ,
2015-03-24 17:24:07 +00:00
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
} ,
} ,
2015-03-25 13:44:40 +00:00
Spec : api . NodeSpec {
ExternalID : "node0" ,
} ,
2015-03-12 03:00:52 +00:00
} ,
} ,
} ,
// Node created long time ago, with status updated recently.
2015-03-23 01:10:35 +00:00
// Expect no action from node controller (within monitor grace period).
2015-03-12 03:00:52 +00:00
{
fakeNodeHandler : & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
2015-09-17 22:21:55 +00:00
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
2015-03-12 03:00:52 +00:00
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
2015-03-23 01:10:35 +00:00
Type : api . NodeReady ,
2015-03-23 18:33:55 +00:00
Status : api . ConditionTrue ,
2015-03-23 01:10:35 +00:00
// Node status has just been updated.
2015-03-27 14:09:51 +00:00
LastHeartbeatTime : fakeNow ,
2015-03-23 01:10:35 +00:00
LastTransitionTime : fakeNow ,
2015-03-12 03:00:52 +00:00
} ,
} ,
2015-03-24 17:24:07 +00:00
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
} ,
} ,
2015-03-25 13:44:40 +00:00
Spec : api . NodeSpec {
ExternalID : "node0" ,
} ,
2015-01-30 20:50:47 +00:00
} ,
2015-01-16 22:28:20 +00:00
} ,
2016-01-29 06:34:08 +00:00
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) } } ) ,
2015-01-16 22:28:20 +00:00
} ,
2015-03-12 03:00:52 +00:00
expectedRequestCount : 1 , // List
expectedNodes : nil ,
2015-01-16 22:28:20 +00:00
} ,
2014-12-19 09:27:01 +00:00
}
2015-01-16 22:28:20 +00:00
2015-10-22 19:47:43 +00:00
for i , item := range table {
2016-03-09 05:54:59 +00:00
nodeController := NewNodeController ( nil , item . fakeNodeHandler , 5 * time . Minute , flowcontrol . NewFakeAlwaysRateLimiter ( ) ,
2016-05-20 11:21:52 +00:00
flowcontrol . NewFakeAlwaysRateLimiter ( ) , testNodeMonitorGracePeriod , testNodeStartupGracePeriod , testNodeMonitorPeriod , nil , nil , 0 , false )
2015-09-17 22:21:55 +00:00
nodeController . now = func ( ) unversioned . Time { return fakeNow }
2015-04-10 22:30:11 +00:00
if err := nodeController . monitorNodeStatus ( ) ; err != nil {
2015-01-16 22:28:20 +00:00
t . Errorf ( "unexpected error: %v" , err )
}
2015-03-31 15:15:39 +00:00
if item . timeToPass > 0 {
2015-09-17 22:21:55 +00:00
nodeController . now = func ( ) unversioned . Time { return unversioned . Time { Time : fakeNow . Add ( item . timeToPass ) } }
2015-03-31 15:15:39 +00:00
item . fakeNodeHandler . Existing [ 0 ] . Status = item . newNodeStatus
2015-04-10 22:30:11 +00:00
if err := nodeController . monitorNodeStatus ( ) ; err != nil {
2015-03-31 15:15:39 +00:00
t . Errorf ( "unexpected error: %v" , err )
}
}
2015-03-12 03:00:52 +00:00
if item . expectedRequestCount != item . fakeNodeHandler . RequestCount {
2015-01-16 22:28:20 +00:00
t . Errorf ( "expected %v call, but got %v." , item . expectedRequestCount , item . fakeNodeHandler . RequestCount )
}
2015-04-08 09:32:47 +00:00
if len ( item . fakeNodeHandler . UpdatedNodes ) > 0 && ! api . Semantic . DeepEqual ( item . expectedNodes , item . fakeNodeHandler . UpdatedNodes ) {
2016-03-11 02:43:55 +00:00
t . Errorf ( "Case[%d] unexpected nodes: %s" , i , diff . ObjectDiff ( item . expectedNodes [ 0 ] , item . fakeNodeHandler . UpdatedNodes [ 0 ] ) )
2015-10-22 19:47:43 +00:00
}
if len ( item . fakeNodeHandler . UpdatedNodeStatuses ) > 0 && ! api . Semantic . DeepEqual ( item . expectedNodes , item . fakeNodeHandler . UpdatedNodeStatuses ) {
2016-03-11 02:43:55 +00:00
t . Errorf ( "Case[%d] unexpected nodes: %s" , i , diff . ObjectDiff ( item . expectedNodes [ 0 ] , item . fakeNodeHandler . UpdatedNodeStatuses [ 0 ] ) )
2015-01-16 22:28:20 +00:00
}
2014-12-19 09:27:01 +00:00
}
2015-01-16 22:28:20 +00:00
}
2015-11-24 22:46:17 +00:00
func TestMonitorNodeStatusMarkPodsNotReady ( t * testing . T ) {
fakeNow := unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC )
table := [ ] struct {
fakeNodeHandler * FakeNodeHandler
timeToPass time . Duration
newNodeStatus api . NodeStatus
expectedPodStatusUpdate bool
} {
// Node created recently, without status.
// Expect no action from node controller (within startup grace period).
{
fakeNodeHandler : & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
CreationTimestamp : fakeNow ,
} ,
} ,
} ,
2016-01-29 06:34:08 +00:00
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) } } ) ,
2015-11-24 22:46:17 +00:00
} ,
expectedPodStatusUpdate : false ,
} ,
// Node created long time ago, with status updated recently.
// Expect no action from node controller (within monitor grace period).
{
fakeNodeHandler : & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionTrue ,
// Node status has just been updated.
LastHeartbeatTime : fakeNow ,
LastTransitionTime : fakeNow ,
} ,
} ,
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
} ,
} ,
Spec : api . NodeSpec {
ExternalID : "node0" ,
} ,
} ,
} ,
2016-01-29 06:34:08 +00:00
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) } } ) ,
2015-11-24 22:46:17 +00:00
} ,
expectedPodStatusUpdate : false ,
} ,
// Node created long time ago, with status updated by kubelet exceeds grace period.
// Expect pods status updated and Unknown node status posted from node controller
{
fakeNodeHandler : & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionTrue ,
// Node status hasn't been updated for 1hr.
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
{
Type : api . NodeOutOfDisk ,
Status : api . ConditionFalse ,
// Node status hasn't been updated for 1hr.
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
} ,
} ,
Spec : api . NodeSpec {
ExternalID : "node0" ,
} ,
} ,
} ,
2016-01-29 06:34:08 +00:00
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) } } ) ,
2015-11-24 22:46:17 +00:00
} ,
timeToPass : 1 * time . Minute ,
newNodeStatus : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionTrue ,
// Node status hasn't been updated for 1hr.
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
{
Type : api . NodeOutOfDisk ,
Status : api . ConditionFalse ,
// Node status hasn't been updated for 1hr.
LastHeartbeatTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
LastTransitionTime : unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC ) ,
} ,
} ,
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
} ,
} ,
expectedPodStatusUpdate : true ,
} ,
}
for i , item := range table {
2016-03-09 05:54:59 +00:00
nodeController := NewNodeController ( nil , item . fakeNodeHandler , 5 * time . Minute , flowcontrol . NewFakeAlwaysRateLimiter ( ) ,
2016-05-20 11:21:52 +00:00
flowcontrol . NewFakeAlwaysRateLimiter ( ) , testNodeMonitorGracePeriod , testNodeStartupGracePeriod , testNodeMonitorPeriod , nil , nil , 0 , false )
2015-11-24 22:46:17 +00:00
nodeController . now = func ( ) unversioned . Time { return fakeNow }
if err := nodeController . monitorNodeStatus ( ) ; err != nil {
t . Errorf ( "Case[%d] unexpected error: %v" , i , err )
}
if item . timeToPass > 0 {
nodeController . now = func ( ) unversioned . Time { return unversioned . Time { Time : fakeNow . Add ( item . timeToPass ) } }
item . fakeNodeHandler . Existing [ 0 ] . Status = item . newNodeStatus
if err := nodeController . monitorNodeStatus ( ) ; err != nil {
t . Errorf ( "Case[%d] unexpected error: %v" , i , err )
}
}
podStatusUpdated := false
for _ , action := range item . fakeNodeHandler . Actions ( ) {
2016-04-13 22:33:15 +00:00
if action . GetVerb ( ) == "update" && action . GetResource ( ) . Resource == "pods" && action . GetSubresource ( ) == "status" {
2015-11-24 22:46:17 +00:00
podStatusUpdated = true
}
}
if podStatusUpdated != item . expectedPodStatusUpdate {
t . Errorf ( "Case[%d] expect pod status updated to be %v, but got %v" , i , item . expectedPodStatusUpdate , podStatusUpdated )
}
}
}
2015-08-05 13:22:13 +00:00
func TestNodeDeletion ( t * testing . T ) {
2015-09-17 22:21:55 +00:00
fakeNow := unversioned . Date ( 2015 , 1 , 1 , 12 , 0 , 0 , 0 , time . UTC )
2015-08-05 13:22:13 +00:00
fakeNodeHandler := & FakeNodeHandler {
Existing : [ ] * api . Node {
{
ObjectMeta : api . ObjectMeta {
Name : "node0" ,
2015-09-17 22:21:55 +00:00
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
2015-08-05 13:22:13 +00:00
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionTrue ,
// Node status has just been updated.
LastHeartbeatTime : fakeNow ,
LastTransitionTime : fakeNow ,
} ,
} ,
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
} ,
} ,
Spec : api . NodeSpec {
ExternalID : "node0" ,
} ,
} ,
{
ObjectMeta : api . ObjectMeta {
Name : "node1" ,
2015-09-17 22:21:55 +00:00
CreationTimestamp : unversioned . Date ( 2012 , 1 , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
2015-08-05 13:22:13 +00:00
} ,
Status : api . NodeStatus {
Conditions : [ ] api . NodeCondition {
{
Type : api . NodeReady ,
Status : api . ConditionTrue ,
// Node status has just been updated.
LastHeartbeatTime : fakeNow ,
LastTransitionTime : fakeNow ,
} ,
} ,
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
} ,
} ,
Spec : api . NodeSpec {
ExternalID : "node0" ,
} ,
} ,
} ,
2016-01-29 06:34:08 +00:00
Clientset : fake . NewSimpleClientset ( & api . PodList { Items : [ ] api . Pod { * newPod ( "pod0" , "node0" ) , * newPod ( "pod1" , "node1" ) } } ) ,
2015-08-05 13:22:13 +00:00
}
2016-03-09 05:54:59 +00:00
nodeController := NewNodeController ( nil , fakeNodeHandler , 5 * time . Minute , flowcontrol . NewFakeAlwaysRateLimiter ( ) , flowcontrol . NewFakeAlwaysRateLimiter ( ) ,
2016-05-20 11:21:52 +00:00
testNodeMonitorGracePeriod , testNodeStartupGracePeriod , testNodeMonitorPeriod , nil , nil , 0 , false )
2015-09-17 22:21:55 +00:00
nodeController . now = func ( ) unversioned . Time { return fakeNow }
2015-08-05 13:22:13 +00:00
if err := nodeController . monitorNodeStatus ( ) ; err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
2016-01-29 06:34:08 +00:00
fakeNodeHandler . Delete ( "node1" , nil )
2015-08-05 13:22:13 +00:00
if err := nodeController . monitorNodeStatus ( ) ; err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
2015-08-21 01:11:40 +00:00
nodeController . podEvictor . Try ( func ( value TimedValue ) ( bool , time . Duration ) {
2016-07-11 11:23:53 +00:00
deletePods ( fakeNodeHandler , nodeController . recorder , value . Value , nodeController . daemonSetStore )
2015-08-21 01:11:40 +00:00
return true , 0
} )
2015-08-05 13:22:13 +00:00
podEvicted := false
for _ , action := range fakeNodeHandler . Actions ( ) {
2016-04-13 22:33:15 +00:00
if action . GetVerb ( ) == "delete" && action . GetResource ( ) . Resource == "pods" {
2015-08-05 13:22:13 +00:00
podEvicted = true
}
}
if ! podEvicted {
t . Error ( "expected pods to be evicted from the deleted node" )
}
}
2015-10-20 02:25:31 +00:00
func TestCheckPod ( t * testing . T ) {
tcs := [ ] struct {
pod api . Pod
prune bool
} {
{
pod : api . Pod {
ObjectMeta : api . ObjectMeta { DeletionTimestamp : nil } ,
Spec : api . PodSpec { NodeName : "new" } ,
} ,
prune : false ,
} ,
{
pod : api . Pod {
ObjectMeta : api . ObjectMeta { DeletionTimestamp : nil } ,
Spec : api . PodSpec { NodeName : "old" } ,
} ,
prune : false ,
} ,
{
pod : api . Pod {
ObjectMeta : api . ObjectMeta { DeletionTimestamp : nil } ,
Spec : api . PodSpec { NodeName : "" } ,
} ,
prune : false ,
} ,
{
pod : api . Pod {
ObjectMeta : api . ObjectMeta { DeletionTimestamp : nil } ,
Spec : api . PodSpec { NodeName : "nonexistant" } ,
} ,
prune : false ,
} ,
{
pod : api . Pod {
ObjectMeta : api . ObjectMeta { DeletionTimestamp : & unversioned . Time { } } ,
Spec : api . PodSpec { NodeName : "new" } ,
} ,
prune : false ,
} ,
{
pod : api . Pod {
ObjectMeta : api . ObjectMeta { DeletionTimestamp : & unversioned . Time { } } ,
Spec : api . PodSpec { NodeName : "old" } ,
} ,
prune : true ,
} ,
2015-12-03 22:01:16 +00:00
{
pod : api . Pod {
ObjectMeta : api . ObjectMeta { DeletionTimestamp : & unversioned . Time { } } ,
Spec : api . PodSpec { NodeName : "older" } ,
} ,
prune : true ,
} ,
{
pod : api . Pod {
ObjectMeta : api . ObjectMeta { DeletionTimestamp : & unversioned . Time { } } ,
Spec : api . PodSpec { NodeName : "oldest" } ,
} ,
prune : true ,
} ,
2015-10-20 02:25:31 +00:00
{
pod : api . Pod {
ObjectMeta : api . ObjectMeta { DeletionTimestamp : & unversioned . Time { } } ,
Spec : api . PodSpec { NodeName : "" } ,
} ,
prune : true ,
} ,
{
pod : api . Pod {
ObjectMeta : api . ObjectMeta { DeletionTimestamp : & unversioned . Time { } } ,
Spec : api . PodSpec { NodeName : "nonexistant" } ,
} ,
prune : true ,
} ,
}
2016-05-20 11:21:52 +00:00
nc := NewNodeController ( nil , nil , 0 , nil , nil , 0 , 0 , 0 , nil , nil , 0 , false )
2015-10-20 02:25:31 +00:00
nc . nodeStore . Store = cache . NewStore ( cache . MetaNamespaceKeyFunc )
nc . nodeStore . Store . Add ( & api . Node {
ObjectMeta : api . ObjectMeta {
Name : "new" ,
} ,
Status : api . NodeStatus {
NodeInfo : api . NodeSystemInfo {
KubeletVersion : "v1.1.0" ,
} ,
} ,
} )
nc . nodeStore . Store . Add ( & api . Node {
ObjectMeta : api . ObjectMeta {
Name : "old" ,
} ,
Status : api . NodeStatus {
NodeInfo : api . NodeSystemInfo {
KubeletVersion : "v1.0.0" ,
} ,
} ,
} )
2015-12-03 22:01:16 +00:00
nc . nodeStore . Store . Add ( & api . Node {
ObjectMeta : api . ObjectMeta {
Name : "older" ,
} ,
Status : api . NodeStatus {
NodeInfo : api . NodeSystemInfo {
KubeletVersion : "v0.21.4" ,
} ,
} ,
} )
nc . nodeStore . Store . Add ( & api . Node {
ObjectMeta : api . ObjectMeta {
Name : "oldest" ,
} ,
Status : api . NodeStatus {
NodeInfo : api . NodeSystemInfo {
KubeletVersion : "v0.19.3" ,
} ,
} ,
} )
2015-10-20 02:25:31 +00:00
for i , tc := range tcs {
var deleteCalls int
2016-07-11 11:23:53 +00:00
forcefullyDeletePodsFunc := func ( _ * api . Pod ) error {
2015-10-20 02:25:31 +00:00
deleteCalls ++
2016-02-27 00:59:16 +00:00
return nil
2015-10-20 02:25:31 +00:00
}
2016-07-11 11:23:53 +00:00
nc . maybeDeleteTerminatingPod ( & tc . pod , nc . nodeStore . Store , forcefullyDeletePodsFunc )
2015-10-20 02:25:31 +00:00
if tc . prune && deleteCalls != 1 {
t . Errorf ( "[%v] expected number of delete calls to be 1 but got %v" , i , deleteCalls )
}
if ! tc . prune && deleteCalls != 0 {
t . Errorf ( "[%v] expected number of delete calls to be 0 but got %v" , i , deleteCalls )
}
}
}
2016-03-08 19:00:35 +00:00
func TestCleanupOrphanedPods ( t * testing . T ) {
2016-07-11 11:23:53 +00:00
pods := [ ] * api . Pod {
2016-03-08 19:00:35 +00:00
newPod ( "a" , "foo" ) ,
newPod ( "b" , "bar" ) ,
newPod ( "c" , "gone" ) ,
}
2016-05-20 11:21:52 +00:00
nc := NewNodeController ( nil , nil , 0 , nil , nil , 0 , 0 , 0 , nil , nil , 0 , false )
2016-03-08 19:00:35 +00:00
nc . nodeStore . Store . Add ( newNode ( "foo" ) )
nc . nodeStore . Store . Add ( newNode ( "bar" ) )
for _ , pod := range pods {
p := pod
2016-04-07 12:15:21 +00:00
nc . podStore . Indexer . Add ( & p )
2016-03-08 19:00:35 +00:00
}
var deleteCalls int
var deletedPodName string
2016-07-11 11:23:53 +00:00
forcefullyDeletePodFunc := func ( p * api . Pod ) error {
2016-03-08 19:00:35 +00:00
deleteCalls ++
deletedPodName = p . ObjectMeta . Name
return nil
}
2016-07-11 11:23:53 +00:00
cleanupOrphanedPods ( pods , nc . nodeStore . Store , forcefullyDeletePodFunc )
2016-03-08 19:00:35 +00:00
if deleteCalls != 1 {
t . Fatalf ( "expected one delete, got: %v" , deleteCalls )
}
if deletedPodName != "c" {
t . Fatalf ( "expected deleted pod name to be 'c', but got: %q" , deletedPodName )
}
}