Skip to content
Snippets Groups Projects
Commit d246f592 authored by Oliver's avatar Oliver
Browse files

add redis cluster to test setup

parent 09e179cd
No related branches found
No related tags found
No related merge requests found
Loading
@@ -6,10 +6,11 @@ machine:
Loading
@@ -6,10 +6,11 @@ machine:
- /usr/bin/redis-server --port 6380: - /usr/bin/redis-server --port 6380:
background: true background: true
environment: environment:
SRC_LOCATION: "/home/ubuntu/.go_workspace/src/github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME" SRC_LOCATION: "/home/ubuntu/.go_workspace/src/github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME"
COVERAGE_PROFILE: "/home/ubuntu/coverage.out" COVERAGE_PROFILE: "/home/ubuntu/coverage.out"
GO_LDFLAGS: '-extldflags "-static" -X main.VERSION=$CIRCLE_TAG -X main.COMMIT_SHA1=$CIRCLE_SHA1 -X main.BUILD_DATE=$(date +%F-%T)' GO_LDFLAGS: '-extldflags "-static" -X main.VERSION=$CIRCLE_TAG -X main.COMMIT_SHA1=$CIRCLE_SHA1 -X main.BUILD_DATE=$(date +%F-%T)'
MY_GO_VERSION: "1.9.2" MY_GO_VERSION: "1.9.2"
REDIS_TEST_VERSION: "3.2.11"
   
dependencies: dependencies:
pre: pre:
Loading
@@ -17,16 +18,20 @@ dependencies:
Loading
@@ -17,16 +18,20 @@ dependencies:
- rm -rf /home/ubuntu/.go_project - rm -rf /home/ubuntu/.go_project
- sudo service redis-server stop - sudo service redis-server stop
- > - >
cd ~ && if [ ! -d "redis-3.2.10" ]; then cd ~ && if [ ! -d "redis-$REDIS_TEST_VERSION" ]; then
wget http://download.redis.io/releases/redis-3.2.10.tar.gz wget http://download.redis.io/releases/redis-$REDIS_TEST_VERSION.tar.gz
tar xzf redis-3.2.10.tar.gz tar xzf redis-$REDIS_TEST_VERSION.tar.gz
cd redis-3.2.10 && make; cd redis-$REDIS_TEST_VERSION && make;
fi fi
- cd ~/redis-3.2.10 && sudo make install - cd ~/redis-$REDIS_TEST_VERSION && sudo make install
- sudo sed -i 's/bin/local\/bin/g' /etc/init/redis-server.conf - sudo sed -i 's/bin/local\/bin/g' /etc/init/redis-server.conf
- sudo service redis-server start - sudo service redis-server start
#
# the next line will bring up a cluster of redis instances with slaves
# for addtl tests
- docker run -p 7000-7006:7000-7006 --name redis_cluster_test -d oliver006/redis_cluster_test
cache_directories: cache_directories:
- ~/redis-3.2.10 - ~/redis-$REDIS_TEST_VERSION
override: override:
- mkdir -p "/home/ubuntu/.go_workspace/src/github.com/$CIRCLE_PROJECT_USERNAME" - mkdir -p "/home/ubuntu/.go_workspace/src/github.com/$CIRCLE_PROJECT_USERNAME"
- ln -s $HOME/$CIRCLE_PROJECT_REPONAME $SRC_LOCATION - ln -s $HOME/$CIRCLE_PROJECT_REPONAME $SRC_LOCATION
Loading
Loading
Loading
@@ -570,6 +570,16 @@ func (e *Exporter) extractInfoMetrics(info, addr string, alias string, scrapes c
Loading
@@ -570,6 +570,16 @@ func (e *Exporter) extractInfoMetrics(info, addr string, alias string, scrapes c
return nil return nil
} }
   
func doRedisCmd(c redis.Conn, cmd string, args ...interface{}) (reply interface{}, err error) {
log.Debugf("c.Do() - running command: %s %s", cmd, args)
defer log.Debugf("c.Do() - done")
res, err := c.Do(cmd, args...)
if err != nil {
log.Debugf("c.Do() - err: %s", err)
}
return res, err
}
func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx int) error { func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx int) error {
options := []redis.DialOption{ options := []redis.DialOption{
redis.DialConnectTimeout(5 * time.Second), redis.DialConnectTimeout(5 * time.Second),
Loading
@@ -596,7 +606,7 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
Loading
@@ -596,7 +606,7 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
} }
   
if err != nil { if err != nil {
log.Printf("redis err: %s", err) log.Debugf("aborting for addr: %s - redis err: %s", addr, err)
return err return err
} }
   
Loading
@@ -615,7 +625,7 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
Loading
@@ -615,7 +625,7 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
log.Debugf("Redis CONFIG err: %s", err) log.Debugf("Redis CONFIG err: %s", err)
} }
   
