func B64Decode(s *core.Secret, key string) (string, error) {
	decoded, err := b64.StdEncoding.DecodeString(string(s.Data[key]))
	if err != nil {
		return "", err
	}
	return string(decoded), nil
}
B64Decode decodes the provided secret
package utils
import (
	"context"
	b64 "encoding/base64"
	"fmt"
	"io/ioutil"
	"math/rand"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"time"
	"github.com/RedHatInsights/clowder/controllers/cloud.redhat.com/errors"
	obj "github.com/RedHatInsights/clowder/controllers/cloud.redhat.com/object"
	"github.com/go-logr/logr"
	core "k8s.io/api/core/v1"
	k8serr "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
	"sigs.k8s.io/controller-runtime/pkg/client"
	ctrllog "sigs.k8s.io/controller-runtime/pkg/log"
)
const rCharSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
const lCharSet = "abcdefghijklmnopqrstuvwxyz0123456789"
func init() {
	rand.Seed(time.Now().UnixNano())
}
var Log logr.Logger = ctrllog.NullLogger{}
func RandString(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = rCharSet[rand.Intn(len(rCharSet))]
	}
	return string(b)
}
func RandStringLower(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = lCharSet[rand.Intn(len(lCharSet))]
	}
	return string(b)
}
type Updater bool
func (u *Updater) Apply(ctx context.Context, cl client.Client, obj client.Object) error {
	var err error
	var kind string
	if obj.GetObjectKind().GroupVersionKind().Kind == "" {
		kind = reflect.TypeOf(obj).String()
	} else {
		kind = obj.GetObjectKind().GroupVersionKind().Kind
	}
	meta := obj.(metav1.Object)
	if *u {
		err = cl.Update(ctx, obj)
	} else {
		if meta.GetName() == "" {
			Log.Info("Skipping resource as name unknown", "kind", kind)
			return nil
		}
		err = cl.Create(ctx, obj)
	}
	if err != nil {
		verb := "creating"
		if *u {
			verb = "updating"
		}
		msg := fmt.Sprintf("Error %s resource %s %s", verb, kind, meta.GetName())
		return errors.Wrap(msg, err)
	}
	return nil
}
func UpdateOrErr(err error) (Updater, error) {
	update := Updater(err == nil)
	if err != nil && !k8serr.IsNotFound(err) {
		return update, errors.Wrap("Failed to update", err)
	}
	return update, nil
}
func UpdateAllOrErr(ctx context.Context, cl client.Client, nn types.NamespacedName, obj ...client.Object) (map[client.Object]Updater, error) {
	updates := map[client.Object]Updater{}
	for _, resource := range obj {
		update, err := UpdateOrErr(cl.Get(ctx, nn, resource))
		if err != nil {
			return updates, err
		}
		updates[resource] = update
	}
	return updates, nil
}
func ApplyAll(ctx context.Context, cl client.Client, updates map[client.Object]Updater) error {
	for resource, update := range updates {
		if err := update.Apply(ctx, cl, resource); err != nil {
			return err
		}
	}
	return nil
}