2015-08-28 05:54:45 +00:00
/ *
Copyright 2015 The Kubernetes Authors All rights reserved .
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 initialresources
import (
"testing"
"time"
"k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
)
type fakeSource struct {
2015-10-02 10:08:22 +00:00
f func ( kind api . ResourceName , perc int64 , image , namespace string , exactMatch bool , start , end time . Time ) ( int64 , int64 , error )
2015-08-28 05:54:45 +00:00
}
2015-10-02 10:08:22 +00:00
func ( s * fakeSource ) GetUsagePercentile ( kind api . ResourceName , perc int64 , image , namespace string , exactMatch bool , start , end time . Time ) ( usage int64 , samples int64 , err error ) {
return s . f ( kind , perc , image , namespace , exactMatch , start , end )
2015-08-28 05:54:45 +00:00
}
func parseReq ( cpu , mem string ) api . ResourceList {
if cpu == "" && mem == "" {
return nil
}
req := api . ResourceList { }
if cpu != "" {
req [ api . ResourceCPU ] = resource . MustParse ( cpu )
}
if mem != "" {
req [ api . ResourceMemory ] = resource . MustParse ( mem )
}
return req
}
func addContainer ( pod * api . Pod , name , image string , request api . ResourceList ) {
pod . Spec . Containers = append ( pod . Spec . Containers , api . Container {
Name : name ,
Image : image ,
Resources : api . ResourceRequirements { Requests : request } ,
} )
}
2015-09-15 19:05:52 +00:00
func createPod ( name string , image string , request api . ResourceList ) * api . Pod {
pod := & api . Pod {
2015-10-02 10:08:22 +00:00
ObjectMeta : api . ObjectMeta { Name : name , Namespace : "test-ns" } ,
2015-08-28 05:54:45 +00:00
Spec : api . PodSpec { } ,
}
pod . Spec . Containers = [ ] api . Container { }
2015-09-15 19:05:52 +00:00
addContainer ( pod , "c0" , image , request )
2015-08-28 05:54:45 +00:00
return pod
}
2015-09-15 19:05:52 +00:00
func getPods ( ) [ ] * api . Pod {
return [ ] * api . Pod {
2015-08-28 05:54:45 +00:00
createPod ( "p0" , "image:v0" , parseReq ( "" , "" ) ) ,
createPod ( "p1" , "image:v1" , parseReq ( "" , "300" ) ) ,
createPod ( "p2" , "image:v2" , parseReq ( "300m" , "" ) ) ,
createPod ( "p3" , "image:v3" , parseReq ( "300m" , "300" ) ) ,
}
}
func verifyContainer ( t * testing . T , c * api . Container , cpu , mem int64 ) {
req := c . Resources . Requests
if req . Cpu ( ) . MilliValue ( ) != cpu {
t . Errorf ( "Wrong CPU request for container %v. Expected %v, got %v." , c . Name , cpu , req . Cpu ( ) . MilliValue ( ) )
}
if req . Memory ( ) . Value ( ) != mem {
t . Errorf ( "Wrong memory request for container %v. Expected %v, got %v." , c . Name , mem , req . Memory ( ) . Value ( ) )
}
}
func verifyPod ( t * testing . T , pod * api . Pod , cpu , mem int64 ) {
verifyContainer ( t , & pod . Spec . Containers [ 0 ] , cpu , mem )
}
2015-09-15 19:05:52 +00:00
func verifyAnnotation ( t * testing . T , pod * api . Pod , expected string ) {
a , ok := pod . ObjectMeta . Annotations [ initialResourcesAnnotation ]
if ! ok {
t . Errorf ( "No annotation but expected %v" , expected )
}
if a != expected {
t . Errorf ( "Wrong annatation set by Initial Resources: got %v, expected %v" , a , expected )
}
}
func expectNoAnnotation ( t * testing . T , pod * api . Pod ) {
if a , ok := pod . ObjectMeta . Annotations [ initialResourcesAnnotation ] ; ok {
t . Errorf ( "Expected no annatation but got %v" , a )
}
}
func admit ( t * testing . T , ir admission . Interface , pods [ ] * api . Pod ) {
2015-08-28 05:54:45 +00:00
for i := range pods {
2015-09-15 19:05:52 +00:00
p := pods [ i ]
2016-04-21 15:14:58 +00:00
if err := ir . Admit ( admission . NewAttributesRecord ( p , api . Kind ( "Pod" ) . WithVersion ( "version" ) , "test" , p . ObjectMeta . Name , api . Resource ( "pods" ) . WithVersion ( "version" ) , "" , admission . Create , nil ) ) ; err != nil {
2015-08-28 05:54:45 +00:00
t . Error ( err )
}
}
}
2015-10-02 10:08:22 +00:00
func performTest ( t * testing . T , ir admission . Interface ) {
2015-08-28 05:54:45 +00:00
pods := getPods ( )
admit ( t , ir , pods )
2015-09-15 19:05:52 +00:00
verifyPod ( t , pods [ 0 ] , 100 , 100 )
verifyPod ( t , pods [ 1 ] , 100 , 300 )
verifyPod ( t , pods [ 2 ] , 300 , 100 )
verifyPod ( t , pods [ 3 ] , 300 , 300 )
verifyAnnotation ( t , pods [ 0 ] , "Initial Resources plugin set: cpu, memory request for container c0" )
verifyAnnotation ( t , pods [ 1 ] , "Initial Resources plugin set: cpu request for container c0" )
verifyAnnotation ( t , pods [ 2 ] , "Initial Resources plugin set: memory request for container c0" )
expectNoAnnotation ( t , pods [ 3 ] )
2015-08-28 05:54:45 +00:00
}
2015-10-02 10:08:22 +00:00
func TestEstimationBasedOnTheSameImageSameNamespace7d ( t * testing . T ) {
f := func ( _ api . ResourceName , _ int64 , _ , ns string , exactMatch bool , start , end time . Time ) ( int64 , int64 , error ) {
if exactMatch && end . Sub ( start ) == week && ns == "test-ns" {
return 100 , 120 , nil
}
return 200 , 120 , nil
}
performTest ( t , newInitialResources ( & fakeSource { f : f } , 90 , false ) )
}
func TestEstimationBasedOnTheSameImageSameNamespace30d ( t * testing . T ) {
f := func ( _ api . ResourceName , _ int64 , _ , ns string , exactMatch bool , start , end time . Time ) ( int64 , int64 , error ) {
if exactMatch && end . Sub ( start ) == week && ns == "test-ns" {
2015-08-28 05:54:45 +00:00
return 200 , 20 , nil
}
2015-10-02 10:08:22 +00:00
if exactMatch && end . Sub ( start ) == month && ns == "test-ns" {
2015-08-28 05:54:45 +00:00
return 100 , 120 , nil
}
return 200 , 120 , nil
}
2015-10-02 10:08:22 +00:00
performTest ( t , newInitialResources ( & fakeSource { f : f } , 90 , false ) )
}
2015-08-28 05:54:45 +00:00
2015-10-02 10:08:22 +00:00
func TestEstimationBasedOnTheSameImageAllNamespaces7d ( t * testing . T ) {
f := func ( _ api . ResourceName , _ int64 , _ , ns string , exactMatch bool , start , end time . Time ) ( int64 , int64 , error ) {
if exactMatch && ns == "test-ns" {
return 200 , 20 , nil
}
if exactMatch && end . Sub ( start ) == week && ns == "" {
return 100 , 120 , nil
}
return 200 , 120 , nil
}
performTest ( t , newInitialResources ( & fakeSource { f : f } , 90 , false ) )
}
2015-08-28 05:54:45 +00:00
2015-10-02 10:08:22 +00:00
func TestEstimationBasedOnTheSameImageAllNamespaces30d ( t * testing . T ) {
f := func ( _ api . ResourceName , _ int64 , _ , ns string , exactMatch bool , start , end time . Time ) ( int64 , int64 , error ) {
if exactMatch && ns == "test-ns" {
return 200 , 20 , nil
}
if exactMatch && end . Sub ( start ) == week && ns == "" {
return 200 , 20 , nil
}
if exactMatch && end . Sub ( start ) == month && ns == "" {
return 100 , 120 , nil
}
return 200 , 120 , nil
}
performTest ( t , newInitialResources ( & fakeSource { f : f } , 90 , false ) )
2015-08-28 05:54:45 +00:00
}
func TestEstimationBasedOnOtherImages ( t * testing . T ) {
2015-10-02 10:08:22 +00:00
f := func ( _ api . ResourceName , _ int64 , image , ns string , exactMatch bool , _ , _ time . Time ) ( int64 , int64 , error ) {
if image == "image" && ! exactMatch && ns == "" {
2015-08-28 05:54:45 +00:00
return 100 , 5 , nil
}
return 200 , 20 , nil
}
2015-10-02 10:08:22 +00:00
performTest ( t , newInitialResources ( & fakeSource { f : f } , 90 , false ) )
2015-08-28 05:54:45 +00:00
}
func TestNoData ( t * testing . T ) {
2015-10-02 10:08:22 +00:00
f := func ( _ api . ResourceName , _ int64 , _ , ns string , _ bool , _ , _ time . Time ) ( int64 , int64 , error ) {
2015-08-28 05:54:45 +00:00
return 200 , 0 , nil
}
2015-10-02 10:08:22 +00:00
ir := newInitialResources ( & fakeSource { f : f } , 90 , false )
2015-08-28 05:54:45 +00:00
2015-09-15 19:05:52 +00:00
pods := [ ] * api . Pod {
2015-08-28 05:54:45 +00:00
createPod ( "p0" , "image:v0" , parseReq ( "" , "" ) ) ,
}
admit ( t , ir , pods )
if pods [ 0 ] . Spec . Containers [ 0 ] . Resources . Requests != nil {
t . Errorf ( "Unexpected resource estimation" )
}
2015-09-15 19:05:52 +00:00
expectNoAnnotation ( t , pods [ 0 ] )
2015-08-28 05:54:45 +00:00
}
func TestManyContainers ( t * testing . T ) {
2015-10-02 10:08:22 +00:00
f := func ( _ api . ResourceName , _ int64 , _ , ns string , exactMatch bool , _ , _ time . Time ) ( int64 , int64 , error ) {
2015-08-28 05:54:45 +00:00
if exactMatch {
return 100 , 120 , nil
}
return 200 , 30 , nil
}
2015-10-02 10:08:22 +00:00
ir := newInitialResources ( & fakeSource { f : f } , 90 , false )
2015-08-28 05:54:45 +00:00
pod := createPod ( "p" , "image:v0" , parseReq ( "" , "" ) )
2015-09-15 19:05:52 +00:00
addContainer ( pod , "c1" , "image:v1" , parseReq ( "" , "300" ) )
addContainer ( pod , "c2" , "image:v2" , parseReq ( "300m" , "" ) )
addContainer ( pod , "c3" , "image:v3" , parseReq ( "300m" , "300" ) )
admit ( t , ir , [ ] * api . Pod { pod } )
2015-08-28 05:54:45 +00:00
verifyContainer ( t , & pod . Spec . Containers [ 0 ] , 100 , 100 )
verifyContainer ( t , & pod . Spec . Containers [ 1 ] , 100 , 300 )
verifyContainer ( t , & pod . Spec . Containers [ 2 ] , 300 , 100 )
verifyContainer ( t , & pod . Spec . Containers [ 3 ] , 300 , 300 )
2015-09-15 19:05:52 +00:00
verifyAnnotation ( t , pod , "Initial Resources plugin set: cpu, memory request for container c0; cpu request for container c1; memory request for container c2" )
2015-08-28 05:54:45 +00:00
}
2015-10-02 10:08:22 +00:00
func TestNamespaceAware ( t * testing . T ) {
f := func ( _ api . ResourceName , _ int64 , _ , ns string , exactMatch bool , start , end time . Time ) ( int64 , int64 , error ) {
if ns == "test-ns" {
return 200 , 0 , nil
}
return 200 , 120 , nil
}
ir := newInitialResources ( & fakeSource { f : f } , 90 , true )
pods := [ ] * api . Pod {
createPod ( "p0" , "image:v0" , parseReq ( "" , "" ) ) ,
}
admit ( t , ir , pods )
if pods [ 0 ] . Spec . Containers [ 0 ] . Resources . Requests != nil {
t . Errorf ( "Unexpected resource estimation" )
}
expectNoAnnotation ( t , pods [ 0 ] )
}