info, err := redis.String(c.Do("INFO", "ALL")) info, err := redis.String(doRedisCmd(c, "INFO", "ALL"))
if err == nil { if err == nil {
e.extractInfoMetrics(info, addr, e.redis.Aliases[idx], scrapes, dbCount, true) e.extractInfoMetrics(info, addr, e.redis.Aliases[idx], scrapes, dbCount, true)
} else { } else {
Loading
@@ -623,8 +633,8 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
Loading
@@ -623,8 +633,8 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
return err return err
} }
   
if strings.Index(info, "cluster_enabled:1") != -1 { if strings.Contains(info, "cluster_enabled:1") {
info, err = redis.String(c.Do("CLUSTER", "INFO")) info, err = redis.String(doRedisCmd(c, "CLUSTER", "INFO"))
if err != nil { if err != nil {
log.Errorf("redis err: %s", err) log.Errorf("redis err: %s", err)
} else { } else {
Loading
@@ -632,7 +642,7 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
Loading
@@ -632,7 +642,7 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
} }
} }
   
if reply, err := c.Do("LATENCY", "LATEST"); err == nil { if reply, err := doRedisCmd(c, "LATENCY", "LATEST"); err == nil {
var eventName string var eventName string
var spikeLast, milliseconds, max int64 var spikeLast, milliseconds, max int64
if tempVal, _ := reply.([]interface{}); len(tempVal) > 0 { if tempVal, _ := reply.([]interface{}); len(tempVal) > 0 {
Loading
@@ -646,13 +656,14 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
Loading
@@ -646,13 +656,14 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
} }
} }
   
