2016-06-29 00:20:08 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2016 The Kubernetes Authors .
2016-06-29 00:20:08 +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 .
* /
package framework
import (
2016-07-06 02:05:53 +00:00
"fmt"
2016-06-29 00:20:08 +00:00
"sync"
2016-07-06 02:05:53 +00:00
"time"
2016-06-29 00:20:08 +00:00
"k8s.io/kubernetes/pkg/api"
2016-07-06 02:05:53 +00:00
"k8s.io/kubernetes/pkg/api/errors"
2016-06-29 00:20:08 +00:00
"k8s.io/kubernetes/pkg/client/unversioned"
2016-09-21 19:58:25 +00:00
"k8s.io/kubernetes/pkg/labels"
2016-09-15 21:49:14 +00:00
"k8s.io/kubernetes/pkg/util/sets"
2016-07-06 02:05:53 +00:00
"k8s.io/kubernetes/pkg/util/wait"
2016-06-29 00:20:08 +00:00
2016-07-20 17:26:56 +00:00
. "github.com/onsi/ginkgo"
2016-06-29 00:20:08 +00:00
. "github.com/onsi/gomega"
)
2016-09-15 21:49:14 +00:00
// ImageWhiteList is the images used in the current test suite. It should be initialized in test suite and
// the images in the white list should be pre-pulled in the test suite. Currently, this is only used by
// node e2e test.
var ImageWhiteList sets . String
2016-08-22 11:07:16 +00:00
// Convenience method for getting a pod client interface in the framework's namespace,
// possibly applying test-suite specific transformations to the pod spec, e.g. for
// node e2e pod scheduling.
2016-07-08 05:56:46 +00:00
func ( f * Framework ) PodClient ( ) * PodClient {
return & PodClient {
f : f ,
PodInterface : f . Client . Pods ( f . Namespace . Name ) ,
}
2016-06-29 00:20:08 +00:00
}
2016-07-08 05:56:46 +00:00
type PodClient struct {
f * Framework
unversioned . PodInterface
2016-06-29 00:20:08 +00:00
}
2016-07-08 05:56:46 +00:00
// Create creates a new pod according to the framework specifications (don't wait for it to start).
func ( c * PodClient ) Create ( pod * api . Pod ) * api . Pod {
2016-07-20 18:03:05 +00:00
c . mungeSpec ( pod )
2016-07-08 05:56:46 +00:00
p , err := c . PodInterface . Create ( pod )
2016-06-29 00:20:08 +00:00
ExpectNoError ( err , "Error creating Pod" )
2016-07-10 23:57:18 +00:00
return p
2016-06-29 00:20:08 +00:00
}
2016-07-08 05:56:46 +00:00
// CreateSync creates a new pod according to the framework specifications, and wait for it to start.
func ( c * PodClient ) CreateSync ( pod * api . Pod ) * api . Pod {
p := c . Create ( pod )
ExpectNoError ( c . f . WaitForPodRunning ( p . Name ) )
2016-07-15 18:06:10 +00:00
// Get the newest pod after it becomes running, some status may change after pod created, such as pod ip.
2016-08-05 22:02:44 +00:00
p , err := c . Get ( p . Name )
2016-07-15 18:06:10 +00:00
ExpectNoError ( err )
2016-07-08 05:56:46 +00:00
return p
}
// CreateBatch create a batch of pods. All pods are created before waiting.
func ( c * PodClient ) CreateBatch ( pods [ ] * api . Pod ) [ ] * api . Pod {
2016-07-10 23:57:18 +00:00
ps := make ( [ ] * api . Pod , len ( pods ) )
2016-06-29 00:20:08 +00:00
var wg sync . WaitGroup
2016-07-15 18:06:10 +00:00
for i , pod := range pods {
2016-06-29 00:20:08 +00:00
wg . Add ( 1 )
2016-07-15 18:06:10 +00:00
go func ( i int , pod * api . Pod ) {
2016-07-20 17:26:56 +00:00
defer wg . Done ( )
defer GinkgoRecover ( )
2016-07-15 18:06:10 +00:00
ps [ i ] = c . CreateSync ( pod )
} ( i , pod )
2016-06-29 00:20:08 +00:00
}
wg . Wait ( )
2016-07-10 23:57:18 +00:00
return ps
2016-06-29 00:20:08 +00:00
}
2016-07-08 05:56:46 +00:00
// Update updates the pod object. It retries if there is a conflict, throw out error if
2016-07-06 02:05:53 +00:00
// there is any other errors. name is the pod name, updateFn is the function updating the
// pod object.
2016-07-08 05:56:46 +00:00
func ( c * PodClient ) Update ( name string , updateFn func ( pod * api . Pod ) ) {
2016-07-06 02:05:53 +00:00
ExpectNoError ( wait . Poll ( time . Millisecond * 500 , time . Second * 30 , func ( ) ( bool , error ) {
2016-07-08 05:56:46 +00:00
pod , err := c . PodInterface . Get ( name )
2016-07-06 02:05:53 +00:00
if err != nil {
return false , fmt . Errorf ( "failed to get pod %q: %v" , name , err )
}
updateFn ( pod )
2016-07-08 05:56:46 +00:00
_ , err = c . PodInterface . Update ( pod )
2016-07-06 02:05:53 +00:00
if err == nil {
Logf ( "Successfully updated pod %q" , name )
return true , nil
}
if errors . IsConflict ( err ) {
Logf ( "Conflicting update to pod %q, re-get and re-update: %v" , name , err )
return false , nil
}
return false , fmt . Errorf ( "failed to update pod %q: %v" , name , err )
} ) )
}
2016-07-08 05:56:46 +00:00
2016-09-21 19:58:25 +00:00
// DeleteSync deletes the pod and wait for the pod to disappear for `timeout`. If the pod doesn't
// disappear before the timeout, it will fail the test.
func ( c * PodClient ) DeleteSync ( name string , options * api . DeleteOptions , timeout time . Duration ) {
err := c . Delete ( name , options )
if err != nil && ! errors . IsNotFound ( err ) {
Failf ( "Failed to delete pod %q: %v" , name , err )
}
Expect ( WaitForPodToDisappear ( c . f . Client , c . f . Namespace . Name , name , labels . Everything ( ) ,
2 * time . Second , timeout ) ) . To ( Succeed ( ) , "wait for pod %q to disappear" , name )
}
2016-07-20 18:03:05 +00:00
// mungeSpec apply test-suite specific transformations to the pod spec.
func ( c * PodClient ) mungeSpec ( pod * api . Pod ) {
if TestContext . NodeName != "" {
Expect ( pod . Spec . NodeName ) . To ( Or ( BeZero ( ) , Equal ( TestContext . NodeName ) ) , "Test misconfigured" )
pod . Spec . NodeName = TestContext . NodeName
2016-09-15 21:49:14 +00:00
if ! TestContext . PrepullImages {
return
}
// If prepull is enabled, munge the container spec to make sure the images are not pulled
// during the test.
for i := range pod . Spec . Containers {
c := & pod . Spec . Containers [ i ]
if c . ImagePullPolicy == api . PullAlways {
// If the image pull policy is PullAlways, the image doesn't need to be in
// the white list or pre-pulled, because the image is expected to be pulled
// in the test anyway.
continue
}
// If the image policy is not PullAlways, the image must be in the white list and
// pre-pulled.
Expect ( ImageWhiteList . Has ( c . Image ) ) . To ( BeTrue ( ) , "Image %q is not in the white list, consider adding it to CommonImageWhiteList in test/e2e/common/util.go or NodeImageWhiteList in test/e2e_node/image_list.go" , c . Image )
// Do not pull images during the tests because the images in white list should have
// been prepulled.
c . ImagePullPolicy = api . PullNever
}
2016-07-20 18:03:05 +00:00
}
}
2016-07-08 05:56:46 +00:00
// TODO(random-liu): Move pod wait function into this file
2016-09-23 20:36:37 +00:00
// WaitForSuccess waits for pod to success.
func ( c * PodClient ) WaitForSuccess ( name string , timeout time . Duration ) {
f := c . f
Expect ( waitForPodCondition ( f . Client , f . Namespace . Name , name , "success or failure" , timeout ,
func ( pod * api . Pod ) ( bool , error ) {
switch pod . Status . Phase {
case api . PodFailed :
return true , fmt . Errorf ( "pod %q failed with reason: %q, message: %q" , name , pod . Status . Reason , pod . Status . Message )
case api . PodSucceeded :
return true , nil
default :
return false , nil
}
} ,
) ) . To ( Succeed ( ) , "wait for pod %q to success" , name )
}