test(zfspv): minikube setup for travis

to run integration test cases

Signed-off-by: Pawan <pawan@mayadata.io>
This commit is contained in:
Pawan 2019-11-26 17:09:07 +05:30 committed by Kiran Mova
parent 7ab6156b98
commit d933b47c75
27 changed files with 4933 additions and 5 deletions

181
tests/pvc/build.go Normal file
View file

@ -0,0 +1,181 @@
/*
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 pvc
import (
"github.com/openebs/zfs-localpv/pkg/common/errors"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
)
// Builder is the builder object for PVC
type Builder struct {
pvc *PVC
errs []error
}
// NewBuilder returns new instance of Builder
func NewBuilder() *Builder {
return &Builder{pvc: &PVC{object: &corev1.PersistentVolumeClaim{}}}
}
// BuildFrom returns new instance of Builder
// from the provided api instance
func BuildFrom(pvc *corev1.PersistentVolumeClaim) *Builder {
if pvc == nil {
b := NewBuilder()
b.errs = append(
b.errs,
errors.New("failed to build pvc object: nil pvc"),
)
return b
}
return &Builder{
pvc: &PVC{
object: pvc,
},
}
}
// WithName sets the Name field of PVC with provided value.
func (b *Builder) WithName(name string) *Builder {
if len(name) == 0 {
b.errs = append(b.errs, errors.New("failed to build PVC object: missing PVC name"))
return b
}
b.pvc.object.Name = name
return b
}
// WithGenerateName sets the GenerateName field of
// PVC with provided value
func (b *Builder) WithGenerateName(name string) *Builder {
if len(name) == 0 {
b.errs = append(
b.errs,
errors.New("failed to build PVC object: missing PVC generateName"),
)
return b
}
b.pvc.object.GenerateName = name
return b
}
// WithNamespace sets the Namespace field of PVC provided arguments
func (b *Builder) WithNamespace(namespace string) *Builder {
if len(namespace) == 0 {
namespace = "default"
}
b.pvc.object.Namespace = namespace
return b
}
// WithAnnotations sets the Annotations field of PVC with provided arguments
func (b *Builder) WithAnnotations(annotations map[string]string) *Builder {
if len(annotations) == 0 {
b.errs = append(b.errs, errors.New("failed to build PVC object: missing annotations"))
return b
}
b.pvc.object.Annotations = annotations
return b
}
// WithLabels merges existing labels if any
// with the ones that are provided here
func (b *Builder) WithLabels(labels map[string]string) *Builder {
if len(labels) == 0 {
b.errs = append(
b.errs,
errors.New("failed to build PVC object: missing labels"),
)
return b
}
if b.pvc.object.Labels == nil {
b.pvc.object.Labels = map[string]string{}
}
for key, value := range labels {
b.pvc.object.Labels[key] = value
}
return b
}
// WithLabelsNew resets existing labels if any with
// ones that are provided here
func (b *Builder) WithLabelsNew(labels map[string]string) *Builder {
if len(labels) == 0 {
b.errs = append(
b.errs,
errors.New("failed to build PVC object: missing labels"),
)
return b
}
// copy of original map
newlbls := map[string]string{}
for key, value := range labels {
newlbls[key] = value
}
// override
b.pvc.object.Labels = newlbls
return b
}
// WithStorageClass sets the StorageClass field of PVC with provided arguments
func (b *Builder) WithStorageClass(scName string) *Builder {
if len(scName) == 0 {
b.errs = append(b.errs, errors.New("failed to build PVC object: missing storageclass name"))
return b
}
b.pvc.object.Spec.StorageClassName = &scName
return b
}
// WithAccessModes sets the AccessMode field in PVC with provided arguments
func (b *Builder) WithAccessModes(accessMode []corev1.PersistentVolumeAccessMode) *Builder {
if len(accessMode) == 0 {
b.errs = append(b.errs, errors.New("failed to build PVC object: missing accessmodes"))
return b
}
b.pvc.object.Spec.AccessModes = accessMode
return b
}
// WithCapacity sets the Capacity field in PVC with provided arguments
func (b *Builder) WithCapacity(capacity string) *Builder {
resCapacity, err := resource.ParseQuantity(capacity)
if err != nil {
b.errs = append(b.errs, errors.Wrapf(err, "failed to build PVC object: failed to parse capacity {%s}", capacity))
return b
}
resourceList := corev1.ResourceList{
corev1.ResourceName(corev1.ResourceStorage): resCapacity,
}
b.pvc.object.Spec.Resources.Requests = resourceList
return b
}
// Build returns the PVC API instance
func (b *Builder) Build() (*corev1.PersistentVolumeClaim, error) {
if len(b.errs) > 0 {
return nil, errors.Errorf("%+v", b.errs)
}
return b.pvc.object, nil
}

165
tests/pvc/buildlist.go Normal file
View file

@ -0,0 +1,165 @@
/*
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 pvc
import (
"github.com/openebs/zfs-localpv/pkg/common/errors"
corev1 "k8s.io/api/core/v1"
)
// ListBuilder enables building an instance of
// PVCList
type ListBuilder struct {
// template to build a list of pvcs
template *corev1.PersistentVolumeClaim
// count determines the number of
// pvcs to be built using the provided
// template
count int
list *PVCList
filters PredicateList
errs []error
}
// NewListBuilder returns an instance of ListBuilder
func NewListBuilder() *ListBuilder {
return &ListBuilder{list: &PVCList{}}
}
// ListBuilderFromTemplate returns a new instance of
// ListBuilder based on the provided pvc template
func ListBuilderFromTemplate(pvc *corev1.PersistentVolumeClaim) *ListBuilder {
b := NewListBuilder()
if pvc == nil {
b.errs = append(
b.errs,
errors.New("failed to build pvc list: nil pvc template"),
)
return b
}
b.template = pvc
b.count = 1
return b
}
// ListBuilderForAPIObjects returns a new instance of
// ListBuilder based on provided api pvc list
func ListBuilderForAPIObjects(pvcs *corev1.PersistentVolumeClaimList) *ListBuilder {
b := &ListBuilder{list: &PVCList{}}
if pvcs == nil {
b.errs = append(
b.errs,
errors.New("failed to build pvc list: missing api list"),
)
return b
}
for _, pvc := range pvcs.Items {
pvc := pvc
b.list.items = append(b.list.items, &PVC{object: &pvc})
}
return b
}
// ListBuilderForObjects returns a new instance of
// ListBuilder based on provided pvc list
func ListBuilderForObjects(pvcs *PVCList) *ListBuilder {
b := &ListBuilder{}
if pvcs == nil {
b.errs = append(
b.errs,
errors.New("failed to build pvc list: missing object list"),
)
return b
}
b.list = pvcs
return b
}
// WithFilter adds filters on which the pvcs
// are filtered
func (b *ListBuilder) WithFilter(pred ...Predicate) *ListBuilder {
b.filters = append(b.filters, pred...)
return b
}
// WithCount sets the count that determines
// the number of pvcs to be built
func (b *ListBuilder) WithCount(count int) *ListBuilder {
b.count = count
return b
}
func (b *ListBuilder) buildFromTemplateIfNilList() {
if len(b.list.items) != 0 || b.template == nil {
return
}
for i := 0; i < b.count; i++ {
b.list.items = append(b.list.items, &PVC{object: b.template})
}
}
// List returns the list of pvc instances
// that was built by this builder
func (b *ListBuilder) List() (*PVCList, error) {
if len(b.errs) > 0 {
return nil, errors.Errorf("failed to build pvc list: %+v", b.errs)
}
b.buildFromTemplateIfNilList()
if b.filters == nil || len(b.filters) == 0 {
return b.list, nil
}
filteredList := &PVCList{}
for _, pvc := range b.list.items {
if b.filters.all(pvc) {
filteredList.items = append(filteredList.items, pvc)
}
}
return filteredList, nil
}
// Len returns the number of items present
// in the PVCList of a builder
func (b *ListBuilder) Len() (int, error) {
l, err := b.List()
if err != nil {
return 0, err
}
return l.Len(), nil
}
// APIList builds core API PVC list using listbuilder
func (b *ListBuilder) APIList() (*corev1.PersistentVolumeClaimList, error) {
l, err := b.List()
if err != nil {
return nil, err
}
return l.ToAPIList(), nil
}

288
tests/pvc/kubernetes.go Normal file
View file

@ -0,0 +1,288 @@
// 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 pvc
import (
"strings"
"github.com/openebs/zfs-localpv/pkg/common/errors"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
client "github.com/openebs/zfs-localpv/pkg/common/kubernetes/client"
"k8s.io/client-go/kubernetes"
)
// getClientsetFn is a typed function that
// abstracts fetching of clientset
type getClientsetFn func() (clientset *kubernetes.Clientset, err error)
// getClientsetFromPathFn is a typed function that
// abstracts fetching of clientset from kubeConfigPath
type getClientsetForPathFn func(kubeConfigPath string) (clientset *kubernetes.Clientset, err error)
// getpvcFn is a typed function that
// abstracts fetching of pvc
type getFn func(cli *kubernetes.Clientset, name string, namespace string, opts metav1.GetOptions) (*corev1.PersistentVolumeClaim, error)
// listFn is a typed function that abstracts
// listing of pvcs
type listFn func(cli *kubernetes.Clientset, namespace string, opts metav1.ListOptions) (*corev1.PersistentVolumeClaimList, error)
// deleteFn is a typed function that abstracts
// deletion of pvcs
type deleteFn func(cli *kubernetes.Clientset, namespace string, name string, deleteOpts *metav1.DeleteOptions) error
// deleteFn is a typed function that abstracts
// deletion of pvc's collection
type deleteCollectionFn func(cli *kubernetes.Clientset, namespace string, listOpts metav1.ListOptions, deleteOpts *metav1.DeleteOptions) error
// createFn is a typed function that abstracts
// creation of pvc
type createFn func(cli *kubernetes.Clientset, namespace string, pvc *corev1.PersistentVolumeClaim) (*corev1.PersistentVolumeClaim, error)
// updateFn is a typed function that abstracts
// updation of pvc
type updateFn func(cli *kubernetes.Clientset, namespace string, pvc *corev1.PersistentVolumeClaim) (*corev1.PersistentVolumeClaim, error)
// Kubeclient enables kubernetes API operations
// on pvc instance
type Kubeclient struct {
// clientset refers to pvc clientset
// that will be responsible to
// make kubernetes API calls
clientset *kubernetes.Clientset
// namespace holds the namespace on which
// kubeclient has to operate
namespace string
// kubeconfig path to get kubernetes clientset
kubeConfigPath string
// functions useful during mocking
getClientset getClientsetFn
getClientsetForPath getClientsetForPathFn
list listFn
get getFn
create createFn
update updateFn
del deleteFn
delCollection deleteCollectionFn
}
// KubeclientBuildOption abstracts creating an
// instance of kubeclient
type KubeclientBuildOption func(*Kubeclient)
// withDefaults sets the default options
// of kubeclient instance
func (k *Kubeclient) withDefaults() {
if k.getClientset == nil {
k.getClientset = func() (clients *kubernetes.Clientset, err error) {
return client.New().Clientset()
}
}
if k.getClientsetForPath == nil {
k.getClientsetForPath = func(kubeConfigPath string) (clients *kubernetes.Clientset, err error) {
return client.New(client.WithKubeConfigPath(kubeConfigPath)).Clientset()
}
}
if k.get == nil {
k.get = func(cli *kubernetes.Clientset, name string, namespace string, opts metav1.GetOptions) (*corev1.PersistentVolumeClaim, error) {
return cli.CoreV1().PersistentVolumeClaims(namespace).Get(name, opts)
}
}
if k.list == nil {
k.list = func(cli *kubernetes.Clientset, namespace string, opts metav1.ListOptions) (*corev1.PersistentVolumeClaimList, error) {
return cli.CoreV1().PersistentVolumeClaims(namespace).List(opts)
}
}
if k.del == nil {
k.del = func(cli *kubernetes.Clientset, namespace string, name string, deleteOpts *metav1.DeleteOptions) error {
return cli.CoreV1().PersistentVolumeClaims(namespace).Delete(name, deleteOpts)
}
}
if k.delCollection == nil {
k.delCollection = func(cli *kubernetes.Clientset, namespace string, listOpts metav1.ListOptions, deleteOpts *metav1.DeleteOptions) error {
return cli.CoreV1().PersistentVolumeClaims(namespace).DeleteCollection(deleteOpts, listOpts)
}
}
if k.create == nil {
k.create = func(cli *kubernetes.Clientset, namespace string, pvc *corev1.PersistentVolumeClaim) (*corev1.PersistentVolumeClaim, error) {
return cli.CoreV1().PersistentVolumeClaims(namespace).Create(pvc)
}
}
if k.update == nil {
k.update = func(cli *kubernetes.Clientset, namespace string, pvc *corev1.PersistentVolumeClaim) (*corev1.PersistentVolumeClaim, error) {
return cli.CoreV1().PersistentVolumeClaims(namespace).Update(pvc)
}
}
}
// WithClientSet sets the kubernetes client against
// the kubeclient instance
func WithClientSet(c *kubernetes.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
// pvc operations
func NewKubeClient(opts ...KubeclientBuildOption) *Kubeclient {
k := &Kubeclient{}
for _, o := range opts {
o(k)
}
k.withDefaults()
return k
}
// WithNamespace sets the kubernetes client against
// the provided namespace
func (k *Kubeclient) WithNamespace(namespace string) *Kubeclient {
k.namespace = namespace
return k
}
func (k *Kubeclient) getClientsetForPathOrDirect() (*kubernetes.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() (*kubernetes.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
}
// Get returns a pvc resource
// instances present in kubernetes cluster
func (k *Kubeclient) Get(name string, opts metav1.GetOptions) (*corev1.PersistentVolumeClaim, error) {
if strings.TrimSpace(name) == "" {
return nil, errors.New("failed to get pvc: missing pvc name")
}
cli, err := k.getClientsetOrCached()
if err != nil {
return nil, errors.Wrapf(err, "failed to get pvc {%s}", name)
}
return k.get(cli, name, k.namespace, opts)
}
// List returns a list of pvc
// instances present in kubernetes cluster
func (k *Kubeclient) List(opts metav1.ListOptions) (*corev1.PersistentVolumeClaimList, error) {
cli, err := k.getClientsetOrCached()
if err != nil {
return nil, errors.Wrapf(err, "failed to list pvc listoptions: '%v'", opts)
}
return k.list(cli, k.namespace, opts)
}
// Delete deletes a pvc instance from the
// kubecrnetes cluster
func (k *Kubeclient) Delete(name string, deleteOpts *metav1.DeleteOptions) error {
if strings.TrimSpace(name) == "" {
return errors.New("failed to delete pvc: missing pvc name")
}
cli, err := k.getClientsetOrCached()
if err != nil {
return errors.Wrapf(err, "failed to delete pvc {%s}", name)
}
return k.del(cli, k.namespace, name, deleteOpts)
}
// Create creates a pvc in specified namespace in kubernetes cluster
func (k *Kubeclient) Create(pvc *corev1.PersistentVolumeClaim) (*corev1.PersistentVolumeClaim, error) {
if pvc == nil {
return nil, errors.New("failed to create pvc: nil pvc object")
}
cli, err := k.getClientsetOrCached()
if err != nil {
return nil, errors.Wrapf(err, "failed to create pvc {%s} in namespace {%s}", pvc.Name, pvc.Namespace)
}
return k.create(cli, k.namespace, pvc)
}
// Update updates a pvc in specified namespace in kubernetes cluster
func (k *Kubeclient) Update(pvc *corev1.PersistentVolumeClaim) (*corev1.PersistentVolumeClaim, error) {
if pvc == nil {
return nil, errors.New("failed to update pvc: nil pvc object")
}
cli, err := k.getClientsetOrCached()
if err != nil {
return nil, errors.Wrapf(err, "failed to update pvc {%s} in namespace {%s}", pvc.Name, pvc.Namespace)
}
return k.update(cli, k.namespace, pvc)
}
// CreateCollection creates a list of pvcs
// in specified namespace in kubernetes cluster
func (k *Kubeclient) CreateCollection(
list *corev1.PersistentVolumeClaimList,
) (*corev1.PersistentVolumeClaimList, error) {
if list == nil || len(list.Items) == 0 {
return nil, errors.New("failed to create list of pvcs: nil pvc list provided")
}
newlist := &corev1.PersistentVolumeClaimList{}
for _, item := range list.Items {
item := item
obj, err := k.Create(&item)
if err != nil {
return nil, err
}
newlist.Items = append(newlist.Items, *obj)
}
return newlist, nil
}
// DeleteCollection deletes a collection of pvc 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 pvcs")
}
return k.delCollection(cli, k.namespace, listOpts, deleteOpts)
}

View file

@ -0,0 +1,116 @@
// 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 pvc
import (
"strings"
corev1 "k8s.io/api/core/v1"
)
// PVC is a wrapper over persistentvolumeclaim api
// object. It provides build, validations and other common
// logic to be used by various feature specific callers.
type PVC struct {
object *corev1.PersistentVolumeClaim
}
// PVCList is a wrapper over persistentvolumeclaim api
// object. It provides build, validations and other common
// logic to be used by various feature specific callers.
type PVCList struct {
items []*PVC
}
// Len returns the number of items present
// in the PVCList
func (p *PVCList) Len() int {
return len(p.items)
}
// ToAPIList converts PVCList to API PVCList
func (p *PVCList) ToAPIList() *corev1.PersistentVolumeClaimList {
plist := &corev1.PersistentVolumeClaimList{}
for _, pvc := range p.items {
plist.Items = append(plist.Items, *pvc.object)
}
return plist
}
type pvcBuildOption func(*PVC)
// NewForAPIObject returns a new instance of PVC
func NewForAPIObject(obj *corev1.PersistentVolumeClaim, opts ...pvcBuildOption) *PVC {
p := &PVC{object: obj}
for _, o := range opts {
o(p)
}
return p
}
// Predicate defines an abstraction
// to determine conditional checks
// against the provided pvc instance
type Predicate func(*PVC) bool
// IsBound returns true if the pvc is bounded
func (p *PVC) IsBound() bool {
return p.object.Status.Phase == corev1.ClaimBound
}
// IsBound is a predicate to filter out pvcs
// which is bounded
func IsBound() Predicate {
return func(p *PVC) bool {
return p.IsBound()
}
}
// IsNil returns true if the PVC instance
// is nil
func (p *PVC) IsNil() bool {
return p.object == nil
}
// IsNil is predicate to filter out nil PVC
// instances
func IsNil() Predicate {
return func(p *PVC) bool {
return p.IsNil()
}
}
// ContainsName is filter function to filter pvc's
// based on the name
func ContainsName(name string) Predicate {
return func(p *PVC) bool {
return strings.Contains(p.object.GetName(), name)
}
}
// PredicateList holds a list of predicate
type PredicateList []Predicate
// all returns true if all the predicates
// succeed against the provided pvc
// instance
func (l PredicateList) all(p *PVC) bool {
for _, pred := range l {
if !pred(p) {
return false
}
}
return true
}