supabase-operator/internal/controller/utils.go
Peter Kurfer 647f602c79
Some checks failed
Lint / Run on Ubuntu (push) Failing after 2m58s
E2E Tests / Run on Ubuntu (push) Failing after 4m18s
Tests / Run on Ubuntu (push) Failing after 2m39s
feat: basic functionality implemented
- added Core CRD to manage DB migrations & configuration, PostgREST and
  GoTrue (auth)
- added APIGateway CRD to manage Envoy proxy
- added Dashboard CRD to manage (so far) pg-meta and (soon) studio
  deployments
- implemented basic Envoy control plane based on K8s watcher
2025-01-04 17:07:49 +01:00

145 lines
3.1 KiB
Go

package controller
import (
"context"
"crypto/sha256"
"errors"
"io"
"maps"
"reflect"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"code.icb4dc0.de/prskr/supabase-operator/api"
)
func Close(closer io.Closer, err *error) {
*err = errors.Join(*err, closer.Close())
}
func CloseCtx(ctx context.Context, closable interface {
Close(ctx context.Context) error
}, err *error,
) {
*err = errors.Join(*err, closable.Close(ctx))
}
func ptrOf[T any](val T) *T {
return &val
}
func boolValueOf(ptr *bool) bool {
if ptr == nil {
return false
}
return *ptr
}
func MergeLabels(source map[string]string, toAppend ...map[string]string) map[string]string {
result := make(map[string]string, len(source)+len(toAppend))
maps.Copy(result, source)
for _, additionalLabels := range toAppend {
for k, v := range additionalLabels {
if _, exists := result[k]; exists {
continue
}
result[k] = v
}
}
return result
}
func MergeEnv(source []corev1.EnvVar, toAppend ...corev1.EnvVar) []corev1.EnvVar {
existingKeys := make(map[string]bool, len(source)+len(toAppend))
merged := append(make([]corev1.EnvVar, 0, len(source)+len(toAppend)), source...)
for _, v := range source {
existingKeys[v.Name] = true
}
for _, v := range toAppend {
if _, alreadyPresent := existingKeys[v.Name]; alreadyPresent {
continue
}
merged = append(merged, v)
existingKeys[v.Name] = true
}
return merged
}
func ValueOrFallback[T any](value, fallback T) T {
rval := reflect.ValueOf(value)
if rval.IsZero() {
return fallback
}
return value
}
func HashStrings(vals ...string) []byte {
h := sha256.New()
for _, v := range vals {
h.Write([]byte(v))
}
return h.Sum(nil)
}
func HashBytes(vals ...[]byte) []byte {
h := sha256.New()
for _, v := range vals {
h.Write(v)
}
return h.Sum(nil)
}
func FieldSelectorEventHandler[TItem metav1.Object, TList api.ObjectList[TItem]](
cli client.Client,
fieldSelector string,
) handler.TypedEventHandler[client.Object, reconcile.Request] {
return handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request {
var (
list TList
selectorInstance = client.MatchingFieldsSelector{
Selector: fields.OneTermEqualSelector(fieldSelector, obj.GetName()),
}
logger = log.FromContext(ctx, "object", obj.GetName(), "namespace", obj.GetNamespace())
)
list = reflect.New(reflect.TypeOf(list).Elem()).Interface().(TList)
if err := cli.List(ctx, list, selectorInstance, client.InNamespace(obj.GetNamespace())); err != nil {
logger.Error(err, "could not list items for field selector event handler")
return nil
}
requests := make([]reconcile.Request, 0)
for item := range list.Iter() {
requests = append(requests, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: item.GetName(),
Namespace: obj.GetNamespace(),
},
})
}
return requests
})
}