// Copyright © 2020 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 restorebuilder import ( "context" "encoding/json" client "github.com/openebs/lib-csi/pkg/common/kubernetes/client" apis "github.com/openebs/zfs-localpv/pkg/apis/openebs.io/zfs/v1" clientset "github.com/openebs/zfs-localpv/pkg/generated/clientset/internalclientset" "github.com/pkg/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // getClientsetFn is a typed function that // abstracts fetching of internal clientset type getClientsetFn func() (clientset *clientset.Clientset, err error) // getClientsetFromPathFn is a typed function that // abstracts fetching of clientset from kubeConfigPath type getClientsetForPathFn func(kubeConfigPath string) ( clientset *clientset.Clientset, err error, ) // createFn is a typed function that abstracts // creating zfsrstr rstrume instance type createFn func( cs *clientset.Clientset, upgradeResultObj *apis.ZFSRestore, namespace string, ) (*apis.ZFSRestore, error) // getFn is a typed function that abstracts // fetching a zfsrstr rstrume instance type getFn func( cli *clientset.Clientset, name, namespace string, opts metav1.GetOptions, ) (*apis.ZFSRestore, error) // listFn is a typed function that abstracts // listing of zfsrstr rstrume instances type listFn func( cli *clientset.Clientset, namespace string, opts metav1.ListOptions, ) (*apis.ZFSRestoreList, error) // delFn is a typed function that abstracts // deleting a zfsrstr rstrume instance type delFn func( cli *clientset.Clientset, name, namespace string, opts *metav1.DeleteOptions, ) error // updateFn is a typed function that abstracts // updating zfsrstr rstrume instance type updateFn func( cs *clientset.Clientset, rstr *apis.ZFSRestore, namespace string, ) (*apis.ZFSRestore, error) // Kubeclient enables kubernetes API operations // on zfsrstr rstrume instance type Kubeclient struct { // clientset refers to zfsrstr rstrume's // clientset that will be responsible to // make kubernetes API calls clientset *clientset.Clientset kubeConfigPath string // namespace holds the namespace on which // kubeclient has to operate namespace string // functions useful during mocking getClientset getClientsetFn getClientsetForPath getClientsetForPathFn get getFn list listFn del delFn create createFn update updateFn } // KubeclientBuildOption defines the abstraction // to build a kubeclient instance type KubeclientBuildOption func(*Kubeclient) // defaultGetClientset is the default implementation to // get kubernetes clientset instance func defaultGetClientset() (clients *clientset.Clientset, err error) { config, err := client.GetConfig(client.New()) if err != nil { return nil, err } return clientset.NewForConfig(config) } // defaultGetClientsetForPath is the default implementation to // get kubernetes clientset instance based on the given // kubeconfig path func defaultGetClientsetForPath( kubeConfigPath string, ) (clients *clientset.Clientset, err error) { config, err := client.GetConfig( client.New(client.WithKubeConfigPath(kubeConfigPath))) if err != nil { return nil, err } return clientset.NewForConfig(config) } // defaultGet is the default implementation to get // a zfsrstr rstrume instance in kubernetes cluster func defaultGet( cli *clientset.Clientset, name, namespace string, opts metav1.GetOptions, ) (*apis.ZFSRestore, error) { return cli.ZfsV1(). ZFSRestores(namespace). Get(context.TODO(), name, opts) } // defaultList is the default implementation to list // zfsrstr rstrume instances in kubernetes cluster func defaultList( cli *clientset.Clientset, namespace string, opts metav1.ListOptions, ) (*apis.ZFSRestoreList, error) { return cli.ZfsV1(). ZFSRestores(namespace). List(context.TODO(), opts) } // defaultCreate is the default implementation to delete // a zfsrstr rstrume instance in kubernetes cluster func defaultDel( cli *clientset.Clientset, name, namespace string, opts *metav1.DeleteOptions, ) error { deletePropagation := metav1.DeletePropagationForeground opts.PropagationPolicy = &deletePropagation err := cli.ZfsV1(). ZFSRestores(namespace). Delete(context.TODO(), name, *opts) return err } // defaultCreate is the default implementation to create // a zfsrstr rstrume instance in kubernetes cluster func defaultCreate( cli *clientset.Clientset, rstr *apis.ZFSRestore, namespace string, ) (*apis.ZFSRestore, error) { return cli.ZfsV1(). ZFSRestores(namespace). Create(context.TODO(), rstr, metav1.CreateOptions{}) } // defaultUpdate is the default implementation to update // a zfsrstr rstrume instance in kubernetes cluster func defaultUpdate( cli *clientset.Clientset, rstr *apis.ZFSRestore, namespace string, ) (*apis.ZFSRestore, error) { return cli.ZfsV1(). ZFSRestores(namespace). Update(context.TODO(), rstr, metav1.UpdateOptions{}) } // withDefaults sets the default options // of kubeclient instance func (k *Kubeclient) withDefaults() { if k.getClientset == nil { k.getClientset = defaultGetClientset } if k.getClientsetForPath == nil { k.getClientsetForPath = defaultGetClientsetForPath } if k.get == nil { k.get = defaultGet } if k.list == nil { k.list = defaultList } if k.del == nil { k.del = defaultDel } if k.create == nil { k.create = defaultCreate } if k.update == nil { k.update = defaultUpdate } } // WithClientSet sets the kubernetes client against // the kubeclient instance func WithClientSet(c *clientset.Clientset) KubeclientBuildOption { return func(k *Kubeclient) { k.clientset = c } } // WithNamespace sets the kubernetes client against // the provided namespace func WithNamespace(namespace string) KubeclientBuildOption { return func(k *Kubeclient) { k.namespace = namespace } } // WithNamespace sets the provided namespace // against this Kubeclient instance func (k *Kubeclient) WithNamespace(namespace string) *Kubeclient { k.namespace = namespace return k } // WithKubeConfigPath sets the kubernetes client // against the provided path func WithKubeConfigPath(path string) KubeclientBuildOption { return func(k *Kubeclient) { k.kubeConfigPath = path } } // NewKubeclient returns a new instance of // kubeclient meant for zfsrstr rstrume operations func NewKubeclient(opts ...KubeclientBuildOption) *Kubeclient { k := &Kubeclient{} for _, o := range opts { o(k) } k.withDefaults() return k } func (k *Kubeclient) getClientsetForPathOrDirect() ( *clientset.Clientset, error, ) { if k.kubeConfigPath != "" { return k.getClientsetForPath(k.kubeConfigPath) } return k.getClientset() } // getClientOrCached returns either a new instance // of kubernetes client or its cached copy func (k *Kubeclient) getClientOrCached() (*clientset.Clientset, error) { if k.clientset != nil { return k.clientset, nil } c, err := k.getClientsetForPathOrDirect() if err != nil { return nil, errors.Wrapf( err, "failed to get clientset", ) } k.clientset = c return k.clientset, nil } // Create creates a zfsrstr rstrume instance // in kubernetes cluster func (k *Kubeclient) Create(rstr *apis.ZFSRestore) (*apis.ZFSRestore, error) { if rstr == nil { return nil, errors.New( "failed to create csirstrume: nil rstr object", ) } cs, err := k.getClientOrCached() if err != nil { return nil, errors.Wrapf( err, "failed to create zfsrstr rstrume {%s} in namespace {%s}", rstr.Name, k.namespace, ) } return k.create(cs, rstr, k.namespace) } // Get returns zfsrstr rstrume object for given name func (k *Kubeclient) Get( name string, opts metav1.GetOptions, ) (*apis.ZFSRestore, error) { if name == "" { return nil, errors.New( "failed to get zfsrstr rstrume: missing zfsrstr rstrume name", ) } cli, err := k.getClientOrCached() if err != nil { return nil, errors.Wrapf( err, "failed to get zfsrstr rstrume {%s} in namespace {%s}", name, k.namespace, ) } return k.get(cli, name, k.namespace, opts) } // GetRaw returns zfsrstr rstrume instance // in bytes func (k *Kubeclient) GetRaw( name string, opts metav1.GetOptions, ) ([]byte, error) { if name == "" { return nil, errors.New( "failed to get raw zfsrstr rstrume: missing rstr name", ) } csiv, err := k.Get(name, opts) if err != nil { return nil, errors.Wrapf( err, "failed to get zfsrstr rstrume {%s} in namespace {%s}", name, k.namespace, ) } return json.Marshal(csiv) } // List returns a list of zfsrstr rstrume // instances present in kubernetes cluster func (k *Kubeclient) List(opts metav1.ListOptions) (*apis.ZFSRestoreList, error) { cli, err := k.getClientOrCached() if err != nil { return nil, errors.Wrapf( err, "failed to list zfsrstr rstrumes in namespace {%s}", k.namespace, ) } return k.list(cli, k.namespace, opts) } // Delete deletes the zfsrstr rstrume from // kubernetes func (k *Kubeclient) Delete(name string) error { if name == "" { return errors.New( "failed to delete csirstrume: missing rstr name", ) } cli, err := k.getClientOrCached() if err != nil { return errors.Wrapf( err, "failed to delete csirstrume {%s} in namespace {%s}", name, k.namespace, ) } return k.del(cli, name, k.namespace, &metav1.DeleteOptions{}) } // Update updates this zfsrstr rstrume instance // against kubernetes cluster func (k *Kubeclient) Update(rstr *apis.ZFSRestore) (*apis.ZFSRestore, error) { if rstr == nil { return nil, errors.New( "failed to update csirstrume: nil rstr object", ) } cs, err := k.getClientOrCached() if err != nil { return nil, errors.Wrapf( err, "failed to update csirstrume {%s} in namespace {%s}", rstr.Name, rstr.Namespace, ) } return k.update(cs, rstr, k.namespace) }