-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient.go
160 lines (136 loc) · 3.83 KB
/
client.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
151
152
153
154
155
156
157
158
159
160
package oxidized
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"time"
)
const (
DeviceStatusSuccess = "success"
DeviceStatusNever = "never"
DeviceStatusNoConnection = "no_connection"
)
type Device struct {
// FullName is the full name of the device, e.g. "netzwerk/leaf-netzwerk-01"
FullName string `json:"full_name"`
// Name is the name of the device, e.g. "leaf-netzwerk-01"
Name string `json:"name"`
// Group is the group of the device, e.g. "netzwerk"
Group string `json:"group"`
// Ip is the FQDN or IP of the device
Ip string `json:"ip"`
// Model is the model of the device, e.g. "cisco_ios"
Model string `json:"model"`
// Status is either "success", "never" or "no_connection"
Status string `json:"status"`
// Last is the last backup of the device
Last struct {
// Start is the start time of the last backup
Start string `json:"start"`
// End is the end time of the last backup
End string `json:"end"`
// Status is the status of the last backup
Status string `json:"status"`
// Time is the time of the last backup in seconds
Time float32 `json:"time"`
}
}
type DeviceStat struct {
Name string `json:"name"`
}
type ConfigStat struct {
// Size of the config in bytes
Size int
// Number of lines in the config
Lines int
}
type OxidizedClient struct {
Url string
Username string
Password string
}
func NewOxidizedClient(url, username, password string) *OxidizedClient {
return &OxidizedClient{
Url: url,
Username: username,
Password: password,
}
}
// get makes a GET request to the given path and decodes the response into v.
func (c *OxidizedClient) get(path string, v interface{}) error {
req, err := http.NewRequest("GET", c.Url+"/"+path+"?format=json", nil)
if err != nil {
return err
}
resp, err := c.request(*req)
if err != nil {
return err
}
slog.Debug("Got response from oxidized", "status_code", resp.StatusCode)
defer resp.Body.Close()
// debug json response
b, _ := io.ReadAll(resp.Body)
slog.Debug("Read response content", "body", string(b))
// decode json response from b
return json.Unmarshal(b, v)
}
func (c *OxidizedClient) request(req http.Request) (*http.Response, error) {
slog.Debug("Sending request to oxidized", "url", req.URL.String(), "method", req.Method)
if c.Username != "" && c.Password != "" {
req.SetBasicAuth(c.Username, c.Password)
}
return http.DefaultClient.Do(&req)
}
// GetDevices returns a list of devices from the oxidized API.
func (c *OxidizedClient) GetDevices() ([]Device, error) {
var devices []Device
err := c.get("nodes", &devices)
if err != nil {
return nil, err
}
slog.Debug("Got devices", "count", len(devices))
return devices, nil
}
// GetDeviceStats returns the stats from the oxidized API.
func (c *OxidizedClient) GetStatus() ([]DeviceStat, error) {
var stats []DeviceStat
err := c.get("nodes/stats", &stats)
if err != nil {
return nil, err
}
slog.Debug("Got device stats", "count", len(stats))
return stats, nil
}
func (c *OxidizedClient) GetConfigStats(group string, name string) (*ConfigStat, error) {
req, err := http.NewRequest("GET", c.Url+"/"+"node/fetch/"+group+"/"+name, nil)
if err != nil {
return nil, err
}
slog.Debug("Getting config of device", "group", group, "name", name)
resp, err := c.request(*req)
if err != nil {
return nil, err
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("failed to fetch config for %s/%s: %s", group, name, resp.Status)
}
defer resp.Body.Close()
b, _ := io.ReadAll(resp.Body)
return &ConfigStat{
Size: len(b),
Lines: bytes.Count(b, []byte("\n")),
}, nil
}
// ConvertOixidzedTimeTo8601 converts from 2019-11-19 14:00:00 CET
// to UnixTimeStamp
func ConvertOixidzedTimeToUnix(t string) (int64, error) {
parsed, err := time.Parse("2006-01-02 15:04:05 MST", t)
if err != nil {
return 0, err
}
unix := parsed.Unix()
return unix, nil
}