log.Debugf("e.keys: %#v", e.keys)
for _, k := range e.keys { for _, k := range e.keys {
if _, err := c.Do("SELECT", k.db); err != nil { if _, err := doRedisCmd(c, "SELECT", k.db); err != nil {
continue continue
} }
   
obtainedKeys := []string{} obtainedKeys := []string{}
if tempVal, err := redis.Strings(c.Do("KEYS", k.key)); err == nil && tempVal != nil { if tempVal, err := redis.Strings(doRedisCmd(c, "KEYS", k.key)); err == nil && tempVal != nil {
for _, tempKey := range tempVal { for _, tempKey := range tempVal {
log.Debugf("Append result: %s", tempKey) log.Debugf("Append result: %s", tempKey)
obtainedKeys = append(obtainedKeys, tempKey) obtainedKeys = append(obtainedKeys, tempKey)
Loading
@@ -662,7 +673,7 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
Loading
@@ -662,7 +673,7 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
for _, key := range obtainedKeys { for _, key := range obtainedKeys {
dbLabel := "db" + k.db dbLabel := "db" + k.db
keyLabel := key keyLabel := key
if tempVal, err := c.Do("GET", key); err == nil && tempVal != nil { if tempVal, err := doRedisCmd(c, "GET", key); err == nil && tempVal != nil {
if val, err := strconv.ParseFloat(fmt.Sprintf("%s", tempVal), 64); err == nil { if val, err := strconv.ParseFloat(fmt.Sprintf("%s", tempVal), 64); err == nil {
e.keyValues.WithLabelValues(addr, e.redis.Aliases[idx], dbLabel, keyLabel).Set(val) e.keyValues.WithLabelValues(addr, e.redis.Aliases[idx], dbLabel, keyLabel).Set(val)
} }
Loading
@@ -676,7 +687,7 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
Loading
@@ -676,7 +687,7 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
"PFCOUNT", "PFCOUNT",
"STRLEN", "STRLEN",
} { } {
if tempVal, err := c.Do(op, key); err == nil && tempVal != nil { if tempVal, err := doRedisCmd(c, op, key); err == nil && tempVal != nil {
e.keySizes.WithLabelValues(addr, e.redis.Aliases[idx], dbLabel, keyLabel).Set(float64(tempVal.(int64))) e.keySizes.WithLabelValues(addr, e.redis.Aliases[idx], dbLabel, keyLabel).Set(float64(tempVal.(int64)))
break break
} }
Loading
@@ -684,18 +695,18 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
Loading
@@ -684,18 +695,18 @@ func (e *Exporter) scrapeRedisHost(scrapes chan<- scrapeResult, addr string, idx
} }
} }
   
log.Debugf("scrapeRedisHost() done")
return nil return nil
} }
   
func (e *Exporter) scrape(scrapes chan<- scrapeResult) { func (e *Exporter) scrape(scrapes chan<- scrapeResult) {
defer close(scrapes) defer close(scrapes)
now := time.Now().UnixNano() now := time.Now().UnixNano()
e.totalScrapes.Inc() e.totalScrapes.Inc()
   
errorCount := 0 errorCount := 0
for idx, addr := range e.redis.Addrs { for idx, addr := range e.redis.Addrs {
var up float64 = 1 var up float64 = 1
if err := e.scrapeRedisHost(scrapes, addr, idx); err != nil { if err := e.scrapeRedisHost(scrapes, addr, idx); err != nil {
errorCount++ errorCount++
Loading
Loading
Loading
@@ -13,10 +13,10 @@ import (
Loading
@@ -13,10 +13,10 @@ import (
"flag" "flag"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"net/url" "net/url"
"os"
"strings" "strings"
"testing" "testing"
"time" "time"
Loading
@@ -25,6 +25,7 @@ import (
Loading
@@ -25,6 +25,7 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
dto "github.com/prometheus/client_model/go" dto "github.com/prometheus/client_model/go"
log "github.com/sirupsen/logrus"
) )
   
const ( const (
Loading
@@ -100,25 +101,21 @@ func resetLatency(t *testing.T, addr string) error {
Loading
@@ -100,25 +101,21 @@ func resetLatency(t *testing.T, addr string) error {
return nil return nil
} }
   
func getMetrics(t *testing.T) []byte { func downloadUrl(t *testing.T, url string) []byte {
url := TestServerURL + "/metrics" log.Debugf("downloadURL() %s", url)
log.Printf("Getting metrics from: %s", url)
resp, err := http.Get(url) resp, err := http.Get(url)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp.Body.Close() defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body) body, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
return body return body
} }
   
func TestLatencySpike(t *testing.T) { func TestLatencySpike(t *testing.T) {
e, _ := NewRedisExporter(defaultRedisHost, "test", "") e, _ := NewRedisExporter(defaultRedisHost, "test", "")
   
setupLatency(t, defaultRedisHost.Addrs[0]) setupLatency(t, defaultRedisHost.Addrs[0])
Loading
@@ -230,7 +227,6 @@ func deleteKeysFromDB(t *testing.T, addr string) error {
Loading
@@ -230,7 +227,6 @@ func deleteKeysFromDB(t *testing.T, addr string) error {
} }
   
c.Do("DEL", TestSetName) c.Do("DEL", TestSetName)
return nil return nil
} }
   
Loading
@@ -574,13 +570,16 @@ func TestCommandStats(t *testing.T) {
Loading
@@ -574,13 +570,16 @@ func TestCommandStats(t *testing.T) {
} }
   
func TestHTTPEndpoint(t *testing.T) { func TestHTTPEndpoint(t *testing.T) {
ts := httptest.NewServer(promhttp.Handler())
defer ts.Close()
e, _ := NewRedisExporter(defaultRedisHost, "test", dbNumStrFull+"="+url.QueryEscape(keys[0])) e, _ := NewRedisExporter(defaultRedisHost, "test", dbNumStrFull+"="+url.QueryEscape(keys[0]))
   
setupDBKeys(t, defaultRedisHost.Addrs[0]) setupDBKeys(t, defaultRedisHost.Addrs[0])
defer deleteKeysFromDB(t, defaultRedisHost.Addrs[0]) defer deleteKeysFromDB(t, defaultRedisHost.Addrs[0])
prometheus.Register(e) prometheus.Register(e)
   
body := getMetrics(t) body := downloadUrl(t, ts.URL+"/metrics")
   
tests := []string{ tests := []string{
// metrics // metrics
Loading
@@ -603,12 +602,10 @@ func TestHTTPEndpoint(t *testing.T) {
Loading
@@ -603,12 +602,10 @@ func TestHTTPEndpoint(t *testing.T) {
} }
   
func TestNonExistingHost(t *testing.T) { func TestNonExistingHost(t *testing.T) {
rr := RedisHost{Addrs: []string{"unix:///tmp/doesnt.exist"}, Aliases: []string{""}} rr := RedisHost{Addrs: []string{"unix:///tmp/doesnt.exist"}, Aliases: []string{""}}
e, _ := NewRedisExporter(rr, "test", "") e, _ := NewRedisExporter(rr, "test", "")
   
chM := make(chan prometheus.Metric) chM := make(chan prometheus.Metric)
go func() { go func() {
e.Collect(chM) e.Collect(chM)
close(chM) close(chM)
Loading
@@ -757,6 +754,9 @@ func TestSanitizeMetricName(t *testing.T) {
Loading
@@ -757,6 +754,9 @@ func TestSanitizeMetricName(t *testing.T) {
} }
   
func TestKeysReset(t *testing.T) { func TestKeysReset(t *testing.T) {
ts := httptest.NewServer(promhttp.Handler())
defer ts.Close()
e, _ := NewRedisExporter(defaultRedisHost, "test", dbNumStrFull+"="+keys[0]) e, _ := NewRedisExporter(defaultRedisHost, "test", dbNumStrFull+"="+keys[0])
   
setupDBKeys(t, defaultRedisHost.Addrs[0]) setupDBKeys(t, defaultRedisHost.Addrs[0])
Loading
@@ -764,13 +764,13 @@ func TestKeysReset(t *testing.T) {
Loading
@@ -764,13 +764,13 @@ func TestKeysReset(t *testing.T) {
   
prometheus.Register(e) prometheus.Register(e)
   
chM := make(chan prometheus.Metric) chM := make(chan prometheus.Metric, 10000)
go func() { go func() {
e.Collect(chM) e.Collect(chM)
close(chM) close(chM)
}() }()
   
body := getMetrics(t) body := downloadUrl(t, ts.URL+"/metrics")
   
if !bytes.Contains(body, []byte(keys[0])) { if !bytes.Contains(body, []byte(keys[0])) {
t.Errorf("Did not found key %q\n%s", keys[0], body) t.Errorf("Did not found key %q\n%s", keys[0], body)
Loading
@@ -778,14 +778,182 @@ func TestKeysReset(t *testing.T) {
Loading
@@ -778,14 +778,182 @@ func TestKeysReset(t *testing.T) {
   
deleteKeysFromDB(t, defaultRedisHost.Addrs[0]) deleteKeysFromDB(t, defaultRedisHost.Addrs[0])
   
body = getMetrics(t) body = downloadUrl(t, ts.URL+"/metrics")
   
if bytes.Contains(body, []byte(keys[0])) { if bytes.Contains(body, []byte(keys[0])) {
t.Errorf("Metric is present in metrics list %q\n%s", keys[0], body) t.Errorf("Metric is present in metrics list %q\n%s", keys[0], body)
} }
} }
   
func TestClusterMaster(t *testing.T) {
if os.Getenv("TEST_REDIS_CLUSTER_MASTER_URI") == "" {
log.Println("TEST_REDIS_CLUSTER_MASTER_URI not set - skipping")
t.SkipNow()
return
}
ts := httptest.NewServer(promhttp.Handler())
defer ts.Close()
addr := "redis://" + os.Getenv("TEST_REDIS_CLUSTER_MASTER_URI")
host := RedisHost{Addrs: []string{addr}, Aliases: []string{"master"}}
e, _ := NewRedisExporter(host, "test", "")
setupDBKeys(t, defaultRedisHost.Addrs[0])
defer deleteKeysFromDB(t, defaultRedisHost.Addrs[0])
log.Println("wut")
prometheus.Register(e)
chM := make(chan prometheus.Metric, 10000)
go func() {
e.Collect(chM)
close(chM)
}()
body := downloadUrl(t, ts.URL+"/metrics")
if !bytes.Contains(body, []byte("test_instance_info")) {
t.Errorf("Did not found key %q\n%s", keys[0], body)
}
}
func TestPasswordProtectedInstance(t *testing.T) {
ts := httptest.NewServer(promhttp.Handler())
defer ts.Close()
testPwd := "p4$$w0rd"
host := defaultRedisHost
host.Passwords = []string{testPwd}
setupDBKeys(t, host.Addrs[0])
// set password for redis instance
c, err := redis.DialURL(host.Addrs[0])
if err != nil {
t.Errorf("couldn't setup redis, err: %s ", err)
return
}
defer c.Close()
if _, err = c.Do("CONFIG", "SET", "requirepass", testPwd); err != nil {
t.Fatalf("error setting password, err: %s", err)
}
c.Flush()
defer func() {
if _, err = c.Do("auth", testPwd); err != nil {
t.Fatalf("error unsetting password, err: %s", err)
}
if _, err = c.Do("CONFIG", "SET", "requirepass", ""); err != nil {
t.Fatalf("error unsetting password, err: %s", err)
}
deleteKeysFromDB(t, host.Addrs[0])
}()
e, _ := NewRedisExporter(host, "test", "")
prometheus.Register(e)
chM := make(chan prometheus.Metric, 10000)
go func() {
e.Collect(chM)
close(chM)
}()
body := downloadUrl(t, ts.URL+"/metrics")
if !bytes.Contains(body, []byte("test_up")) {
t.Errorf("error")
}
}
func TestPasswordInvalid(t *testing.T) {
ts := httptest.NewServer(promhttp.Handler())
defer ts.Close()
testPwd := "p4$$w0rd"
host := defaultRedisHost
host.Passwords = []string{"wrong_password"}
setupDBKeys(t, host.Addrs[0])
// set password for redis instance
c, err := redis.DialURL(host.Addrs[0])
if err != nil {
t.Errorf("couldn't setup redis, err: %s ", err)
return
}
defer c.Close()
if _, err = c.Do("CONFIG", "SET", "requirepass", testPwd); err != nil {
t.Fatalf("error setting password, err: %s", err)
}
c.Flush()
defer func() {
if _, err = c.Do("auth", testPwd); err != nil {
t.Fatalf("error unsetting password, err: %s", err)
}
if _, err = c.Do("CONFIG", "SET", "requirepass", ""); err != nil {
t.Fatalf("error unsetting password, err: %s", err)
}
deleteKeysFromDB(t, host.Addrs[0])
}()
e, _ := NewRedisExporter(host, "test", "")
prometheus.Register(e)
chM := make(chan prometheus.Metric, 10000)
go func() {
e.Collect(chM)
close(chM)
}()
body := downloadUrl(t, ts.URL+"/metrics")
log.Println(string(body))
if !bytes.Contains(body, []byte("test_exporter_last_scrape_error 1")) {
t.Errorf(`error, expected string "test_exporter_last_scrape_error 1" in body`)
}
}
func TestClusterSlave(t *testing.T) {
if os.Getenv("TEST_REDIS_CLUSTER_SLAVE_URI") == "" {
log.Println("TEST_REDIS_CLUSTER_SLAVE_URI not set - skipping")
t.SkipNow()
return
}
ts := httptest.NewServer(promhttp.Handler())
defer ts.Close()
addr := "redis://" + os.Getenv("TEST_REDIS_CLUSTER_SLAVE_URI")
host := RedisHost{Addrs: []string{addr}, Aliases: []string{"slave"}}
e, _ := NewRedisExporter(host, "test", "")
setupDBKeys(t, defaultRedisHost.Addrs[0])
defer deleteKeysFromDB(t, defaultRedisHost.Addrs[0])
log.Println("wut")
prometheus.Register(e)
chM := make(chan prometheus.Metric, 10000)
go func() {
e.Collect(chM)
close(chM)
}()
body := downloadUrl(t, ts.URL+"/metrics")
if !bytes.Contains(body, []byte("test_instance_info")) {
t.Errorf("Did not found key %q\n%s", keys[0], body)
}
}
func init() { func init() {
ll := strings.ToLower(os.Getenv("LOG_LEVEL"))
if pl, err := log.ParseLevel(ll); err == nil {
log.Printf("Setting log level to: %s", ll)
log.SetLevel(pl)
} else {
log.SetLevel(log.InfoLevel)
}
for _, n := range []string{"john", "paul", "ringo", "george"} { for _, n := range []string{"john", "paul", "ringo", "george"} {
key := fmt.Sprintf("key_%s_%d", n, ts) key := fmt.Sprintf("key_%s_%d", n, ts)
keys = append(keys, key) keys = append(keys, key)
Loading
@@ -812,6 +980,4 @@ func init() {
Loading
@@ -812,6 +980,4 @@ func init() {
   
log.Printf("Using redis addrs: %#v", addrs) log.Printf("Using redis addrs: %#v", addrs)
defaultRedisHost = RedisHost{Addrs: []string{"redis://" + *redisAddr}, Aliases: aliases} defaultRedisHost = RedisHost{Addrs: []string{"redis://" + *redisAddr}, Aliases: aliases}
TestServerURL = httptest.NewServer(promhttp.Handler()).URL
} }
Loading
@@ -104,7 +104,7 @@ func main() {
Loading
@@ -104,7 +104,7 @@ func main() {
} else { } else {
prometheus.MustRegister(exp) prometheus.MustRegister(exp)
prometheus.MustRegister(buildInfo) prometheus.MustRegister(buildInfo)
http.Handle(*metricPath, prometheus.Handler()) http.Handle(*metricPath, promhttp.Handler())
} }
   
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment