123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 |
- // Copyright 2016 Circonus, Inc. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package checkmgr
- import (
- "crypto/tls"
- "crypto/x509"
- "encoding/json"
- "errors"
- "fmt"
- "io/ioutil"
- "log"
- "net/http"
- "net/http/httptest"
- "net/url"
- "os"
- "strconv"
- "strings"
- "testing"
- "time"
- "github.com/circonus-labs/circonus-gometrics/api"
- "github.com/circonus-labs/circonus-gometrics/api/config"
- )
- func sslBroker() *httptest.Server {
- f := func(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(200)
- w.Header().Set("Content-Type", "application/json")
- fmt.Fprintln(w, r.Method)
- }
- return httptest.NewTLSServer(http.HandlerFunc(f))
- }
- var (
- testCMCheck = api.Check{
- CID: "/check/1234",
- Active: true,
- BrokerCID: "/broker/1234",
- CheckBundleCID: "/check_bundle/1234",
- CheckUUID: "abc123-a1b2-c3d4-e5f6-123abc",
- Details: map[config.Key]string{config.SubmissionURL: "https://127.0.0.1:43191/module/httptrap/abc123-a1b2-c3d4-e5f6-123abc/blah"},
- }
- testCMCheckBundle = api.CheckBundle{
- CheckUUIDs: []string{"abc123-a1b2-c3d4-e5f6-123abc"},
- Checks: []string{"/check/1234"},
- CID: "/check_bundle/1234",
- Created: 0,
- LastModified: 0,
- LastModifedBy: "",
- ReverseConnectURLs: []string{
- "mtev_reverse://127.0.0.1:43191/check/abc123-a1b2-c3d4-e5f6-123abc",
- },
- Brokers: []string{"/broker/1234"},
- DisplayName: "test check",
- Config: map[config.Key]string{
- config.SubmissionURL: "https://127.0.0.1:43191/module/httptrap/abc123-a1b2-c3d4-e5f6-123abc/blah",
- },
- // Config: api.CheckBundleConfig{
- // SubmissionURL: "https://127.0.0.1:43191/module/httptrap/abc123-a1b2-c3d4-e5f6-123abc/blah",
- // ReverseSecret: "blah",
- // },
- Metrics: []api.CheckBundleMetric{
- {
- Name: "elmo",
- Type: "numeric",
- Status: "active",
- },
- },
- MetricLimit: 0,
- Notes: nil,
- Period: 60,
- Status: "active",
- Target: "127.0.0.1",
- Timeout: 10,
- Type: "httptrap",
- Tags: []string{},
- }
- testCMBroker = api.Broker{
- CID: "/broker/1234",
- Name: "test broker",
- Type: "enterprise",
- Details: []api.BrokerDetail{
- {
- CN: "testbroker.example.com",
- ExternalHost: nil,
- ExternalPort: 43191,
- IP: &[]string{"127.0.0.1"}[0],
- Modules: []string{"httptrap"},
- Port: &[]uint16{43191}[0],
- Status: "active",
- },
- },
- }
- )
- func testCMServer() *httptest.Server {
- f := func(w http.ResponseWriter, r *http.Request) {
- // fmt.Printf("%s %s\n", r.Method, r.URL.String())
- switch r.URL.Path {
- case "/check_bundle/1234": // handle GET/PUT/DELETE
- switch r.Method {
- case "PUT": // update
- defer r.Body.Close()
- b, err := ioutil.ReadAll(r.Body)
- if err != nil {
- panic(err)
- }
- w.WriteHeader(200)
- w.Header().Set("Content-Type", "application/json")
- fmt.Fprintln(w, string(b))
- case "GET": // get by id/cid
- ret, err := json.Marshal(testCMCheckBundle)
- if err != nil {
- panic(err)
- }
- w.WriteHeader(200)
- w.Header().Set("Content-Type", "application/json")
- fmt.Fprintln(w, string(ret))
- default:
- w.WriteHeader(500)
- fmt.Fprintln(w, "unsupported method")
- }
- case "/check_bundle":
- switch r.Method {
- case "GET": // search
- if strings.HasPrefix(r.URL.String(), "/check_bundle?search=") {
- r := []api.CheckBundle{testCMCheckBundle}
- ret, err := json.Marshal(r)
- if err != nil {
- panic(err)
- }
- w.WriteHeader(200)
- w.Header().Set("Content-Type", "application/json")
- fmt.Fprintln(w, string(ret))
- } else {
- w.WriteHeader(200)
- w.Header().Set("Content-Type", "application/json")
- fmt.Fprintln(w, "[]")
- }
- case "POST": // create
- defer r.Body.Close()
- _, err := ioutil.ReadAll(r.Body)
- if err != nil {
- panic(err)
- }
- ret, err := json.Marshal(testCheckBundle)
- if err != nil {
- panic(err)
- }
- w.WriteHeader(200)
- w.Header().Set("Content-Type", "application/json")
- fmt.Fprintln(w, string(ret))
- default:
- w.WriteHeader(405)
- fmt.Fprintf(w, "method not allowed %s", r.Method)
- }
- case "/broker":
- switch r.Method {
- case "GET":
- r := []api.Broker{testCMBroker}
- ret, err := json.Marshal(r)
- if err != nil {
- panic(err)
- }
- w.WriteHeader(200)
- w.Header().Set("Content-Type", "application/json")
- fmt.Fprintln(w, string(ret))
- default:
- w.WriteHeader(405)
- fmt.Fprintf(w, "method not allowed %s", r.Method)
- }
- case "/broker/1234":
- switch r.Method {
- case "GET":
- ret, err := json.Marshal(testCMBroker)
- if err != nil {
- panic(err)
- }
- w.WriteHeader(200)
- w.Header().Set("Content-Type", "application/json")
- fmt.Fprintln(w, string(ret))
- default:
- w.WriteHeader(405)
- fmt.Fprintf(w, "method not allowed %s", r.Method)
- }
- case "/check":
- switch r.Method {
- case "GET":
- r := []api.Check{testCMCheck}
- ret, err := json.Marshal(r)
- if err != nil {
- panic(err)
- }
- w.WriteHeader(200)
- w.Header().Set("Content-Type", "application/json")
- fmt.Fprintln(w, string(ret))
- default:
- w.WriteHeader(405)
- fmt.Fprintf(w, "method not allowed %s", r.Method)
- }
- case "/check/1234":
- switch r.Method {
- case "GET":
- ret, err := json.Marshal(testCMCheck)
- if err != nil {
- panic(err)
- }
- w.WriteHeader(200)
- w.Header().Set("Content-Type", "application/json")
- fmt.Fprintln(w, string(ret))
- default:
- w.WriteHeader(405)
- fmt.Fprintf(w, "method not allowed %s", r.Method)
- }
- case "/pki/ca.crt":
- w.WriteHeader(200)
- w.Header().Set("Content-Type", "application/json")
- fmt.Fprintln(w, cert)
- default:
- msg := fmt.Sprintf("not found %s", r.URL.Path)
- w.WriteHeader(404)
- fmt.Fprintln(w, msg)
- }
- }
- return httptest.NewServer(http.HandlerFunc(f))
- }
- func TestNewCheckManager(t *testing.T) {
- t.Log("no config supplied")
- {
- expectedError := errors.New("invalid Check Manager configuration (nil)")
- _, err := NewCheckManager(nil)
- if err == nil || err.Error() != expectedError.Error() {
- t.Errorf("Expected an '%#v' error, got '%#v'", expectedError, err)
- }
- }
- t.Log("no API Token and no Submission URL supplied")
- {
- expectedError := errors.New("invalid check manager configuration (no API token AND no submission url)")
- cfg := &Config{}
- _, err := NewCheckManager(cfg)
- if err == nil || err.Error() != expectedError.Error() {
- t.Errorf("Expected an '%#v' error, got '%#v'", expectedError, err)
- }
- }
- t.Log("no API Token, Submission URL (http) only")
- {
- cfg := &Config{}
- cfg.Check.SubmissionURL = "http://127.0.0.1:56104"
- cm, err := NewCheckManager(cfg)
- if err != nil {
- t.Errorf("Expected no error, got '%v'", err)
- }
- cm.Initialize()
- for !cm.IsReady() {
- t.Log("\twaiting for cm to init")
- time.Sleep(1 * time.Second)
- }
- trap, err := cm.GetSubmissionURL()
- if err != nil {
- t.Errorf("Expected no error, got '%v'", err)
- }
- if trap.URL.String() != cfg.Check.SubmissionURL {
- t.Errorf("Expected '%s' == '%s'", trap.URL.String(), cfg.Check.SubmissionURL)
- }
- if trap.TLS != nil {
- t.Errorf("Expected nil found %#v", trap.TLS)
- }
- }
- t.Log("no API Token, Submission URL (https) only")
- {
- cfg := &Config{}
- cfg.Check.SubmissionURL = "https://127.0.0.1/v2"
- cm, err := NewCheckManager(cfg)
- if err != nil {
- t.Fatalf("Expected no error, got '%v'", err)
- }
- cm.Initialize()
- for !cm.IsReady() {
- t.Log("\twaiting for cm to init")
- time.Sleep(1 * time.Second)
- }
- trap, err := cm.GetSubmissionURL()
- if err != nil {
- t.Fatalf("Expected no error, got '%v'", err)
- }
- if trap.URL.String() != cfg.Check.SubmissionURL {
- t.Fatalf("Expected '%s' == '%s'", trap.URL.String(), cfg.Check.SubmissionURL)
- }
- if trap.TLS == nil {
- t.Fatalf("Expected a x509 cert pool, found nil")
- }
- }
- t.Log("Defaults")
- {
- server := testCMServer()
- defer server.Close()
- testURL, err := url.Parse(server.URL)
- if err != nil {
- t.Fatalf("Error parsing temporary url %v", err)
- }
- hostParts := strings.Split(testURL.Host, ":")
- hostPort, err := strconv.Atoi(hostParts[1])
- if err != nil {
- t.Fatalf("Error converting port to numeric %v", err)
- }
- testCMBroker.Details[0].ExternalHost = &hostParts[0]
- testCMBroker.Details[0].ExternalPort = uint16(hostPort)
- cfg := &Config{
- Log: log.New(os.Stderr, "", log.LstdFlags),
- API: api.Config{
- TokenKey: "1234",
- TokenApp: "abc",
- URL: server.URL,
- },
- }
- cm, err := NewCheckManager(cfg)
- if err != nil {
- t.Fatalf("Expected no error, got '%v'", err)
- }
- cm.Initialize()
- for !cm.IsReady() {
- t.Log("\twaiting for cm to init")
- time.Sleep(1 * time.Second)
- }
- trap, err := cm.GetSubmissionURL()
- if err != nil {
- t.Fatalf("Expected no error, got '%v'", err)
- }
- suburl, found := testCMCheckBundle.Config["submission_url"]
- if !found {
- t.Fatalf("Exected submission_url in check bundle config %+v", testCMCheckBundle)
- }
- if trap.URL.String() != suburl {
- t.Fatalf("Expected '%s' got '%s'", suburl, trap.URL.String())
- }
- }
- t.Log("Custom broker ssl config")
- {
- server := sslBroker()
- defer server.Close()
- cfg := &Config{
- Log: log.New(os.Stderr, "", log.LstdFlags),
- }
- c := server.Certificate()
- cp := x509.NewCertPool()
- cp.AddCert(c)
- cfg.Check.SubmissionURL = server.URL
- cfg.Broker.TLSConfig = &tls.Config{RootCAs: cp}
- cm, err := NewCheckManager(cfg)
- if err != nil {
- t.Fatalf("Expected no error, got '%v'", err)
- }
- cm.Initialize()
- for !cm.IsReady() {
- t.Log("\twaiting for cm to init")
- time.Sleep(1 * time.Second)
- }
- trap, err := cm.GetSubmissionURL()
- if err != nil {
- t.Fatalf("Expected no error, got '%v'", err)
- }
- if trap.URL.String() != server.URL {
- t.Fatalf("Expected '%s' got '%s'", server.URL, trap.URL.String())
- }
- // quick request to make sure the trap.TLS is the one passed and not the default
- client := &http.Client{Transport: &http.Transport{TLSClientConfig: trap.TLS}}
- if _, err := client.Get(trap.URL.String()); err != nil {
- t.Fatalf("expected no error, got (%s)", err)
- }
- t.Log("test ResetTrap")
- {
- err := cm.ResetTrap()
- if err != nil {
- t.Fatalf("expected no error, got (%s)", err)
- }
- trap, err := cm.GetSubmissionURL()
- if err != nil {
- t.Fatalf("Expected no error, got '%v'", err)
- }
- if trap.URL.String() != server.URL {
- t.Fatalf("Expected '%s' got '%s'", server.URL, trap.URL.String())
- }
- }
- t.Log("test RefreshTrap")
- {
- cm.trapLastUpdate = time.Now().Add(-(cm.trapMaxURLAge + 2*time.Second))
- cm.RefreshTrap()
- trap, err := cm.GetSubmissionURL()
- if err != nil {
- t.Fatalf("Expected no error, got '%v'", err)
- }
- if trap.URL.String() != server.URL {
- t.Fatalf("Expected '%s' got '%s'", server.URL, trap.URL.String())
- }
- }
- }
- }
|