2015-09-21 22:51:27 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2015 The Kubernetes Authors .
2015-09-21 22:51:27 +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 .
* /
2016-06-06 22:43:57 +00:00
package podgc
2015-09-21 22:51:27 +00:00
import (
"sync"
"testing"
"time"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
2016-09-12 14:47:17 +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-10-25 18:58:13 +00:00
"k8s.io/kubernetes/pkg/labels"
2015-09-21 22:51:27 +00:00
"k8s.io/kubernetes/pkg/util/sets"
)
2016-10-14 12:40:08 +00:00
type FakeController struct { }
func ( * FakeController ) Run ( <- chan struct { } ) { }
func ( * FakeController ) HasSynced ( ) bool {
return true
}
2016-09-12 14:47:17 +00:00
func TestGCTerminated ( t * testing . T ) {
2015-09-25 19:33:33 +00:00
type nameToPhase struct {
name string
phase api . PodPhase
}
2015-09-21 22:51:27 +00:00
testCases := [ ] struct {
2015-09-25 19:33:33 +00:00
pods [ ] nameToPhase
2015-09-21 22:51:27 +00:00
threshold int
deletedPodNames sets . String
} {
{
2015-09-25 19:33:33 +00:00
pods : [ ] nameToPhase {
{ name : "a" , phase : api . PodFailed } ,
{ name : "b" , phase : api . PodSucceeded } ,
2015-09-21 22:51:27 +00:00
} ,
2016-09-12 14:47:17 +00:00
threshold : 0 ,
// threshold = 0 disables terminated pod deletion
deletedPodNames : sets . NewString ( ) ,
} ,
{
pods : [ ] nameToPhase {
{ name : "a" , phase : api . PodFailed } ,
{ name : "b" , phase : api . PodSucceeded } ,
{ name : "c" , phase : api . PodFailed } ,
} ,
threshold : 1 ,
2015-09-21 22:51:27 +00:00
deletedPodNames : sets . NewString ( "a" , "b" ) ,
} ,
2016-09-12 14:47:17 +00:00
{
pods : [ ] nameToPhase {
{ name : "a" , phase : api . PodRunning } ,
{ name : "b" , phase : api . PodSucceeded } ,
{ name : "c" , phase : api . PodFailed } ,
} ,
threshold : 1 ,
deletedPodNames : sets . NewString ( "b" ) ,
} ,
2015-09-21 22:51:27 +00:00
{
2015-09-25 19:33:33 +00:00
pods : [ ] nameToPhase {
{ name : "a" , phase : api . PodFailed } ,
{ name : "b" , phase : api . PodSucceeded } ,
2015-09-21 22:51:27 +00:00
} ,
threshold : 1 ,
deletedPodNames : sets . NewString ( "a" ) ,
} ,
{
2015-09-25 19:33:33 +00:00
pods : [ ] nameToPhase {
{ name : "a" , phase : api . PodFailed } ,
{ name : "b" , phase : api . PodSucceeded } ,
2015-09-21 22:51:27 +00:00
} ,
threshold : 5 ,
deletedPodNames : sets . NewString ( ) ,
} ,
}
for i , test := range testCases {
2016-01-29 06:34:08 +00:00
client := fake . NewSimpleClientset ( )
2016-09-12 14:47:17 +00:00
gcc := NewFromClient ( client , test . threshold )
deletedPodNames := make ( [ ] string , 0 )
var lock sync . Mutex
gcc . deletePod = func ( _ , name string ) error {
lock . Lock ( )
defer lock . Unlock ( )
deletedPodNames = append ( deletedPodNames , name )
return nil
}
creationTime := time . Unix ( 0 , 0 )
for _ , pod := range test . pods {
creationTime = creationTime . Add ( 1 * time . Hour )
gcc . podStore . Indexer . Add ( & api . Pod {
ObjectMeta : api . ObjectMeta { Name : pod . name , CreationTimestamp : unversioned . Time { Time : creationTime } } ,
Status : api . PodStatus { Phase : pod . phase } ,
Spec : api . PodSpec { NodeName : "node" } ,
} )
}
store := cache . NewStore ( cache . MetaNamespaceKeyFunc )
store . Add ( & api . Node {
ObjectMeta : api . ObjectMeta { Name : "node" } ,
} )
gcc . nodeStore = cache . StoreToNodeLister { Store : store }
2016-10-14 12:40:08 +00:00
gcc . podController = & FakeController { }
gcc . nodeController = & FakeController { }
2016-09-12 14:47:17 +00:00
gcc . gc ( )
pass := true
for _ , pod := range deletedPodNames {
if ! test . deletedPodNames . Has ( pod ) {
pass = false
}
}
if len ( deletedPodNames ) != len ( test . deletedPodNames ) {
pass = false
}
if ! pass {
t . Errorf ( "[%v]pod's deleted expected and actual did not match.\n\texpected: %v\n\tactual: %v" , i , test . deletedPodNames , deletedPodNames )
}
}
}
func TestGCOrphaned ( t * testing . T ) {
type nameToPhase struct {
name string
phase api . PodPhase
}
testCases := [ ] struct {
pods [ ] nameToPhase
threshold int
deletedPodNames sets . String
} {
{
pods : [ ] nameToPhase {
{ name : "a" , phase : api . PodFailed } ,
{ name : "b" , phase : api . PodSucceeded } ,
} ,
threshold : 0 ,
deletedPodNames : sets . NewString ( "a" , "b" ) ,
} ,
{
pods : [ ] nameToPhase {
{ name : "a" , phase : api . PodRunning } ,
} ,
threshold : 1 ,
deletedPodNames : sets . NewString ( "a" ) ,
} ,
}
for i , test := range testCases {
client := fake . NewSimpleClientset ( )
gcc := NewFromClient ( client , test . threshold )
2015-10-10 00:15:00 +00:00
deletedPodNames := make ( [ ] string , 0 )
var lock sync . Mutex
gcc . deletePod = func ( _ , name string ) error {
lock . Lock ( )
defer lock . Unlock ( )
deletedPodNames = append ( deletedPodNames , name )
return nil
}
2015-09-21 22:51:27 +00:00
creationTime := time . Unix ( 0 , 0 )
2015-09-25 19:33:33 +00:00
for _ , pod := range test . pods {
2015-09-21 22:51:27 +00:00
creationTime = creationTime . Add ( 1 * time . Hour )
2016-04-07 12:15:21 +00:00
gcc . podStore . Indexer . Add ( & api . Pod {
2016-03-23 23:45:24 +00:00
ObjectMeta : api . ObjectMeta { Name : pod . name , CreationTimestamp : unversioned . Time { Time : creationTime } } ,
2015-09-25 19:33:33 +00:00
Status : api . PodStatus { Phase : pod . phase } ,
2016-09-12 14:47:17 +00:00
Spec : api . PodSpec { NodeName : "node" } ,
2015-09-21 22:51:27 +00:00
} )
}
2016-09-12 14:47:17 +00:00
store := cache . NewStore ( cache . MetaNamespaceKeyFunc )
gcc . nodeStore = cache . StoreToNodeLister { Store : store }
2016-10-14 12:40:08 +00:00
gcc . podController = & FakeController { }
gcc . nodeController = & FakeController { }
2016-09-12 14:47:17 +00:00
2016-10-25 18:58:13 +00:00
pods , err := gcc . podStore . List ( labels . Everything ( ) )
if err != nil {
t . Errorf ( "Error while listing all Pods: %v" , err )
return
}
gcc . gcOrphaned ( pods )
pass := true
for _ , pod := range deletedPodNames {
if ! test . deletedPodNames . Has ( pod ) {
pass = false
}
}
if len ( deletedPodNames ) != len ( test . deletedPodNames ) {
pass = false
}
if ! pass {
t . Errorf ( "[%v]pod's deleted expected and actual did not match.\n\texpected: %v\n\tactual: %v" , i , test . deletedPodNames , deletedPodNames )
}
}
}
func TestGCUnscheduledTerminating ( t * testing . T ) {
type nameToPhase struct {
name string
phase api . PodPhase
deletionTimeStamp * unversioned . Time
nodeName string
}
testCases := [ ] struct {
2016-10-27 20:30:04 +00:00
name string
2016-10-25 18:58:13 +00:00
pods [ ] nameToPhase
deletedPodNames sets . String
} {
{
2016-10-27 20:30:04 +00:00
name : "Unscheduled pod in any phase must be deleted" ,
2016-10-25 18:58:13 +00:00
pods : [ ] nameToPhase {
{ name : "a" , phase : api . PodFailed , deletionTimeStamp : & unversioned . Time { } , nodeName : "" } ,
{ name : "b" , phase : api . PodSucceeded , deletionTimeStamp : & unversioned . Time { } , nodeName : "" } ,
{ name : "c" , phase : api . PodRunning , deletionTimeStamp : & unversioned . Time { } , nodeName : "" } ,
} ,
deletedPodNames : sets . NewString ( "a" , "b" , "c" ) ,
} ,
{
2016-10-27 20:30:04 +00:00
name : "Scheduled pod in any phase must not be deleted" ,
2016-10-25 18:58:13 +00:00
pods : [ ] nameToPhase {
{ name : "a" , phase : api . PodFailed , deletionTimeStamp : nil , nodeName : "" } ,
{ name : "b" , phase : api . PodSucceeded , deletionTimeStamp : nil , nodeName : "node" } ,
{ name : "c" , phase : api . PodRunning , deletionTimeStamp : & unversioned . Time { } , nodeName : "node" } ,
} ,
deletedPodNames : sets . NewString ( ) ,
} ,
}
for i , test := range testCases {
client := fake . NewSimpleClientset ( )
gcc := NewFromClient ( client , - 1 )
deletedPodNames := make ( [ ] string , 0 )
var lock sync . Mutex
gcc . deletePod = func ( _ , name string ) error {
lock . Lock ( )
defer lock . Unlock ( )
deletedPodNames = append ( deletedPodNames , name )
return nil
}
creationTime := time . Unix ( 0 , 0 )
for _ , pod := range test . pods {
creationTime = creationTime . Add ( 1 * time . Hour )
gcc . podStore . Indexer . Add ( & api . Pod {
ObjectMeta : api . ObjectMeta { Name : pod . name , CreationTimestamp : unversioned . Time { Time : creationTime } ,
DeletionTimestamp : pod . deletionTimeStamp } ,
Status : api . PodStatus { Phase : pod . phase } ,
Spec : api . PodSpec { NodeName : pod . nodeName } ,
} )
}
store := cache . NewStore ( cache . MetaNamespaceKeyFunc )
gcc . nodeStore = cache . StoreToNodeLister { Store : store }
gcc . podController = & FakeController { }
gcc . nodeController = & FakeController { }
pods , err := gcc . podStore . List ( labels . Everything ( ) )
if err != nil {
t . Errorf ( "Error while listing all Pods: %v" , err )
return
}
gcc . gcUnscheduledTerminating ( pods )
2015-09-21 22:51:27 +00:00
pass := true
2015-10-10 00:15:00 +00:00
for _ , pod := range deletedPodNames {
2015-09-21 22:51:27 +00:00
if ! test . deletedPodNames . Has ( pod ) {
pass = false
}
}
2015-10-10 00:15:00 +00:00
if len ( deletedPodNames ) != len ( test . deletedPodNames ) {
2015-09-21 22:51:27 +00:00
pass = false
}
if ! pass {
2016-10-27 20:30:04 +00:00
t . Errorf ( "[%v]pod's deleted expected and actual did not match.\n\texpected: %v\n\tactual: %v, test: %v" , i , test . deletedPodNames , deletedPodNames , test . name )
2015-09-21 22:51:27 +00:00
}
}
}