Add TM2 nagios validator, fix html formatting
Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/667ed342 Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/667ed342 Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/667ed342 Branch: refs/heads/master Commit: 667ed342cd41d73923fffdf144134cedbac32bc4 Parents: e252d4c Author: Robert Butts <[email protected]> Authored: Fri Mar 3 11:47:24 2017 -0700 Committer: Dave Neuman <[email protected]> Committed: Wed Apr 12 15:43:31 2017 -0600 ---------------------------------------------------------------------- traffic_monitor_golang/common/nagios/nagios.go | 23 +++ .../traffic_monitor/tmcheck/tmcheck.go | 2 +- .../tools/nagios-validate-offline.go | 50 +++++ .../tools/service-validate-offline.go | 204 +++++++++++++++++++ .../traffic_monitor/tools/validate-offline.go | 200 ------------------ 5 files changed, 278 insertions(+), 201 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/667ed342/traffic_monitor_golang/common/nagios/nagios.go ---------------------------------------------------------------------- diff --git a/traffic_monitor_golang/common/nagios/nagios.go b/traffic_monitor_golang/common/nagios/nagios.go new file mode 100644 index 0000000..53af782 --- /dev/null +++ b/traffic_monitor_golang/common/nagios/nagios.go @@ -0,0 +1,23 @@ +package nagios + +import ( + "fmt" + "os" + "strings" +) + +type Status int + +const ( + Ok Status = 0 + Warning Status = 1 + Critical Status = 2 +) + +func Exit(status Status, msg string) { + if msg != "" { + msg = strings.TrimRight(msg, "\n") + fmt.Printf("%s\n", msg) + } + os.Exit(int(status)) +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/667ed342/traffic_monitor_golang/traffic_monitor/tmcheck/tmcheck.go ---------------------------------------------------------------------- diff --git a/traffic_monitor_golang/traffic_monitor/tmcheck/tmcheck.go b/traffic_monitor_golang/traffic_monitor/tmcheck/tmcheck.go index 0fdab61..fa2c533 100644 --- a/traffic_monitor_golang/traffic_monitor/tmcheck/tmcheck.go +++ b/traffic_monitor_golang/traffic_monitor/tmcheck/tmcheck.go @@ -228,7 +228,7 @@ func AllMonitorsCRStatesOfflineValidator( invalid := map[enum.TrafficMonitorName]bool{} invalidStart := map[enum.TrafficMonitorName]time.Time{} for { - tmErrs, err := ValidateAllMonitorsOfflineStates(toClient, includeOffline) // []MonitorError { + tmErrs, err := ValidateAllMonitorsOfflineStates(toClient, includeOffline) if err != nil { onErr("", fmt.Errorf("Error validating monitors: %v", err)) time.Sleep(interval) http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/667ed342/traffic_monitor_golang/traffic_monitor/tools/nagios-validate-offline.go ---------------------------------------------------------------------- diff --git a/traffic_monitor_golang/traffic_monitor/tools/nagios-validate-offline.go b/traffic_monitor_golang/traffic_monitor/tools/nagios-validate-offline.go new file mode 100644 index 0000000..6a1ab96 --- /dev/null +++ b/traffic_monitor_golang/traffic_monitor/tools/nagios-validate-offline.go @@ -0,0 +1,50 @@ +package main + +import ( + "flag" + "fmt" + "github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/common/nagios" + "github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/traffic_monitor/tmcheck" + to "github.com/apache/incubator-trafficcontrol/traffic_ops/client" +) + +const UserAgent = "tm-offline-validator/0.1" + +func main() { + toURI := flag.String("to", "", "The Traffic Ops URI, whose CRConfig to validate") + toUser := flag.String("touser", "", "The Traffic Ops user") + toPass := flag.String("topass", "", "The Traffic Ops password") + includeOffline := flag.Bool("includeOffline", false, "Whether to include Offline Monitors") + help := flag.Bool("help", false, "Usage info") + helpBrief := flag.Bool("h", false, "Usage info") + flag.Parse() + if *help || *helpBrief { + fmt.Printf("Usage: ./nagios-validate-offline -to https://traffic-ops.example.net -touser bill -topass thelizard -includeOffline true\n") + return + } + + toClient, err := to.LoginWithAgent(*toURI, *toUser, *toPass, true, UserAgent, false, tmcheck.RequestTimeout) + if err != nil { + fmt.Printf("Error logging in to Traffic Ops: %v\n", err) + return + } + + monitorErrs, err := tmcheck.ValidateAllMonitorsOfflineStates(toClient, *includeOffline) + + if err != nil { + nagios.Exit(nagios.Critical, fmt.Sprintf("Error validating monitor offline statuses: %v", err)) + } + + errStr := "" + for monitor, err := range monitorErrs { + if err != nil { + errStr += fmt.Sprintf("error validating offline status for monitor %v : %v\n", monitor, err.Error()) + } + } + + if errStr != "" { + nagios.Exit(nagios.Critical, errStr) + } + + nagios.Exit(nagios.Ok, "") +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/667ed342/traffic_monitor_golang/traffic_monitor/tools/service-validate-offline.go ---------------------------------------------------------------------- diff --git a/traffic_monitor_golang/traffic_monitor/tools/service-validate-offline.go b/traffic_monitor_golang/traffic_monitor/tools/service-validate-offline.go new file mode 100644 index 0000000..41e0eb4 --- /dev/null +++ b/traffic_monitor_golang/traffic_monitor/tools/service-validate-offline.go @@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// validate-offline is a utility HTTP service which polls the given Traffic Monitor and validates that no OFFLINE or ADMIN_DOWN caches in the Traffic Ops CRConfig are marked Available in Traffic Monitor's CRstates endpoint. + +package main + +import ( + "flag" + "fmt" + "github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/traffic_monitor/enum" + "github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/traffic_monitor/tmcheck" + to "github.com/apache/incubator-trafficcontrol/traffic_ops/client" + "net/http" + "sort" + "sync" + "time" +) + +const UserAgent = "tm-offline-validator/0.1" + +const LogLimit = 10 + +type Log struct { + log *[]string + limit int + errored *bool + lastCheck *time.Time + m *sync.RWMutex +} + +func (l *Log) Add(msg string) { + l.m.Lock() + defer l.m.Unlock() + *l.log = append([]string{msg}, *l.log...) + if len(*l.log) > l.limit { + *l.log = (*l.log)[:l.limit] + } +} + +func (l *Log) Get() []string { + l.m.RLock() + defer l.m.RUnlock() + return *l.log +} + +func (l *Log) GetErrored() (bool, time.Time) { + l.m.RLock() + defer l.m.RUnlock() + return *l.errored, *l.lastCheck +} + +func (l *Log) SetErrored(e bool) { + l.m.Lock() + defer l.m.Unlock() + *l.errored = e + *l.lastCheck = time.Now() +} + +func NewLog() Log { + log := make([]string, 0, LogLimit+1) + errored := false + limit := LogLimit + lastCheck := time.Time{} + return Log{log: &log, errored: &errored, m: &sync.RWMutex{}, limit: limit, lastCheck: &lastCheck} +} + +type Logs struct { + logs map[enum.TrafficMonitorName]Log + m *sync.RWMutex +} + +func NewLogs() Logs { + return Logs{logs: map[enum.TrafficMonitorName]Log{}, m: &sync.RWMutex{}} +} + +func (l Logs) Get(name enum.TrafficMonitorName) Log { + l.m.Lock() + defer l.m.Unlock() + if _, ok := l.logs[name]; !ok { + l.logs[name] = NewLog() + } + return l.logs[name] +} + +func (l Logs) GetMonitors() []string { + l.m.RLock() + defer l.m.RUnlock() + monitors := []string{} + for name, _ := range l.logs { + monitors = append(monitors, string(name)) + } + return monitors +} + +func main() { + toURI := flag.String("to", "", "The Traffic Ops URI, whose CRConfig to validate") + toUser := flag.String("touser", "", "The Traffic Ops user") + toPass := flag.String("topass", "", "The Traffic Ops password") + interval := flag.Duration("interval", time.Second*time.Duration(5), "The interval to validate") + grace := flag.Duration("grace", time.Second*time.Duration(30), "The grace period before invalid states are reported") + includeOffline := flag.Bool("includeOffline", false, "Whether to include Offline Monitors") + help := flag.Bool("help", false, "Usage info") + helpBrief := flag.Bool("h", false, "Usage info") + flag.Parse() + if *help || *helpBrief { + fmt.Printf("Usage: go run validate-offline -to https://traffic-ops.example.net -touser bill -topass thelizard -tm http://traffic-monitor.example.net -interval 5s -grace 30s -includeOffline true\n") + return + } + + toClient, err := to.LoginWithAgent(*toURI, *toUser, *toPass, true, UserAgent, false, tmcheck.RequestTimeout) + if err != nil { + fmt.Printf("Error logging in to Traffic Ops: %v\n", err) + return + } + + logs := NewLogs() + + onErr := func(name enum.TrafficMonitorName, err error) { + log := logs.Get(name) + log.Add(fmt.Sprintf("%v ERROR %v\n", time.Now(), err)) + log.SetErrored(true) + } + + onResumeSuccess := func(name enum.TrafficMonitorName) { + log := logs.Get(name) + log.Add(fmt.Sprintf("%v INFO State Valid\n", time.Now())) + log.SetErrored(false) + } + + onCheck := func(name enum.TrafficMonitorName, err error) { + log := logs.Get(name) + log.SetErrored(err != nil) + } + + go tmcheck.AllMonitorsCRStatesOfflineValidator(toClient, *interval, *includeOffline, *grace, onErr, onResumeSuccess, onCheck) + + if err := serve(logs, *toURI); err != nil { + fmt.Printf("Serve error: %v\n", err) + } +} + +func serve(logs Logs, toURI string) error { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Content-Type", "text/html") + fmt.Fprintf(w, `<!DOCTYPE html> +<meta http-equiv="refresh" content="5"> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1"> +<title>Traffic Monitor Offline Validator</title> +<style type="text/css">body{margin:40px auto;line-height:1.6;font-size:18px;color:#444;padding:0 8px 0 8px}h1,h2,h3{line-height:1.2}span{padding:0px 4px 0px 4px;}</style>`) + + fmt.Fprintf(w, `<p>%s`, toURI) + + fmt.Fprintf(w, `<table style="width:100%%">`) + + monitors := logs.GetMonitors() + sort.Strings(monitors) // sort, so they're always in the same order in the webpage + for _, monitor := range monitors { + fmt.Fprintf(w, `</tr>`) + + log := logs.Get(enum.TrafficMonitorName(monitor)) + + fmt.Fprintf(w, `<td><span>%s</span></td>`, monitor) + errored, lastCheck := log.GetErrored() + if errored { + fmt.Fprintf(w, `<td><span style="color:red">Invalid</span></td>`) + } else { + fmt.Fprintf(w, `<td><span style="color:limegreen">Valid</span></td>`) + } + fmt.Fprintf(w, `<td><span>as of %v</span></td>`, lastCheck) + + fmt.Fprintf(w, `<td><span style="font-family:monospace">`) + logCopy := log.Get() + firstMsg := "" + if len(logCopy) > 0 { + firstMsg = logCopy[0] + } + fmt.Fprintf(w, "%s\n", firstMsg) + fmt.Fprintf(w, `</span></td>`) + + fmt.Fprintf(w, `</tr>`) + } + fmt.Fprintf(w, `</table>`) + }) + return http.ListenAndServe(":80", nil) +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/667ed342/traffic_monitor_golang/traffic_monitor/tools/validate-offline.go ---------------------------------------------------------------------- diff --git a/traffic_monitor_golang/traffic_monitor/tools/validate-offline.go b/traffic_monitor_golang/traffic_monitor/tools/validate-offline.go deleted file mode 100644 index d031007..0000000 --- a/traffic_monitor_golang/traffic_monitor/tools/validate-offline.go +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -// validate-offline is a utility HTTP service which polls the given Traffic Monitor and validates that no OFFLINE or ADMIN_DOWN caches in the Traffic Ops CRConfig are marked Available in Traffic Monitor's CRstates endpoint. - -package main - -import ( - "flag" - "fmt" - "github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/traffic_monitor/enum" - "github.com/apache/incubator-trafficcontrol/traffic_monitor_golang/traffic_monitor/tmcheck" - to "github.com/apache/incubator-trafficcontrol/traffic_ops/client" - "net/http" - "sync" - "time" -) - -const UserAgent = "tm-offline-validator/0.1" - -const LogLimit = 10000 - -type Log struct { - log *[]string - limit int - errored *bool - m *sync.RWMutex -} - -func (l *Log) Add(msg string) { - l.m.Lock() - defer l.m.Unlock() - *l.log = append([]string{msg}, *l.log...) - if len(*l.log) > l.limit { - *l.log = (*l.log)[:l.limit] - } -} - -func (l *Log) Get() []string { - l.m.RLock() - defer l.m.RUnlock() - return *l.log -} - -func (l *Log) GetErrored() bool { - l.m.RLock() - defer l.m.RUnlock() - return *l.errored -} - -func (l *Log) SetErrored(e bool) { - l.m.Lock() - defer l.m.Unlock() - *l.errored = e -} - -func NewLog() Log { - log := make([]string, 0, LogLimit+1) - errored := false - limit := LogLimit - return Log{log: &log, errored: &errored, m: &sync.RWMutex{}, limit: limit} -} - -type Logs struct { - logs map[enum.TrafficMonitorName]Log - m *sync.RWMutex -} - -func NewLogs() Logs { - return Logs{logs: map[enum.TrafficMonitorName]Log{}, m: &sync.RWMutex{}} -} - -func (l Logs) Get(name enum.TrafficMonitorName) Log { - l.m.Lock() - defer l.m.Unlock() - if _, ok := l.logs[name]; !ok { - l.logs[name] = NewLog() - } - return l.logs[name] -} - -func (l Logs) GetMonitors() []enum.TrafficMonitorName { - l.m.RLock() - defer l.m.RUnlock() - monitors := []enum.TrafficMonitorName{} - for name, _ := range l.logs { - monitors = append(monitors, name) - } - return monitors -} - -func main() { - toURI := flag.String("to", "", "The Traffic Ops URI, whose CRConfig to validate") - toUser := flag.String("touser", "", "The Traffic Ops user") - toPass := flag.String("topass", "", "The Traffic Ops password") - interval := flag.Duration("interval", time.Second*time.Duration(5), "The interval to validate") - grace := flag.Duration("grace", time.Second*time.Duration(30), "The grace period before invalid states are reported") - includeOffline := flag.Bool("includeOffline", false, "Whether to include Offline Monitors") - help := flag.Bool("help", false, "Usage info") - helpBrief := flag.Bool("h", false, "Usage info") - flag.Parse() - if *help || *helpBrief { - fmt.Printf("Usage: go run validate-offline -to https://traffic-ops.example.net -touser bill -topass thelizard -tm http://traffic-monitor.example.net -interval 5s -grace 30s -includeOffline true\n") - return - } - - toClient, err := to.LoginWithAgent(*toURI, *toUser, *toPass, true, UserAgent, false, tmcheck.RequestTimeout) - if err != nil { - fmt.Printf("Error logging in to Traffic Ops: %v\n", err) - return - } - - logs := NewLogs() - - onErr := func(name enum.TrafficMonitorName, err error) { - log := logs.Get(name) - log.Add(fmt.Sprintf("%v ERROR %v\n", time.Now(), err)) - log.SetErrored(true) - } - - onResumeSuccess := func(name enum.TrafficMonitorName) { - log := logs.Get(name) - log.Add(fmt.Sprintf("%v INFO State Valid\n", time.Now())) - log.SetErrored(false) - } - - onCheck := func(name enum.TrafficMonitorName, err error) { - log := logs.Get(name) - if err != nil { - log.Add(fmt.Sprintf("%v DEBUG invalid: %v\n", time.Now(), err)) - } else { - log.Add(fmt.Sprintf("%v DEBUG valid\n", time.Now())) - } - } - - go tmcheck.AllMonitorsCRStatesOfflineValidator(toClient, *interval, *includeOffline, *grace, onErr, onResumeSuccess, onCheck) - - if err := serve(logs, *toURI); err != nil { - fmt.Printf("Serve error: %v\n", err) - } -} - -func serve(logs Logs, toURI string) error { - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Header().Set("Content-Type", "text/html") - fmt.Fprintf(w, `<!DOCTYPE html> -<meta http-equiv="refresh" content="5"> -<meta charset="utf-8"> -<meta name="viewport" content="width=device-width, initial-scale=1"> -<title>Traffic Monitor Offline Validator</title> -<style type="text/css">body{margin:40px auto;line-height:1.6;font-size:18px;color:#444;padding:0 2px}h1,h2,h3{line-height:1.2}</style>`) - - fmt.Fprintf(w, `<p>%s`, toURI) - - fmt.Fprintf(w, `<table style="width:100%%"><tr>`) - - monitors := logs.GetMonitors() - for _, monitor := range monitors { - fmt.Fprintf(w, `<td>`) - - log := logs.Get(monitor) - - fmt.Fprintf(w, `<p>%s`, monitor) - if log.GetErrored() { - fmt.Fprintf(w, `<h1 style="color:red">Invalid</h1>`) - } else { - fmt.Fprintf(w, `<h1 style="color:limegreen">Valid</h1>`) - } - - fmt.Fprintf(w, `<pre>`) - logCopy := log.Get() - for _, msg := range logCopy { - fmt.Fprintf(w, "%s\n", msg) - } - fmt.Fprintf(w, `</pre>`) - - fmt.Fprintf(w, `</td>`) - } - - fmt.Fprintf(w, `</tr></table>`) - }) - return http.ListenAndServe(":80", nil) -}
