You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
3.4 KiB

  1. /*
  2. * Minio Cloud Storage, (C) 2016 Minio, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package cmd
  17. import (
  18. "io/ioutil"
  19. "time"
  20. "github.com/Sirupsen/logrus"
  21. "github.com/garyburd/redigo/redis"
  22. )
  23. // redisNotify to send logs to Redis server
  24. type redisNotify struct {
  25. Enable bool `json:"enable"`
  26. Addr string `json:"address"`
  27. Password string `json:"password"`
  28. Key string `json:"key"`
  29. }
  30. func (r *redisNotify) Validate() error {
  31. if !r.Enable {
  32. return nil
  33. }
  34. if _, err := checkURL(r.Addr); err != nil {
  35. return err
  36. }
  37. return nil
  38. }
  39. type redisConn struct {
  40. *redis.Pool
  41. params redisNotify
  42. }
  43. // Dial a new connection to redis instance at addr, optionally with a
  44. // password if any.
  45. func dialRedis(rNotify redisNotify) (*redis.Pool, error) {
  46. // Return error if redis not enabled.
  47. if !rNotify.Enable {
  48. return nil, errNotifyNotEnabled
  49. }
  50. addr := rNotify.Addr
  51. password := rNotify.Password
  52. rPool := &redis.Pool{
  53. MaxIdle: 3,
  54. IdleTimeout: 240 * time.Second, // Time 2minutes.
  55. Dial: func() (redis.Conn, error) {
  56. c, err := redis.Dial("tcp", addr)
  57. if err != nil {
  58. return nil, err
  59. }
  60. if password != "" {
  61. if _, derr := c.Do("AUTH", password); derr != nil {
  62. c.Close()
  63. return nil, derr
  64. }
  65. }
  66. return c, err
  67. },
  68. TestOnBorrow: func(c redis.Conn, t time.Time) error {
  69. _, err := c.Do("PING")
  70. return err
  71. },
  72. }
  73. // Test if connection with REDIS can be established.
  74. rConn := rPool.Get()
  75. defer rConn.Close()
  76. // Check connection.
  77. _, err := rConn.Do("PING")
  78. if err != nil {
  79. return nil, err
  80. }
  81. // Return pool.
  82. return rPool, nil
  83. }
  84. func newRedisNotify(accountID string) (*logrus.Logger, error) {
  85. rNotify := serverConfig.Notify.GetRedisByID(accountID)
  86. // Dial redis.
  87. rPool, err := dialRedis(rNotify)
  88. if err != nil {
  89. return nil, err
  90. }
  91. rrConn := redisConn{
  92. Pool: rPool,
  93. params: rNotify,
  94. }
  95. redisLog := logrus.New()
  96. redisLog.Out = ioutil.Discard
  97. // Set default JSON formatter.
  98. redisLog.Formatter = new(logrus.JSONFormatter)
  99. redisLog.Hooks.Add(rrConn)
  100. // Success, redis enabled.
  101. return redisLog, nil
  102. }
  103. // Fire is called when an event should be sent to the message broker.
  104. func (r redisConn) Fire(entry *logrus.Entry) error {
  105. rConn := r.Pool.Get()
  106. defer rConn.Close()
  107. // Fetch event type upon reflecting on its original type.
  108. entryStr, ok := entry.Data["EventType"].(string)
  109. if !ok {
  110. return nil
  111. }
  112. // Match the event if its a delete request, attempt to delete the key
  113. if eventMatch(entryStr, []string{"s3:ObjectRemoved:*"}) {
  114. if _, err := rConn.Do("DEL", entry.Data["Key"]); err != nil {
  115. return err
  116. }
  117. return nil
  118. } // else save this as new entry or update any existing ones.
  119. if _, err := rConn.Do("SET", entry.Data["Key"], map[string]interface{}{
  120. "Records": entry.Data["Records"],
  121. }); err != nil {
  122. return err
  123. }
  124. return nil
  125. }
  126. // Required for logrus hook implementation
  127. func (r redisConn) Levels() []logrus.Level {
  128. return []logrus.Level{
  129. logrus.InfoLevel,
  130. }
  131. }