mirror of
https://github.com/TECHNOFAB11/zfs-localpv.git
synced 2025-12-11 22:10:11 +01:00
test(zfspv): minikube setup for travis
to run integration test cases Signed-off-by: Pawan <pawan@mayadata.io>
This commit is contained in:
parent
7ab6156b98
commit
d933b47c75
27 changed files with 4933 additions and 5 deletions
184
tests/pod/build.go
Normal file
184
tests/pod/build.go
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
Copyright 2019 The OpenEBS 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 pod
|
||||
|
||||
import (
|
||||
"github.com/openebs/zfs-localpv/pkg/common/errors"
|
||||
"github.com/openebs/zfs-localpv/tests/container"
|
||||
volume "github.com/openebs/zfs-localpv/tests/k8svolume"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
// k8sNodeLabelKeyHostname is the label key used by Kubernetes
|
||||
// to store the hostname on the node resource.
|
||||
k8sNodeLabelKeyHostname = "kubernetes.io/hostname"
|
||||
)
|
||||
|
||||
// Builder is the builder object for Pod
|
||||
type Builder struct {
|
||||
pod *Pod
|
||||
errs []error
|
||||
}
|
||||
|
||||
// NewBuilder returns new instance of Builder
|
||||
func NewBuilder() *Builder {
|
||||
return &Builder{pod: &Pod{object: &corev1.Pod{}}}
|
||||
}
|
||||
|
||||
// WithName sets the Name field of Pod with provided value.
|
||||
func (b *Builder) WithName(name string) *Builder {
|
||||
if len(name) == 0 {
|
||||
b.errs = append(
|
||||
b.errs,
|
||||
errors.New("failed to build Pod object: missing Pod name"),
|
||||
)
|
||||
return b
|
||||
}
|
||||
b.pod.object.Name = name
|
||||
return b
|
||||
}
|
||||
|
||||
// WithNamespace sets the Namespace field of Pod with provided value.
|
||||
func (b *Builder) WithNamespace(namespace string) *Builder {
|
||||
if len(namespace) == 0 {
|
||||
b.errs = append(
|
||||
b.errs,
|
||||
errors.New("failed to build Pod object: missing namespace"),
|
||||
)
|
||||
return b
|
||||
}
|
||||
b.pod.object.Namespace = namespace
|
||||
return b
|
||||
}
|
||||
|
||||
// WithContainerBuilder adds a container to this pod object.
|
||||
//
|
||||
// NOTE:
|
||||
// container details are present in the provided container
|
||||
// builder object
|
||||
func (b *Builder) WithContainerBuilder(
|
||||
containerBuilder *container.Builder,
|
||||
) *Builder {
|
||||
containerObj, err := containerBuilder.Build()
|
||||
if err != nil {
|
||||
b.errs = append(b.errs, errors.Wrap(err, "failed to build pod"))
|
||||
return b
|
||||
}
|
||||
b.pod.object.Spec.Containers = append(
|
||||
b.pod.object.Spec.Containers,
|
||||
containerObj,
|
||||
)
|
||||
return b
|
||||
}
|
||||
|
||||
// WithVolumeBuilder sets Volumes field of deployment.
|
||||
func (b *Builder) WithVolumeBuilder(volumeBuilder *volume.Builder) *Builder {
|
||||
vol, err := volumeBuilder.Build()
|
||||
if err != nil {
|
||||
b.errs = append(b.errs, errors.Wrap(err, "failed to build deployment"))
|
||||
return b
|
||||
}
|
||||
b.pod.object.Spec.Volumes = append(
|
||||
b.pod.object.Spec.Volumes,
|
||||
*vol,
|
||||
)
|
||||
return b
|
||||
}
|
||||
|
||||
// WithRestartPolicy sets the RestartPolicy field in Pod with provided arguments
|
||||
func (b *Builder) WithRestartPolicy(
|
||||
restartPolicy corev1.RestartPolicy,
|
||||
) *Builder {
|
||||
b.pod.object.Spec.RestartPolicy = restartPolicy
|
||||
return b
|
||||
}
|
||||
|
||||
// WithNodeName sets the NodeName field of Pod with provided value.
|
||||
func (b *Builder) WithNodeName(nodeName string) *Builder {
|
||||
if len(nodeName) == 0 {
|
||||
b.errs = append(
|
||||
b.errs,
|
||||
errors.New("failed to build Pod object: missing Pod node name"),
|
||||
)
|
||||
return b
|
||||
}
|
||||
b.pod.object.Spec.NodeName = nodeName
|
||||
return b
|
||||
}
|
||||
|
||||
// WithNodeSelectorHostnameNew sets the Pod NodeSelector to the provided hostname value
|
||||
// This function replaces (resets) the NodeSelector to use only hostname selector
|
||||
func (b *Builder) WithNodeSelectorHostnameNew(hostname string) *Builder {
|
||||
if len(hostname) == 0 {
|
||||
b.errs = append(
|
||||
b.errs,
|
||||
errors.New("failed to build Pod object: missing Pod hostname"),
|
||||
)
|
||||
return b
|
||||
}
|
||||
|
||||
b.pod.object.Spec.NodeSelector = map[string]string{
|
||||
k8sNodeLabelKeyHostname: hostname,
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// WithContainers sets the Containers field in Pod with provided arguments
|
||||
func (b *Builder) WithContainers(containers []corev1.Container) *Builder {
|
||||
if len(containers) == 0 {
|
||||
b.errs = append(
|
||||
b.errs,
|
||||
errors.New("failed to build Pod object: missing containers"),
|
||||
)
|
||||
return b
|
||||
}
|
||||
b.pod.object.Spec.Containers = containers
|
||||
return b
|
||||
}
|
||||
|
||||
// WithContainer sets the Containers field in Pod with provided arguments
|
||||
func (b *Builder) WithContainer(container corev1.Container) *Builder {
|
||||
return b.WithContainers([]corev1.Container{container})
|
||||
}
|
||||
|
||||
// WithVolumes sets the Volumes field in Pod with provided arguments
|
||||
func (b *Builder) WithVolumes(volumes []corev1.Volume) *Builder {
|
||||
if len(volumes) == 0 {
|
||||
b.errs = append(
|
||||
b.errs,
|
||||
errors.New("failed to build Pod object: missing volumes"),
|
||||
)
|
||||
return b
|
||||
}
|
||||
b.pod.object.Spec.Volumes = volumes
|
||||
return b
|
||||
}
|
||||
|
||||
// WithVolume sets the Volumes field in Pod with provided arguments
|
||||
func (b *Builder) WithVolume(volume corev1.Volume) *Builder {
|
||||
return b.WithVolumes([]corev1.Volume{volume})
|
||||
}
|
||||
|
||||
// Build returns the Pod API instance
|
||||
func (b *Builder) Build() (*corev1.Pod, error) {
|
||||
if len(b.errs) > 0 {
|
||||
return nil, errors.Errorf("%+v", b.errs)
|
||||
}
|
||||
return b.pod.object, nil
|
||||
}
|
||||
82
tests/pod/buildlist.go
Normal file
82
tests/pod/buildlist.go
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
Copyright 2019 The OpenEBS 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 pod
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// ListBuilder enables building an instance of
|
||||
// Podlist
|
||||
type ListBuilder struct {
|
||||
list *PodList
|
||||
filters predicateList
|
||||
}
|
||||
|
||||
// NewListBuilder returns a instance of ListBuilder
|
||||
func NewListBuilder() *ListBuilder {
|
||||
return &ListBuilder{list: &PodList{items: []*Pod{}}}
|
||||
}
|
||||
|
||||
// ListBuilderForAPIList returns a instance of ListBuilder from API PodList
|
||||
func ListBuilderForAPIList(pods *corev1.PodList) *ListBuilder {
|
||||
b := &ListBuilder{list: &PodList{}}
|
||||
if pods == nil {
|
||||
return b
|
||||
}
|
||||
for _, p := range pods.Items {
|
||||
p := p
|
||||
b.list.items = append(b.list.items, &Pod{object: &p})
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// ListBuilderForObjectList returns a instance of ListBuilder from API Pods
|
||||
func ListBuilderForObjectList(pods ...*Pod) *ListBuilder {
|
||||
b := &ListBuilder{list: &PodList{}}
|
||||
if pods == nil {
|
||||
return b
|
||||
}
|
||||
for _, p := range pods {
|
||||
p := p
|
||||
b.list.items = append(b.list.items, p)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// List returns the list of pod
|
||||
// instances that was built by this
|
||||
// builder
|
||||
func (b *ListBuilder) List() *PodList {
|
||||
if b.filters == nil || len(b.filters) == 0 {
|
||||
return b.list
|
||||
}
|
||||
filtered := &PodList{}
|
||||
for _, pod := range b.list.items {
|
||||
if b.filters.all(pod) {
|
||||
filtered.items = append(filtered.items, pod)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
// WithFilter add filters on which the pod
|
||||
// has to be filtered
|
||||
func (b *ListBuilder) WithFilter(pred ...Predicate) *ListBuilder {
|
||||
b.filters = append(b.filters, pred...)
|
||||
return b
|
||||
}
|
||||
406
tests/pod/kubernetes.go
Normal file
406
tests/pod/kubernetes.go
Normal file
|
|
@ -0,0 +1,406 @@
|
|||
// Copyright 2019 The OpenEBS 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 pod
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/openebs/zfs-localpv/pkg/common/errors"
|
||||
client "github.com/openebs/zfs-localpv/pkg/common/kubernetes/client"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
)
|
||||
|
||||
// getClientsetFn is a typed function that
|
||||
// abstracts fetching of clientset
|
||||
type getClientsetFn func() (*clientset.Clientset, error)
|
||||
|
||||
// getClientsetFromPathFn is a typed function that
|
||||
// abstracts fetching of clientset from kubeConfigPath
|
||||
type getClientsetForPathFn func(kubeConfigPath string) (*clientset.Clientset, error)
|
||||
|
||||
// getKubeConfigFn is a typed function that
|
||||
// abstracts fetching of config
|
||||
type getKubeConfigFn func() (*rest.Config, error)
|
||||
|
||||
// getKubeConfigForPathFn is a typed function that
|
||||
// abstracts fetching of config from kubeConfigPath
|
||||
type getKubeConfigForPathFn func(kubeConfigPath string) (*rest.Config, error)
|
||||
|
||||
// createFn is a typed function that abstracts
|
||||
// creation of pod
|
||||
type createFn func(cli *clientset.Clientset, namespace string, pod *corev1.Pod) (*corev1.Pod, error)
|
||||
|
||||
// listFn is a typed function that abstracts
|
||||
// listing of pods
|
||||
type listFn func(cli *clientset.Clientset, namespace string, opts metav1.ListOptions) (*corev1.PodList, error)
|
||||
|
||||
// deleteFn is a typed function that abstracts
|
||||
// deleting of pod
|
||||
type deleteFn func(cli *clientset.Clientset, namespace, name string, opts *metav1.DeleteOptions) error
|
||||
|
||||
// deleteFn is a typed function that abstracts
|
||||
// deletion of pod's collection
|
||||
type deleteCollectionFn func(cli *clientset.Clientset, namespace string, listOpts metav1.ListOptions, deleteOpts *metav1.DeleteOptions) error
|
||||
|
||||
// getFn is a typed function that abstracts
|
||||
// to get pod
|
||||
type getFn func(cli *clientset.Clientset, namespace, name string, opts metav1.GetOptions) (*corev1.Pod, error)
|
||||
|
||||
// execFn is a typed function that abstracts
|
||||
// pod exec
|
||||
type execFn func(cli *clientset.Clientset, config *rest.Config, name, namespace string, opts *corev1.PodExecOptions) (*ExecOutput, error)
|
||||
|
||||
// defaultExec is the default implementation of execFn
|
||||
func defaultExec(
|
||||
cli *clientset.Clientset,
|
||||
config *rest.Config,
|
||||
name string,
|
||||
namespace string,
|
||||
opts *corev1.PodExecOptions,
|
||||
) (*ExecOutput, error) {
|
||||
var stdout, stderr bytes.Buffer
|
||||
|
||||
req := cli.CoreV1().RESTClient().Post().
|
||||
Resource("pods").
|
||||
Name(name).
|
||||
Namespace(namespace).
|
||||
SubResource("exec").
|
||||
VersionedParams(opts, scheme.ParameterCodec)
|
||||
|
||||
// create exec executor which is an interface
|
||||
// for transporting shell-style streams
|
||||
exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Stream initiates transport of standard shell streams
|
||||
// It will transport any non-nil stream to a remote system,
|
||||
// and return an error if a problem occurs
|
||||
err = exec.Stream(remotecommand.StreamOptions{
|
||||
Stdin: nil,
|
||||
Stdout: &stdout,
|
||||
Stderr: &stderr,
|
||||
Tty: opts.TTY,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
execOutput := &ExecOutput{
|
||||
Stdout: stdout.String(),
|
||||
Stderr: stderr.String(),
|
||||
}
|
||||
return execOutput, nil
|
||||
}
|
||||
|
||||
// KubeClient enables kubernetes API operations
|
||||
// on pod instance
|
||||
type KubeClient struct {
|
||||
// clientset refers to pod clientset
|
||||
// that will be responsible to
|
||||
// make kubernetes API calls
|
||||
clientset *clientset.Clientset
|
||||
|
||||
// namespace holds the namespace on which
|
||||
// KubeClient has to operate
|
||||
namespace string
|
||||
|
||||
// kubeConfig represents kubernetes config
|
||||
kubeConfig *rest.Config
|
||||
|
||||
// kubeconfig path to get kubernetes clientset
|
||||
kubeConfigPath string
|
||||
|
||||
// functions useful during mocking
|
||||
getKubeConfig getKubeConfigFn
|
||||
getKubeConfigForPath getKubeConfigForPathFn
|
||||
getClientset getClientsetFn
|
||||
getClientsetForPath getClientsetForPathFn
|
||||
create createFn
|
||||
list listFn
|
||||
del deleteFn
|
||||
delCollection deleteCollectionFn
|
||||
get getFn
|
||||
exec execFn
|
||||
}
|
||||
|
||||
// ExecOutput struct contains stdout and stderr
|
||||
type ExecOutput struct {
|
||||
Stdout string `json:"stdout"`
|
||||
Stderr string `json:"stderr"`
|
||||
}
|
||||
|
||||
// KubeClientBuildOption defines the abstraction
|
||||
// to build a KubeClient instance
|
||||
type KubeClientBuildOption func(*KubeClient)
|
||||
|
||||
// withDefaults sets the default options
|
||||
// of KubeClient instance
|
||||
func (k *KubeClient) withDefaults() {
|
||||
if k.getKubeConfig == nil {
|
||||
k.getKubeConfig = func() (config *rest.Config, err error) {
|
||||
return client.New().Config()
|
||||
}
|
||||
}
|
||||
if k.getKubeConfigForPath == nil {
|
||||
k.getKubeConfigForPath = func(kubeConfigPath string) (
|
||||
config *rest.Config, err error) {
|
||||
return client.New(client.WithKubeConfigPath(kubeConfigPath)).
|
||||
GetConfigForPathOrDirect()
|
||||
}
|
||||
}
|
||||
if k.getClientset == nil {
|
||||
k.getClientset = func() (clients *clientset.Clientset, err error) {
|
||||
return client.New().Clientset()
|
||||
}
|
||||
}
|
||||
if k.getClientsetForPath == nil {
|
||||
k.getClientsetForPath = func(kubeConfigPath string) (
|
||||
clients *clientset.Clientset, err error) {
|
||||
return client.New(client.WithKubeConfigPath(kubeConfigPath)).Clientset()
|
||||
}
|
||||
}
|
||||
if k.create == nil {
|
||||
k.create = func(cli *clientset.Clientset,
|
||||
namespace string, pod *corev1.Pod) (*corev1.Pod, error) {
|
||||
return cli.CoreV1().Pods(namespace).Create(pod)
|
||||
}
|
||||
}
|
||||
if k.list == nil {
|
||||
k.list = func(cli *clientset.Clientset,
|
||||
namespace string, opts metav1.ListOptions) (*corev1.PodList, error) {
|
||||
return cli.CoreV1().Pods(namespace).List(opts)
|
||||
}
|
||||
}
|
||||
if k.del == nil {
|
||||
k.del = func(cli *clientset.Clientset, namespace,
|
||||
name string, opts *metav1.DeleteOptions) error {
|
||||
return cli.CoreV1().Pods(namespace).Delete(name, opts)
|
||||
}
|
||||
}
|
||||
if k.get == nil {
|
||||
k.get = func(cli *clientset.Clientset, namespace,
|
||||
name string, opts metav1.GetOptions) (*corev1.Pod, error) {
|
||||
return cli.CoreV1().Pods(namespace).Get(name, opts)
|
||||
}
|
||||
}
|
||||
if k.delCollection == nil {
|
||||
k.delCollection = func(cli *clientset.Clientset, namespace string,
|
||||
listOpts metav1.ListOptions, deleteOpts *metav1.DeleteOptions) error {
|
||||
return cli.CoreV1().Pods(namespace).DeleteCollection(deleteOpts, listOpts)
|
||||
}
|
||||
}
|
||||
if k.exec == nil {
|
||||
k.exec = defaultExec
|
||||
}
|
||||
}
|
||||
|
||||
// WithClientSet sets the kubernetes client against
|
||||
// the KubeClient instance
|
||||
func WithClientSet(c *clientset.Clientset) KubeClientBuildOption {
|
||||
return func(k *KubeClient) {
|
||||
k.clientset = c
|
||||
}
|
||||
}
|
||||
|
||||
// WithKubeConfigPath sets the kubeConfig path
|
||||
// against client instance
|
||||
func WithKubeConfigPath(path string) KubeClientBuildOption {
|
||||
return func(k *KubeClient) {
|
||||
k.kubeConfigPath = path
|
||||
}
|
||||
}
|
||||
|
||||
// NewKubeClient returns a new instance of KubeClient meant for
|
||||
// zfs volume replica operations
|
||||
func NewKubeClient(opts ...KubeClientBuildOption) *KubeClient {
|
||||
k := &KubeClient{}
|
||||
for _, o := range opts {
|
||||
o(k)
|
||||
}
|
||||
k.withDefaults()
|
||||
return k
|
||||
}
|
||||
|
||||
// WithNamespace sets the kubernetes namespace against
|
||||
// the provided namespace
|
||||
func (k *KubeClient) WithNamespace(namespace string) *KubeClient {
|
||||
k.namespace = namespace
|
||||
return k
|
||||
}
|
||||
|
||||
// WithKubeConfig sets the kubernetes config against
|
||||
// the KubeClient instance
|
||||
func (k *KubeClient) WithKubeConfig(config *rest.Config) *KubeClient {
|
||||
k.kubeConfig = config
|
||||
return k
|
||||
}
|
||||
|
||||
func (k *KubeClient) getClientsetForPathOrDirect() (
|
||||
*clientset.Clientset, error) {
|
||||
if k.kubeConfigPath != "" {
|
||||
return k.getClientsetForPath(k.kubeConfigPath)
|
||||
}
|
||||
return k.getClientset()
|
||||
}
|
||||
|
||||
// getClientsetOrCached returns either a new instance
|
||||
// of kubernetes client or its cached copy
|
||||
func (k *KubeClient) getClientsetOrCached() (*clientset.Clientset, error) {
|
||||
if k.clientset != nil {
|
||||
return k.clientset, nil
|
||||
}
|
||||
|
||||
cs, err := k.getClientsetForPathOrDirect()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get clientset")
|
||||
}
|
||||
k.clientset = cs
|
||||
return k.clientset, nil
|
||||
}
|
||||
|
||||
func (k *KubeClient) getKubeConfigForPathOrDirect() (*rest.Config, error) {
|
||||
if k.kubeConfigPath != "" {
|
||||
return k.getKubeConfigForPath(k.kubeConfigPath)
|
||||
}
|
||||
return k.getKubeConfig()
|
||||
}
|
||||
|
||||
// getKubeConfigOrCached returns either a new instance
|
||||
// of kubernetes config or its cached copy
|
||||
func (k *KubeClient) getKubeConfigOrCached() (*rest.Config, error) {
|
||||
if k.kubeConfig != nil {
|
||||
return k.kubeConfig, nil
|
||||
}
|
||||
|
||||
kc, err := k.getKubeConfigForPathOrDirect()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get kube config")
|
||||
}
|
||||
k.kubeConfig = kc
|
||||
return k.kubeConfig, nil
|
||||
}
|
||||
|
||||
// List returns a list of pod
|
||||
// instances present in kubernetes cluster
|
||||
func (k *KubeClient) List(opts metav1.ListOptions) (*corev1.PodList, error) {
|
||||
cli, err := k.getClientsetOrCached()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to list pods")
|
||||
}
|
||||
return k.list(cli, k.namespace, opts)
|
||||
}
|
||||
|
||||
// Delete deletes a pod instance present in kubernetes cluster
|
||||
func (k *KubeClient) Delete(name string, opts *metav1.DeleteOptions) error {
|
||||
if len(name) == 0 {
|
||||
return errors.New("failed to delete pod: missing pod name")
|
||||
}
|
||||
cli, err := k.getClientsetOrCached()
|
||||
if err != nil {
|
||||
return errors.Wrapf(
|
||||
err,
|
||||
"failed to delete pod {%s}: failed to get clientset",
|
||||
name,
|
||||
)
|
||||
}
|
||||
return k.del(cli, k.namespace, name, opts)
|
||||
}
|
||||
|
||||
// Create creates a pod in specified namespace in kubernetes cluster
|
||||
func (k *KubeClient) Create(pod *corev1.Pod) (*corev1.Pod, error) {
|
||||
if pod == nil {
|
||||
return nil, errors.New("failed to create pod: nil pod object")
|
||||
}
|
||||
cli, err := k.getClientsetOrCached()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(
|
||||
err,
|
||||
"failed to create pod {%s} in namespace {%s}",
|
||||
pod.Name,
|
||||
pod.Namespace,
|
||||
)
|
||||
}
|
||||
return k.create(cli, k.namespace, pod)
|
||||
}
|
||||
|
||||
// Get gets a pod object present in kubernetes cluster
|
||||
func (k *KubeClient) Get(name string,
|
||||
opts metav1.GetOptions) (*corev1.Pod, error) {
|
||||
if len(name) == 0 {
|
||||
return nil, errors.New("failed to get pod: missing pod name")
|
||||
}
|
||||
cli, err := k.getClientsetOrCached()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(
|
||||
err,
|
||||
"failed to get pod {%s}: failed to get clientset",
|
||||
name,
|
||||
)
|
||||
}
|
||||
return k.get(cli, k.namespace, name, opts)
|
||||
}
|
||||
|
||||
// GetRaw gets pod object for a given name and namespace present
|
||||
// in kubernetes cluster and returns result in raw byte.
|
||||
func (k *KubeClient) GetRaw(name string,
|
||||
opts metav1.GetOptions) ([]byte, error) {
|
||||
p, err := k.Get(name, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(p)
|
||||
}
|
||||
|
||||
// Exec runs a command remotely in a container of a pod
|
||||
func (k *KubeClient) Exec(name string,
|
||||
opts *corev1.PodExecOptions) (*ExecOutput, error) {
|
||||
cli, err := k.getClientsetOrCached()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config, err := k.getKubeConfigOrCached()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return k.exec(cli, config, name, k.namespace, opts)
|
||||
}
|
||||
|
||||
// ExecRaw runs a command remotely in a container of a pod
|
||||
// and returns raw output
|
||||
func (k *KubeClient) ExecRaw(name string,
|
||||
opts *corev1.PodExecOptions) ([]byte, error) {
|
||||
execOutput, err := k.Exec(name, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(execOutput)
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of pod objects.
|
||||
func (k *KubeClient) DeleteCollection(listOpts metav1.ListOptions, deleteOpts *metav1.DeleteOptions) error {
|
||||
cli, err := k.getClientsetOrCached()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to delete the collection of pods")
|
||||
}
|
||||
return k.delCollection(cli, k.namespace, listOpts, deleteOpts)
|
||||
}
|
||||
183
tests/pod/pod.go
Normal file
183
tests/pod/pod.go
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
// Copyright 2019 The OpenEBS 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 pod
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// Pod holds the api's pod objects
|
||||
type Pod struct {
|
||||
object *corev1.Pod
|
||||
}
|
||||
|
||||
// PodList holds the list of API pod instances
|
||||
type PodList struct {
|
||||
items []*Pod
|
||||
}
|
||||
|
||||
// PredicateList holds a list of predicate
|
||||
type predicateList []Predicate
|
||||
|
||||
// Predicate defines an abstraction
|
||||
// to determine conditional checks
|
||||
// against the provided pod instance
|
||||
type Predicate func(*Pod) bool
|
||||
|
||||
// ToAPIList converts PodList to API PodList
|
||||
func (pl *PodList) ToAPIList() *corev1.PodList {
|
||||
plist := &corev1.PodList{}
|
||||
for _, pod := range pl.items {
|
||||
plist.Items = append(plist.Items, *pod.object)
|
||||
}
|
||||
return plist
|
||||
}
|
||||
|
||||
type podBuildOption func(*Pod)
|
||||
|
||||
// NewForAPIObject returns a new instance of Pod
|
||||
func NewForAPIObject(obj *corev1.Pod, opts ...podBuildOption) *Pod {
|
||||
p := &Pod{object: obj}
|
||||
for _, o := range opts {
|
||||
o(p)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Len returns the number of items present in the PodList
|
||||
func (pl *PodList) Len() int {
|
||||
return len(pl.items)
|
||||
}
|
||||
|
||||
// all returns true if all the predicates
|
||||
// succeed against the provided pod
|
||||
// instance
|
||||
func (l predicateList) all(p *Pod) bool {
|
||||
for _, pred := range l {
|
||||
if !pred(p) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsRunning retuns true if the pod is in running
|
||||
// state
|
||||
func (p *Pod) IsRunning() bool {
|
||||
return p.object.Status.Phase == "Running"
|
||||
}
|
||||
|
||||
// IsRunning is a predicate to filter out pods
|
||||
// which in running state
|
||||
func IsRunning() Predicate {
|
||||
return func(p *Pod) bool {
|
||||
return p.IsRunning()
|
||||
}
|
||||
}
|
||||
|
||||
// IsCompleted retuns true if the pod is in completed
|
||||
// state
|
||||
func (p *Pod) IsCompleted() bool {
|
||||
return p.object.Status.Phase == "Succeeded"
|
||||
}
|
||||
|
||||
// IsCompleted is a predicate to filter out pods
|
||||
// which in completed state
|
||||
func IsCompleted() Predicate {
|
||||
return func(p *Pod) bool {
|
||||
return p.IsCompleted()
|
||||
}
|
||||
}
|
||||
|
||||
// HasLabels returns true if provided labels
|
||||
// map[key]value are present in the provided PodList
|
||||
// instance
|
||||
func HasLabels(keyValuePair map[string]string) Predicate {
|
||||
return func(p *Pod) bool {
|
||||
// objKeyValues := p.object.GetLabels()
|
||||
for key, value := range keyValuePair {
|
||||
if !p.HasLabel(key, value) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// HasLabel return true if provided lable
|
||||
// key and value are present in the the provided PodList
|
||||
// instance
|
||||
func (p *Pod) HasLabel(key, value string) bool {
|
||||
val, ok := p.object.GetLabels()[key]
|
||||
if ok {
|
||||
return val == value
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// HasLabel is predicate to filter out labeled
|
||||
// pod instances
|
||||
func HasLabel(key, value string) Predicate {
|
||||
return func(p *Pod) bool {
|
||||
return p.HasLabel(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// IsNil returns true if the pod instance
|
||||
// is nil
|
||||
func (p *Pod) IsNil() bool {
|
||||
return p.object == nil
|
||||
}
|
||||
|
||||
// IsNil is predicate to filter out nil pod
|
||||
// instances
|
||||
func IsNil() Predicate {
|
||||
return func(p *Pod) bool {
|
||||
return p.IsNil()
|
||||
}
|
||||
}
|
||||
|
||||
// GetAPIObject returns a API's Pod
|
||||
func (p *Pod) GetAPIObject() *corev1.Pod {
|
||||
return p.object
|
||||
}
|
||||
|
||||
// FromList created a PodList with provided api podlist
|
||||
func FromList(pods *corev1.PodList) *PodList {
|
||||
pl := ListBuilderForAPIList(pods).
|
||||
List()
|
||||
return pl
|
||||
}
|
||||
|
||||
// GetScheduledNodes returns the nodes on which pods are scheduled
|
||||
func (pl *PodList) GetScheduledNodes() map[string]int {
|
||||
nodeNames := make(map[string]int)
|
||||
for _, p := range pl.items {
|
||||
p := p // pin it
|
||||
nodeNames[p.object.Spec.NodeName]++
|
||||
}
|
||||
return nodeNames
|
||||
}
|
||||
|
||||
// IsMatchNodeAny checks the PodList is running on the provided nodes
|
||||
func (pl *PodList) IsMatchNodeAny(nodes map[string]int) bool {
|
||||
for _, p := range pl.items {
|
||||
p := p // pin it
|
||||
if nodes[p.object.Spec.NodeName] == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue