-
Notifications
You must be signed in to change notification settings - Fork 1
/
status.go
150 lines (127 loc) · 3.53 KB
/
status.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
(C) 2022, 2023 Robert Kisteleki & RIPE NCC
See LICENSE file for the license.
*/
package goat
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/url"
)
// status check result object, as it comes from the API
type StatusCheckResult struct {
GloblaAlert bool `json:"global_alert"`
TotalAlerts uint `json:"total_alerts"`
Probes map[uint]StatusCheckProbe `json:"probes"`
}
// status check result for one probe
type StatusCheckProbe struct {
Alert bool `json:"alert"`
Last float64 `json:"last"`
LastPacketLoss float64 `json:"last_packet_loss"`
Source string `json:"source"`
AllRTTs *[]float64 `json:"all"`
}
// a status check result: error or value
type AsyncStatusCheckResult struct {
Status *StatusCheckResult
Error error
}
// ShortString produces a short textual description of the status
func (sc *StatusCheckResult) ShortString() string {
text := fmt.Sprintf("%v\t%d\t%d",
sc.GloblaAlert,
sc.TotalAlerts,
len(sc.Probes),
)
return text
}
// LongString produces a longer textual description of the status
func (sc *StatusCheckResult) LongString() string {
text := sc.ShortString()
// add the list of alerting probes to the output
alerted := make([]uint, 0)
for probe, status := range sc.Probes {
if status.Alert {
alerted = append(alerted, probe)
}
}
text += fmt.Sprintf("\t%v", alerted)
return text
}
// StatusCheckFilter struct holds specified filters and other options
type StatusCheckFilter struct {
params url.Values
id uint
showall bool
}
// NewStatusCheckFilter prepares a new status check filter object
func NewStatusCheckFilter() StatusCheckFilter {
sc := StatusCheckFilter{}
sc.params = url.Values{}
return sc
}
// MsmID sets the measurement ID for which we ask the status check
func (filter *StatusCheckFilter) MsmID(id uint) {
filter.id = id
}
// GetAllRTTs asks for all RTTs to be returned
func (filter *StatusCheckFilter) GetAllRTTs(showall bool) {
filter.showall = showall
if showall {
filter.params.Add("show_all", fmt.Sprintf("%v", showall))
}
}
// Verify sanity of applied filters
func (filter *StatusCheckFilter) verifyFilters() error {
if filter.id == 0 {
return fmt.Errorf("ID must be specified")
}
return nil
}
// StatusCheck returns a status check result
func (filter *StatusCheckFilter) StatusCheck(
verbose bool,
statuses chan AsyncStatusCheckResult,
) {
defer close(statuses)
var status StatusCheckResult
// sanity checks - late in the process, but not too late
err := filter.verifyFilters()
if err != nil {
statuses <- AsyncStatusCheckResult{&status, err}
return
}
// make the request
query := fmt.Sprintf("%smeasurements/%d/status-check?%s", apiBaseURL, filter.id, filter.params.Encode())
resp, err := apiGetRequest(verbose, query, nil)
if err != nil {
statuses <- AsyncStatusCheckResult{&status, err}
return
}
// read the response - it is a single JSON
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
statuses <- AsyncStatusCheckResult{&status, err}
return
}
// check for error(s)
if resp.StatusCode != 200 {
var errors MultiErrorResponse
err = json.Unmarshal(data, &errors)
if err != nil {
statuses <- AsyncStatusCheckResult{&status, err}
return
}
statuses <- AsyncStatusCheckResult{&status, fmt.Errorf(errors.Error.Detail)}
return
}
// parse the response into a status object
err = json.Unmarshal(data, &status)
if err != nil {
statuses <- AsyncStatusCheckResult{&status, err}
return
}
statuses <- AsyncStatusCheckResult{&status, nil}
}