Skip to content

Commit

Permalink
feat(provider): redisfailover (sentinel) implementation (#2)
Browse files Browse the repository at this point in the history
* feat(redis): implement username option (#36)

Allows defining of the username to accompany the password.

* Upgrade dependencies

* Upgrade fasthttp to v1.20.0

* Upgrade fasthttp to v1.21.0 and other dependencies

* Add support to Go v1.16.X

* feat(provider): add redis failover provider (sentinel)

Co-authored-by: Sergio Andres Virviescas Santana <[email protected]>
  • Loading branch information
james-d-elliott and Sergio Andres Virviescas Santana authored Feb 26, 2021
1 parent 5ce5eab commit 16d1a8d
Show file tree
Hide file tree
Showing 9 changed files with 273 additions and 10 deletions.
Empty file added .travis.yml
Empty file.
2 changes: 1 addition & 1 deletion _examples/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import (
"log"
"time"

"github.com/fasthttp/router"
"github.com/authelia/session/v2"
"github.com/authelia/session/v2/providers/memcache"
"github.com/authelia/session/v2/providers/memory"
"github.com/authelia/session/v2/providers/mysql"
"github.com/authelia/session/v2/providers/postgre"
"github.com/authelia/session/v2/providers/redis"
"github.com/authelia/session/v2/providers/sqlite3"
"github.com/fasthttp/router"
"github.com/valyala/fasthttp"
)

Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ require (
github.com/go-sql-driver/mysql v1.5.0
github.com/lib/pq v1.9.0
github.com/mattn/go-sqlite3 v1.14.6
github.com/savsgio/dictpool v0.0.0-20210105101557-9da1bc2fbfce
github.com/savsgio/gotils v0.0.0-20210105085219-0567298fdcac
github.com/savsgio/dictpool v0.0.0-20210217113430-85d3b37fb239
github.com/savsgio/gotils v0.0.0-20210217112953-d4a072536008
github.com/valyala/bytebufferpool v1.0.0
github.com/valyala/fasthttp v1.19.0
github.com/valyala/fasthttp v1.21.0
)
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ github.com/philhofer/fwd v1.1.1 h1:GdGcTjf5RNAxwS4QLsiMzJYj5KEvPJD3Abr261yRQXQ=
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/savsgio/dictpool v0.0.0-20210105101557-9da1bc2fbfce h1:PRDREQ3VGiocUySEdKYQpwdyxDx+e4uKdjVaQvwIR5I=
github.com/savsgio/dictpool v0.0.0-20210105101557-9da1bc2fbfce/go.mod h1:TNr2IIMnYd9/KYEpTVHVrnfmjizlKPTSgkWUbjyof+A=
github.com/savsgio/gotils v0.0.0-20210105085219-0567298fdcac h1:5pr1F6tcjeIKPKlrQZW6hzB0WxZge7SkkYVGG/e5pLY=
github.com/savsgio/gotils v0.0.0-20210105085219-0567298fdcac/go.mod h1:TWNAOTaVzGOXq8RbEvHnhzA/A2sLZzgn0m6URjnukY8=
github.com/savsgio/dictpool v0.0.0-20210217113430-85d3b37fb239 h1:aTxmMsYGLUZfj0EsWaJ1s0HnctxCgjRw3A+TFoO1Tsc=
github.com/savsgio/dictpool v0.0.0-20210217113430-85d3b37fb239/go.mod h1:CfPSewBwpXF/05Izyk9s379O1ysmtUajFVr1nOD83Fs=
github.com/savsgio/gotils v0.0.0-20210217112953-d4a072536008 h1:GfiZ0x43l1tOeyam9RAlJaUkxPwGRz3bIbmtyfTZIWY=
github.com/savsgio/gotils v0.0.0-20210217112953-d4a072536008/go.mod h1:TWNAOTaVzGOXq8RbEvHnhzA/A2sLZzgn0m6URjnukY8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
Expand All @@ -61,8 +61,8 @@ github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk1
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.19.0 h1:PfTS4PeH3xDr3WomrDS2ID8lU2GskK1xS3YG6gIpibU=
github.com/valyala/fasthttp v1.19.0/go.mod h1:jjraHZVbKOXftJfsOYoAjaeygpj5hr8ermTRJNroD7A=
github.com/valyala/fasthttp v1.21.0 h1:fJjaQ7cXdaSF9vDBujlHLDGj7AgoMTMIXvICeePzYbU=
github.com/valyala/fasthttp v1.21.0/go.mod h1:jjraHZVbKOXftJfsOYoAjaeygpj5hr8ermTRJNroD7A=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/otel v0.13.0 h1:2isEnyzjjJZq6r2EKMsFj4TxiQiexsM04AVhwbR/oBA=
Expand Down
1 change: 1 addition & 0 deletions providers/memory/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package memory
import (
"sync"
"time"

"github.com/authelia/session/v2"
"github.com/savsgio/gotils/strconv"
)
Expand Down
8 changes: 8 additions & 0 deletions providers/redisfailover/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Redis Fail Over

Redis Fail Over (Sentinel) provider implementation.

Better encoder:

- Encode: `session.MSGPEncode`
- Decode: `session.MSGPDecode`
12 changes: 12 additions & 0 deletions providers/redisfailover/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package redisfailover

import (
"errors"
"fmt"
)

var errConfigMasterNameEmpty = errors.New("Config MasterName must not be empty")

func errRedisConnection(err error) error {
return fmt.Errorf("Redis connection error: %v", err)
}
137 changes: 137 additions & 0 deletions providers/redisfailover/provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package redisfailover

import (
"context"
"time"

"github.com/go-redis/redis/v8"
"github.com/valyala/bytebufferpool"
)

var all = []byte("*")

// New returns a new configured redis provider
func New(cfg Config) (*Provider, error) {
if cfg.MasterName == "" {
return nil, errConfigMasterNameEmpty
}

db := redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: cfg.MasterName,
SentinelAddrs: cfg.SentinelAddrs,
RouteByLatency: cfg.RouteByLatency,
RouteRandomly: cfg.RouteRandomly,
SlaveOnly: cfg.SlaveOnly,
Username: cfg.Username,
Password: cfg.Password,
DB: cfg.DB,
MaxRetries: cfg.MaxRetries,
MinRetryBackoff: cfg.MinRetryBackoff,
MaxRetryBackoff: cfg.MaxRetryBackoff,
DialTimeout: cfg.DialTimeout,
ReadTimeout: cfg.ReadTimeout,
WriteTimeout: cfg.WriteTimeout,
PoolSize: cfg.PoolSize,
MinIdleConns: cfg.MinIdleConns,
MaxConnAge: cfg.MaxConnAge,
PoolTimeout: cfg.PoolTimeout,
IdleTimeout: cfg.IdleTimeout,
IdleCheckFrequency: cfg.IdleCheckFrequency,
TLSConfig: cfg.TLSConfig,
})

if err := db.Ping(context.Background()).Err(); err != nil {
return nil, errRedisConnection(err)
}

p := &Provider{
config: cfg,
db: db,
}

return p, nil
}

func (p *Provider) getRedisSessionKey(sessionID []byte) string {
key := bytebufferpool.Get()
key.SetString(p.config.KeyPrefix)
key.WriteString(":")
key.Write(sessionID)

keyStr := key.String()

bytebufferpool.Put(key)

return keyStr
}

// Get returns the data of the given session id
func (p *Provider) Get(id []byte) ([]byte, error) {
key := p.getRedisSessionKey(id)

reply, err := p.db.Get(context.Background(), key).Bytes()
if err != nil && err != redis.Nil {
return nil, err
}

return reply, nil

}

// Save saves the session data and expiration from the given session id
func (p *Provider) Save(id, data []byte, expiration time.Duration) error {
key := p.getRedisSessionKey(id)

return p.db.Set(context.Background(), key, data, expiration).Err()
}

// Regenerate updates the session id and expiration with the new session id
// of the the given current session id
func (p *Provider) Regenerate(id, newID []byte, expiration time.Duration) error {
key := p.getRedisSessionKey(id)
newKey := p.getRedisSessionKey(newID)

exists, err := p.db.Exists(context.Background(), key).Result()
if err != nil {
return err
}

if exists > 0 { // Exist
if err = p.db.Rename(context.Background(), key, newKey).Err(); err != nil {
return err
}

if err = p.db.Expire(context.Background(), newKey, expiration).Err(); err != nil {
return err
}
}

return nil
}

