func (r *Resources) Patch(ctx context.Context, objs k8s.Object, patch k8s.Patch, opts ...PatchOption) error {
	patchOptions := &metav1.PatchOptions{}
	for _, fn := range opts {
		fn(patchOptions)
	}
	p := cr.RawPatch(patch.PatchType, patch.Data)
	o := &cr.PatchOptions{Raw: patchOptions}
	return r.client.Patch(ctx, objs, p, o)
}
Patch patches portion of object `orig` with data from object `patch`
package resources
import (
	"context"
	"errors"
	"log"
	"time"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/rest"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes/scheme"
	cr "sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/e2e-framework/klient/k8s"
)
type Resources struct {
	config *rest.Config
	scheme *runtime.Scheme
	client cr.Client
	namespace string
}
func New(cfg *rest.Config) (*Resources, error) {
	if cfg == nil {
		log.Println("must provide rest.Config")
		return nil, errors.New("must provide rest.Config")
	}
	cl, err := cr.New(cfg, cr.Options{Scheme: scheme.Scheme})
	if err != nil {
		log.Println("unexpected error creating client using provided config and client options", err)
		return nil, err
	}
	res := &Resources{
		config: cfg,
		scheme: scheme.Scheme,
		client: cl,
	}
	return res, nil
}
func (r *Resources) WithNamespace(ns string) *Resources {
	r.namespace = ns
	return r
}
func (r *Resources) Get(ctx context.Context, name, namespace string, obj k8s.Object) error {
	return r.client.Get(ctx, cr.ObjectKey{Namespace: namespace, Name: name}, obj)
}
type CreateOption func(*metav1.CreateOptions)
func (r *Resources) Create(ctx context.Context, obj k8s.Object, opts ...CreateOption) error {
	createOptions := &metav1.CreateOptions{}
	for _, fn := range opts {
		fn(createOptions)
	}
	o := &cr.CreateOptions{Raw: createOptions}
	return r.client.Create(ctx, obj, o)
}
type UpdateOption func(*metav1.UpdateOptions)
func (r *Resources) Update(ctx context.Context, obj k8s.Object, opts ...UpdateOption) error {
	updateOptions := &metav1.UpdateOptions{}
	for _, fn := range opts {
		fn(updateOptions)
	}
	o := &cr.UpdateOptions{Raw: updateOptions}
	return r.client.Update(ctx, obj, o)
}
type DeleteOption func(*metav1.DeleteOptions)
func (r *Resources) Delete(ctx context.Context, obj k8s.Object, opts ...DeleteOption) error {
	deleteOptions := &metav1.DeleteOptions{}
	for _, fn := range opts {
		fn(deleteOptions)
	}
	o := &cr.DeleteOptions{Raw: deleteOptions}
	return r.client.Delete(ctx, obj, o)
}
func WithGracePeriod(gpt time.Duration) DeleteOption {
	t := gpt.Milliseconds()
	return func(do *metav1.DeleteOptions) { do.GracePeriodSeconds = &t }
}
func WithDeletePropagation(prop string) DeleteOption {
	p := metav1.DeletionPropagation(prop)
	return func(do *metav1.DeleteOptions) { do.PropagationPolicy = &p }
}
type ListOption func(*metav1.ListOptions)
func (r *Resources) List(ctx context.Context, objs k8s.ObjectList, opts ...ListOption) error {
	listOptions := &metav1.ListOptions{}
	for _, fn := range opts {
		fn(listOptions)
	}
	o := &cr.ListOptions{Raw: listOptions}
	if r.namespace != "" {
		o.Namespace = r.namespace
	}
	return r.client.List(ctx, objs, o)
}
func WithLabelSelector(sel string) ListOption {
	return func(lo *metav1.ListOptions) { lo.LabelSelector = sel }
}
func WithFieldSelector(sel string) ListOption {
	return func(lo *metav1.ListOptions) { lo.FieldSelector = sel }
}
func WithTimeout(to time.Duration) ListOption {
	t := to.Milliseconds()
	return func(lo *metav1.ListOptions) { lo.TimeoutSeconds = &t }
}
type PatchOption func(*metav1.PatchOptions)