diff --git a/go.mod b/go.mod index ecc21dba..b7b7767c 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/minio/minio-go/v7 v7.0.88 github.com/nats-io/nats.go v1.43.0 github.com/pkg/errors v0.9.1 + github.com/redis/go-redis/v9 v9.11.0 github.com/sethvargo/go-envconfig v1.3.0 github.com/stretchr/testify v1.10.0 go.uber.org/zap v1.27.0 @@ -22,6 +23,7 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/aws/smithy-go v1.22.3 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-ini/ini v1.67.0 // indirect diff --git a/go.sum b/go.sum index 928efec7..d009a4b4 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,10 @@ github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k= github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/cert-manager/cert-manager v1.17.1 h1:Aig+lWMoLsmpGd9TOlTvO4t0Ah3D+/vGB37x/f+ZKt0= github.com/cert-manager/cert-manager v1.17.1/go.mod h1:zeG4D+AdzqA7hFMNpYCJgcQ2VOfFNBa+Jzm3kAwiDU4= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -14,6 +18,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= @@ -117,6 +123,8 @@ github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/redis/go-redis/v9 v9.11.0 h1:E3S08Gl/nJNn5vkxd2i78wZxWAPNZgUNTp8WIJUAiIs= +github.com/redis/go-redis/v9 v9.11.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= diff --git a/internal/controller/store_status.go b/internal/controller/store_status.go index d9b8a249..33a49fde 100644 --- a/internal/controller/store_status.go +++ b/internal/controller/store_status.go @@ -66,6 +66,13 @@ func (r *StoreReconciler) reconcileCRStatus( if !store.Spec.DisableS3Check && store.Spec.S3Storage.AccessKeyRef.Key != "" { store.Status.State = r.checkS3Services(ctx, store) } + + if store.Spec.AppCache.Adapter == "redis" { + store.Status.State = r.checkRedisServices(ctx, store) + } else if store.Spec.AppCache.Adapter == "builtin" && store.Spec.Container.Replicas > 1 { + //confirm if we should fail or just log a warning + log.FromContext(ctx).Info("Redis is not configured but the replicas are greater than 1. This can cause problems.") + } } if store.IsState(v1.StateSetup) { @@ -261,6 +268,37 @@ func (r *StoreReconciler) checkS3Services( return v1.StateSetup } +func (r *StoreReconciler) checkRedisServices( + ctx context.Context, + store *v1.Store, +) v1.StatefulAppState { + redisSpec := store.Spec.AppCache.RedisSpec + con := v1.StoreCondition{ + Type: v1.StateWait, + LastTransitionTime: metav1.Time{}, + LastUpdateTime: metav1.Now(), + Message: "Waiting for Redis connection", + Reason: "", + Status: "True", + } + defer func() { + store.Status.AddCondition(con) + }() + + // Test Redis connection + err := util.TestRedisConnection(ctx, redisSpec.RedisHost, redisSpec.RedisPort, "", redisSpec.RedisIndex) + if err != nil { + con.Reason = err.Error() + con.Status = Error + return v1.StateWait + } + + con.LastTransitionTime = metav1.Now() + con.Status = Ready + con.Reason = "Redis connection test passed" + return v1.StateSetup +} + func (r *StoreReconciler) stateSetup(ctx context.Context, store *v1.Store) v1.StatefulAppState { con := v1.StoreCondition{ Type: v1.StateSetup, diff --git a/internal/util/redis.go b/internal/util/redis.go new file mode 100644 index 00000000..d2eacbfb --- /dev/null +++ b/internal/util/redis.go @@ -0,0 +1,34 @@ +package util + +import ( + "context" + "fmt" + "time" + + "github.com/redis/go-redis/v9" +) + +func GenerateRedisURL(host string, port int, password string, db int) string { + if password != "" { + return fmt.Sprintf("redis://:%s@%s:%d/%d", password, host, port, db) + } + return fmt.Sprintf("redis://%s:%d/%d", host, port, db) +} + +func TestRedisConnection(ctx context.Context, host string, port int, password string, db int) error { + client := redis.NewClient(&redis.Options{ + Addr: fmt.Sprintf("%s:%d", host, port), + Password: password, + DB: db, + }) + + ctx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + + _, err := client.Ping(ctx).Result() + if err != nil { + return fmt.Errorf("failed to connect to Redis: %w", err) + } + + return nil +}