bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/cmd/tsdbrelay/integrationTest/main.go (about)

     1  /*
     2  We are going to simulate a full multi-datacenter cluster:
     3  DC1:
     4  	- tsdbrelay:	:5555
     5  	- opentsdb:		:5556
     6  	- bosun: 		:5557
     7  DC2:
     8  	- tsdbrelay		:6555
     9  	- opentsdb 		:6556
    10  	- bosun:		:6557
    11  */
    12  package main
    13  
    14  import (
    15  	"bytes"
    16  	"compress/gzip"
    17  	"encoding/json"
    18  	"fmt"
    19  	"io"
    20  	"log"
    21  	"net/http"
    22  	"os"
    23  	"os/exec"
    24  	"os/signal"
    25  	"time"
    26  
    27  	"bosun.org/metadata"
    28  	"bosun.org/models"
    29  	"bosun.org/opentsdb"
    30  )
    31  
    32  var (
    33  	relay1, relay2     *os.Process
    34  	gotMeta1, gotMeta2 bool
    35  )
    36  
    37  func init() {
    38  	cmd := exec.Command("tsdbrelay", "-l=:5555", "-b=localhost:5557", "-r=localhost:6555", "-t=localhost:5556", "-denormalize=os.cpu__host")
    39  	cmd.Stdout = os.Stdout
    40  	cmd.Stderr = os.Stderr
    41  	err := cmd.Start()
    42  	if err != nil {
    43  		fatal(err)
    44  	}
    45  	relay1 = cmd.Process
    46  	cmd = exec.Command("tsdbrelay", "-l=:6555", "-b=localhost:6557", "-r=localhost:5555", "-t=localhost:6556", "-denormalize=os.cpu__host")
    47  	cmd.Stdout = os.Stdout
    48  	cmd.Stderr = os.Stderr
    49  	err = cmd.Start()
    50  	if err != nil {
    51  		fatal(err)
    52  	}
    53  	relay2 = cmd.Process
    54  	dc1BosunMux := http.NewServeMux()
    55  	dc1BosunMux.HandleFunc("/api/index", handleBosun(dc1BosunReceived))
    56  	dc1BosunMux.HandleFunc("/api/metadata/put", handleMeta(&gotMeta1))
    57  	go func() {
    58  		fatal("DC1-Bosun", http.ListenAndServe(":5557", dc1BosunMux))
    59  	}()
    60  
    61  	dc2BosunMux := http.NewServeMux()
    62  	dc2BosunMux.HandleFunc("/api/index", handleBosun(dc2BosunReceived))
    63  	dc2BosunMux.HandleFunc("/api/metadata/put", handleMeta(&gotMeta2))
    64  	go func() {
    65  		fatal("DC2-Bosun", http.ListenAndServe(":6557", dc2BosunMux))
    66  	}()
    67  
    68  	dc1TsdbMux := http.NewServeMux()
    69  	dc1TsdbMux.HandleFunc("/api/put", handleTsdb(dc1TsdbReceived))
    70  
    71  	go func() {
    72  		fatal("DC1-TSDB", http.ListenAndServe(":5556", dc1TsdbMux))
    73  	}()
    74  
    75  	dc2TsdbMux := http.NewServeMux()
    76  	dc2TsdbMux.HandleFunc("/api/put", handleTsdb(dc2TsdbReceived))
    77  	go func() {
    78  		fatal("DC3-TSDB", http.ListenAndServe(":6556", dc2TsdbMux))
    79  	}()
    80  
    81  	ch := make(chan os.Signal)
    82  	signal.Notify(ch, os.Kill, os.Interrupt)
    83  	go func() {
    84  		<-ch
    85  		fatal("INTERRUPT RECIEVED")
    86  	}()
    87  	time.Sleep(2 * time.Second)
    88  }
    89  
    90  const (
    91  	localRelayUrl  = "http://localhost:5555/api/put"
    92  	remoteRelayUrl = "http://localhost:6555/api/put"
    93  )
    94  
    95  var (
    96  	dc1BosunReceived = map[models.AlertKey]int{}
    97  	dc2BosunReceived = map[models.AlertKey]int{}
    98  	dc1TsdbReceived  = map[models.AlertKey]int{}
    99  	dc2TsdbReceived  = map[models.AlertKey]int{}
   100  )
   101  
   102  func main() {
   103  	// 1. Single data point to local relay
   104  	dp1 := &opentsdb.DataPoint{Metric: "abc", Tags: opentsdb.TagSet{"host": "h1"}}
   105  	buf := encodeMdp([]*opentsdb.DataPoint{dp1})
   106  	resp, err := http.Post(localRelayUrl, "application/json", buf)
   107  	if err != nil {
   108  		fatal(err)
   109  	}
   110  	if resp.StatusCode != 204 {
   111  		fatal("response code not relayed")
   112  	}
   113  	time.Sleep(1 * time.Second)
   114  	check("Bosun DC1", "abc{host=h1}", 1, dc1BosunReceived)
   115  	check("Bosun DC2", "abc{host=h1}", 1, dc2BosunReceived)
   116  	check("Tsdb DC1", "abc{host=h1}", 1, dc1TsdbReceived)
   117  	check("Tsdb DC2", "abc{host=h1}", 1, dc2TsdbReceived)
   118  	log.Println("test 1 ok")
   119  	// 2. Single data point to remote relay. Should be denormalized.
   120  	dp2 := &opentsdb.DataPoint{Metric: "os.cpu", Tags: opentsdb.TagSet{"host": "h1"}}
   121  	buf = encodeMdp([]*opentsdb.DataPoint{dp2})
   122  	resp, err = http.Post(remoteRelayUrl, "application/json", buf)
   123  	if err != nil {
   124  		fatal(err)
   125  	}
   126  	if resp.StatusCode != 204 {
   127  		fatal("response code not relayed")
   128  	}
   129  	time.Sleep(1 * time.Second)
   130  	check("Bosun DC1", "os.cpu{host=h1}", 1, dc1BosunReceived)
   131  	check("Bosun DC2", "os.cpu{host=h1}", 1, dc2BosunReceived)
   132  	check("Tsdb DC1", "os.cpu{host=h1}", 1, dc1TsdbReceived)
   133  	check("Tsdb DC2", "os.cpu{host=h1}", 1, dc2TsdbReceived)
   134  	check("Bosun DC1", "__h1.os.cpu{host=h1}", 1, dc1BosunReceived)
   135  	check("Bosun DC2", "__h1.os.cpu{host=h1}", 1, dc2BosunReceived)
   136  	check("Tsdb DC1", "__h1.os.cpu{host=h1}", 1, dc1TsdbReceived)
   137  	check("Tsdb DC2", "__h1.os.cpu{host=h1}", 1, dc2TsdbReceived)
   138  	log.Println("test 2 ok")
   139  
   140  	metas := []metadata.Metasend{
   141  		{Metric: "foo", Name: "desc", Value: 42},
   142  	}
   143  	b, _ := json.Marshal(metas)
   144  	http.Post("http://localhost:5555/api/metadata/put", "application/json", bytes.NewReader(b))
   145  	time.Sleep(1 * time.Second)
   146  	if !gotMeta1 || !gotMeta2 {
   147  		fatal("Didn't get metadata in both datacenters. ", gotMeta1, gotMeta2)
   148  	}
   149  	killAll()
   150  }
   151  func check(node string, ak models.AlertKey, expected int, data map[models.AlertKey]int) {
   152  	if data[ak] != expected {
   153  		msg := fmt.Sprintf("Expected %s to see %s %d times, but saw %d.", node, ak, expected, data[ak])
   154  		fatal(msg)
   155  	}
   156  }
   157  
   158  func handleBosun(data map[models.AlertKey]int) http.HandlerFunc {
   159  	return func(w http.ResponseWriter, r *http.Request) {
   160  		readDps(r.Body, data)
   161  		w.WriteHeader(500)
   162  	}
   163  }
   164  
   165  func handleMeta(result *bool) http.HandlerFunc {
   166  	return func(w http.ResponseWriter, r *http.Request) {
   167  		*result = true
   168  	}
   169  }
   170  
   171  func handleTsdb(data map[models.AlertKey]int) http.HandlerFunc {
   172  	return func(w http.ResponseWriter, r *http.Request) {
   173  		readDps(r.Body, data)
   174  		w.WriteHeader(204)
   175  	}
   176  }
   177  
   178  func killAll() {
   179  	if relay1 != nil {
   180  		log.Println("Killing relay 1:", relay1.Kill())
   181  	}
   182  	if relay2 != nil {
   183  		log.Println("Killing relay 2:", relay2.Kill())
   184  	}
   185  }
   186  func readDps(r io.Reader, data map[models.AlertKey]int) {
   187  	gr, err := gzip.NewReader(r)
   188  	if err != nil {
   189  		fatal(err)
   190  	}
   191  	jr := json.NewDecoder(gr)
   192  	mdp := []*opentsdb.DataPoint{}
   193  	err = jr.Decode(&mdp)
   194  	if err != nil {
   195  		fatal(err)
   196  	}
   197  	for _, dp := range mdp {
   198  		ak := models.NewAlertKey(dp.Metric, dp.Tags)
   199  		n, ok := data[ak]
   200  		if ok {
   201  			data[ak] = n + 1
   202  		} else {
   203  			data[ak] = 1
   204  		}
   205  	}
   206  }
   207  
   208  func encodeMdp(mdp []*opentsdb.DataPoint) io.Reader {
   209  	buf := &bytes.Buffer{}
   210  	gw := gzip.NewWriter(buf)
   211  	jw := json.NewEncoder(gw)
   212  	jw.Encode(mdp)
   213  	gw.Close()
   214  	return buf
   215  }
   216  
   217  func fatal(i ...interface{}) {
   218  	log.Println(i...)
   219  	killAll()
   220  	log.Fatal("")
   221  }