redis_storage.go 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. package remotecache
  2. import (
  3. "fmt"
  4. "strconv"
  5. "strings"
  6. "time"
  7. "github.com/grafana/grafana/pkg/setting"
  8. "github.com/grafana/grafana/pkg/util/errutil"
  9. redis "gopkg.in/redis.v2"
  10. )
  11. const redisCacheType = "redis"
  12. type redisStorage struct {
  13. c *redis.Client
  14. }
  15. // parseRedisConnStr parses k=v pairs in csv and builds a redis Options object
  16. func parseRedisConnStr(connStr string) (*redis.Options, error) {
  17. keyValueCSV := strings.Split(connStr, ",")
  18. options := &redis.Options{Network: "tcp"}
  19. for _, rawKeyValue := range keyValueCSV {
  20. keyValueTuple := strings.SplitN(rawKeyValue, "=", 2)
  21. if len(keyValueTuple) != 2 {
  22. if strings.HasPrefix(rawKeyValue, "password") {
  23. // don't log the password
  24. rawKeyValue = "password******"
  25. }
  26. return nil, fmt.Errorf("incorrect redis connection string format detected for '%v', format is key=value,key=value", rawKeyValue)
  27. }
  28. connKey := keyValueTuple[0]
  29. connVal := keyValueTuple[1]
  30. switch connKey {
  31. case "addr":
  32. options.Addr = connVal
  33. case "password":
  34. options.Password = connVal
  35. case "db":
  36. i, err := strconv.ParseInt(connVal, 10, 64)
  37. if err != nil {
  38. return nil, errutil.Wrap("value for db in redis connection string must be a number", err)
  39. }
  40. options.DB = i
  41. case "pool_size":
  42. i, err := strconv.Atoi(connVal)
  43. if err != nil {
  44. return nil, errutil.Wrap("value for pool_size in redis connection string must be a number", err)
  45. }
  46. options.PoolSize = i
  47. default:
  48. return nil, fmt.Errorf("unrecorgnized option '%v' in redis connection string", connVal)
  49. }
  50. }
  51. return options, nil
  52. }
  53. func newRedisStorage(opts *setting.RemoteCacheOptions) (*redisStorage, error) {
  54. opt, err := parseRedisConnStr(opts.ConnStr)
  55. if err != nil {
  56. return nil, err
  57. }
  58. return &redisStorage{c: redis.NewClient(opt)}, nil
  59. }
  60. // Set sets value to given key in session.
  61. func (s *redisStorage) Set(key string, val interface{}, expires time.Duration) error {
  62. item := &cachedItem{Val: val}
  63. value, err := encodeGob(item)
  64. if err != nil {
  65. return err
  66. }
  67. status := s.c.SetEx(key, expires, string(value))
  68. return status.Err()
  69. }
  70. // Get gets value by given key in session.
  71. func (s *redisStorage) Get(key string) (interface{}, error) {
  72. v := s.c.Get(key)
  73. item := &cachedItem{}
  74. err := decodeGob([]byte(v.Val()), item)
  75. if err == nil {
  76. return item.Val, nil
  77. }
  78. if err.Error() == "EOF" {
  79. return nil, ErrCacheItemNotFound
  80. }
  81. return nil, err
  82. }
  83. // Delete delete a key from session.
  84. func (s *redisStorage) Delete(key string) error {
  85. cmd := s.c.Del(key)
  86. return cmd.Err()
  87. }