aboutsummaryrefslogtreecommitdiff
path: root/clients/netbox/client.go
diff options
context:
space:
mode:
Diffstat (limited to 'clients/netbox/client.go')
-rw-r--r--clients/netbox/client.go165
1 files changed, 165 insertions, 0 deletions
diff --git a/clients/netbox/client.go b/clients/netbox/client.go
new file mode 100644
index 0000000..905aa40
--- /dev/null
+++ b/clients/netbox/client.go
@@ -0,0 +1,165 @@
1package netbox
2
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "io"
8 "net"
9 "net/http"
10 "net/url"
11 "strconv"
12
13 "code.crute.us/mcrute/golib/vault"
14)
15
16type NetboxClient interface {
17 GetSitePrefixesWithTag(ctx context.Context, site string, tag string) ([]*net.IPNet, error)
18 GetPrefixesWithTag(ctx context.Context, tag string) ([]*net.IPNet, error)
19}
20
21func NewNetboxClient(endpoint string, vault vault.VaultClient, vaultMaterial string) NetboxClient {
22 return &netboxClient{
23 endpoint: endpoint,
24 vault: vault,
25 vaultMaterial: vaultMaterial,
26 }
27}
28
29type netboxClient struct {
30 vault vault.VaultClient
31 endpoint string
32 vaultMaterial string
33}
34
35func (c *netboxClient) makeRequestRaw(ctx context.Context, method, u string, ib io.Reader, o interface{}) error {
36 apiKey, err := c.vault.KVApiKey(ctx, c.vaultMaterial)
37 if err != nil {
38 return err
39 }
40
41 req, err := http.NewRequestWithContext(ctx, method, u, ib)
42 if err != nil {
43 return err
44 }
45 req.Header.Add("Authorization", fmt.Sprintf("Token %s", apiKey.Key))
46
47 res, err := http.DefaultClient.Do(req)
48 if err != nil {
49 return err
50 }
51 defer res.Body.Close()
52
53 if err = json.NewDecoder(res.Body).Decode(o); err != nil {
54 return err
55 }
56
57 return nil
58}
59
60func (c *netboxClient) makeRequest(ctx context.Context, method, path string, q url.Values, ib io.Reader, o interface{}) error {
61 u, err := url.Parse(c.endpoint)
62 if err != nil {
63 return err
64 }
65 u.Path = path
66 u.RawQuery = q.Encode()
67
68 return c.makeRequestRaw(ctx, method, u.String(), ib, o)
69}
70
71func (c *netboxClient) GetSitePrefixesWithTag(ctx context.Context, site string, tag string) ([]*net.IPNet, error) {
72 s, err := c.resolveSiteNameToId(ctx, site)
73 if err != nil {
74 return nil, err
75 }
76
77 out := []*net.IPNet{}
78
79 q := url.Values{}
80 q.Add("site_id", strconv.Itoa(s))
81 q.Add("tag", tag)
82
83 page := &PrefixList{}
84 if err := c.makeRequest(ctx, http.MethodGet, "/api/ipam/prefixes/", q, nil, page); err != nil {
85 return nil, err
86 }
87
88 for _, r := range page.Results {
89 _, ipnet, err := net.ParseCIDR(r.Prefix)
90 if err != nil {
91 return nil, err
92 }
93 out = append(out, ipnet)
94 }
95
96 for page.Next != "" {
97 page = &PrefixList{}
98 if err := c.makeRequestRaw(ctx, http.MethodGet, page.Next, nil, page); err != nil {
99 return nil, err
100 }
101
102 for _, r := range page.Results {
103 _, ipnet, err := net.ParseCIDR(r.Prefix)
104 if err != nil {
105 return nil, err
106 }
107 out = append(out, ipnet)
108 }
109 }
110
111 return out, nil
112}
113
114func (c *netboxClient) GetPrefixesWithTag(ctx context.Context, tag string) ([]*net.IPNet, error) {
115 out := []*net.IPNet{}
116
117 q := url.Values{}
118 q.Add("tag", tag)
119
120 page := &PrefixList{}
121 if err := c.makeRequest(ctx, http.MethodGet, "/api/ipam/prefixes/", q, nil, page); err != nil {
122 return nil, err
123 }
124
125 for _, r := range page.Results {
126 _, ipnet, err := net.ParseCIDR(r.Prefix)
127 if err != nil {
128 return nil, err
129 }
130 out = append(out, ipnet)
131 }
132
133 for page.Next != "" {
134 page = &PrefixList{}
135 if err := c.makeRequestRaw(ctx, http.MethodGet, page.Next, nil, page); err != nil {
136 return nil, err
137 }
138
139 for _, r := range page.Results {
140 _, ipnet, err := net.ParseCIDR(r.Prefix)
141 if err != nil {
142 return nil, err
143 }
144 out = append(out, ipnet)
145 }
146 }
147
148 return out, nil
149}
150
151func (c *netboxClient) resolveSiteNameToId(ctx context.Context, s string) (int, error) {
152 q := url.Values{}
153 q.Add("name", s)
154
155 out := &SiteList{}
156 if err := c.makeRequest(ctx, http.MethodGet, "/api/dcim/sites/", q, nil, out); err != nil {
157 return 0, err
158 }
159
160 if len(out.Results) == 0 {
161 return 0, fmt.Errorf("resolveSiteNameToId: no results returned from netbox")
162 }
163
164 return out.Results[0].ID, nil
165}