Skip to content

Commit

Permalink
GIT-60: enable helper function for conditional waits
Browse files Browse the repository at this point in the history
  • Loading branch information
harshanarayana committed Nov 11, 2021
1 parent 8412394 commit b79a789
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 1 deletion.
12 changes: 11 additions & 1 deletion klient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"k8s.io/client-go/rest"
"sigs.k8s.io/e2e-framework/klient/conf"
"sigs.k8s.io/e2e-framework/klient/k8s/resources"
"sigs.k8s.io/e2e-framework/klient/wait"
)

// Client stores values to interact with the
Expand All @@ -31,11 +32,16 @@ type Client interface {
// This method takes zero or at most 1 namespace (more will panic) that
// can be used in List operations.
Resources(...string) *resources.Resources
// Wait returns an implementation of the wait.Interface that can be used
// to perform helper operation such as waiting for certain condition to be
// met.
Wait() wait.Interface
}

type client struct {
cfg *rest.Config
resources *resources.Resources
waiter wait.Interface
}

// New returns a new Client value
Expand All @@ -44,7 +50,7 @@ func New(cfg *rest.Config) (Client, error) {
if err != nil {
return nil, err
}
return &client{cfg: cfg, resources: res}, nil
return &client{cfg: cfg, resources: res, waiter: wait.New(res)}, nil
}

// NewWithKubeConfigFile creates a client using the kubeconfig filePath
Expand Down Expand Up @@ -74,3 +80,7 @@ func (c *client) Resources(namespace ...string) *resources.Resources {
panic("too many namespaces provided")
}
}

func (c *client) Wait() wait.Interface {
return c.waiter
}
101 changes: 101 additions & 0 deletions klient/wait/wait.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
Copyright 2021 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 wait

import (
"context"
"log"
"time"

appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
apimachinerywait "k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/e2e-framework/klient/k8s/resources"
)

const (
defaultPollTimeout = 5 * time.Minute
defaultPollInterval = 5 * time.Second
)

type Interface interface {
For(cond apimachinerywait.ConditionFunc) error
ForWithIntervalAndTimeout(interval time.Duration, timeout time.Duration, resource *resources.Resources, cond apimachinerywait.ConditionFunc) error
}

type waiter struct {
resources *resources.Resources
}

func New(resources *resources.Resources) *waiter {
return &waiter{resources: resources}
}

func checkIfPodIsRunning(pod *v1.Pod) bool {
switch pod.Status.Phase {
case v1.PodRunning:
return true
default:
return false
}
}

func (w *waiter) PodReadyCondition(pod *v1.Pod) apimachinerywait.ConditionFunc {
return func() (done bool, err error) {
log.Printf("Checking for Pod Ready Condition of %s/%s", pod.GetNamespace(), pod.GetName())
if err := w.resources.Get(context.Background(), pod.GetName(), pod.GetNamespace(), pod); err != nil {
return false, err
}
return checkIfPodIsRunning(pod), nil
}
}

func (w *waiter) PodReadyConditionBySelector(selector string) apimachinerywait.ConditionFunc {
return func() (done bool, err error) {
log.Printf("Waiting for Pod Ready Condition using Label selector %s", selector)
var pods v1.PodList
if err := w.resources.List(context.Background(), &pods, resources.WithLabelSelector(selector)); err != nil {
return false, err
}
allOk := true
for _, pod := range pods.Items {
if ok := checkIfPodIsRunning(&pod); !ok {
allOk = false
break
}
}
return allOk, nil
}
}

func (w *waiter) DeploymentScaled(deployment *appsv1.Deployment, replica int) apimachinerywait.ConditionFunc {
return func() (done bool, err error) {
log.Printf("Checking for the Scale of Deployment %s/%s to be %d", deployment.GetNamespace(), deployment.GetName(), replica)
if err := w.resources.Get(context.Background(), deployment.GetName(), deployment.GetNamespace(), deployment); err != nil {
return false, err
}
return *deployment.Spec.Replicas == int32(replica), nil
}
}

func (w *waiter) For(cond apimachinerywait.ConditionFunc) error {
return apimachinerywait.PollImmediate(defaultPollInterval, defaultPollTimeout, cond)
}

func (w *waiter) ForWithIntervalAndTimeout(interval time.Duration, timeout time.Duration, resource *resources.Resources, cond apimachinerywait.ConditionFunc) error {
return apimachinerywait.PollImmediate(interval, timeout, cond)
}

0 comments on commit b79a789

Please sign in to comment.