// Destroy destroys the session from the given id
func (p *Provider) Destroy(id []byte) error {
key := p.getRedisSessionKey(id)

return p.db.Del(context.Background(), key).Err()
}

// Count returns the total of stored sessions
func (p *Provider) Count() int {
reply, err := p.db.Keys(context.Background(), p.getRedisSessionKey(all)).Result()
if err != nil {
return 0
}

return len(reply)
}

// NeedGC indicates if the GC needs to be run
func (p *Provider) NeedGC() bool {
return false
}

// GC destroys the expired sessions
func (p *Provider) GC() error {
return nil
}
105 changes: 105 additions & 0 deletions providers/redisfailover/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package redisfailover

import (
"crypto/tls"
"time"

"github.com/go-redis/redis/v8"
)

// Config provider settings
type Config struct {
// Key prefix
KeyPrefix string

// The sentinel master name.
MasterName string

// The sentinel nodes seed list (host:port).
SentinelAddrs []string

// The password for the sentinel connection if required (different to username/password).
SentinelPassword string

// Routes read-only commands to the closest node.
RouteByLatency bool

// Routes read-only commands in random order.
RouteRandomly bool

// Route read-only commands to slave nodes.
SlaveOnly bool

// Optional username.
Username string

// Optional password. Must match the password specified in the
// requirepass server configuration option.
Password string

// Database to be selected after connecting to the server.
DB int

// Maximum number of retries before giving up.
// Default is to not retry failed commands.
MaxRetries int

// Minimum backoff between each retry.
// Default is 8 milliseconds; -1 disables backoff.
MinRetryBackoff time.Duration

// Maximum backoff between each retry.
// Default is 512 milliseconds; -1 disables backoff.
MaxRetryBackoff time.Duration

// Dial timeout for establishing new connections.
// Default is 5 seconds.
DialTimeout time.Duration

// Timeout for socket reads. If reached, commands will fail
// with a timeout instead of blocking. Use value -1 for no timeout and 0 for default.
// Default is 3 seconds.
ReadTimeout time.Duration

// Timeout for socket writes. If reached, commands will fail
// with a timeout instead of blocking.
// Default is ReadTimeout.
WriteTimeout time.Duration

// Maximum number of socket connections.
// Default is 10 connections per every CPU as reported by runtime.NumCPU.
PoolSize int

// Minimum number of idle connections which is useful when establishing
// new connection is slow.
MinIdleConns int

// Connection age at which client retires (closes) the connection.
// Default is to not close aged connections.
MaxConnAge time.Duration

// Amount of time client waits for connection if all connections
// are busy before returning an error.
// Default is ReadTimeout + 1 second.
PoolTimeout time.Duration

// Amount of time after which client closes idle connections.
// Should be less than server's timeout.
// Default is 5 minutes. -1 disables idle timeout check.
IdleTimeout time.Duration

// Frequency of idle checks made by idle connections reaper.
// Default is 1 minute. -1 disables idle connections reaper,
// but idle connections are still discarded by the client
// if IdleTimeout is set.
IdleCheckFrequency time.Duration

// TLS Config to use. When set TLS will be negotiated.
TLSConfig *tls.Config
}

// Provider backend manager
type Provider struct {
config Config
db *redis.Client
}

0 comments on commit 16d1a8d

Please sign in to comment.