Skip to content

Commit

Permalink
add GetStaticIPs function and test case (#121)
Browse files Browse the repository at this point in the history
* add GetStaticIPs function and test case

* add fixtures

* move to *net.IPNet

* add comment

* use netip package

* remove line

---------

Co-authored-by: Daniel Paulus <daniel@checklyhq.com>
  • Loading branch information
benben and danielpaulus authored Jul 1, 2024
1 parent 0ad859d commit 1e565ea
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 0 deletions.
69 changes: 69 additions & 0 deletions checkly.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"io/ioutil"
"net/http"
"net/http/httputil"
"net/netip"
"net/url"
"os"
"strconv"
Expand Down Expand Up @@ -1366,6 +1367,74 @@ func (c *client) GetRuntime(
return &result, nil
}

// Get static IP lists
func (c *client) GetStaticIPs(
ctx context.Context,
) ([]StaticIP, error) {
var IPs []StaticIP

// getting IPv6 first
status, res, err := c.apiCall(
ctx,
http.MethodGet,
"static-ipv6s-by-region",
nil,
)
if err != nil {
return nil, err
}
if status != http.StatusOK {
return nil, fmt.Errorf("unexpected response status %d: %q", status, res)
}

var datav6 map[string]string
err = json.Unmarshal([]byte(res), &datav6)
if err != nil {
return nil, fmt.Errorf("decoding error for data %s: %v", res, err)
}

for region, ip := range datav6 {
addr, err := netip.ParsePrefix(ip)
if err != nil {
return nil, fmt.Errorf("could not parse CIDR from %s: %v", ip, err)
}

IPs = append(IPs, StaticIP{Region: region, Address: addr})
}

// and then IPv4
status, res, err = c.apiCall(
ctx,
http.MethodGet,
"static-ips-by-region",
nil,
)
if err != nil {
return nil, err
}
if status != http.StatusOK {
return nil, fmt.Errorf("unexpected response status %d: %q", status, res)
}

var datav4 map[string][]string
err = json.Unmarshal([]byte(res), &datav4)
if err != nil {
return nil, fmt.Errorf("decoding error for data %s: %v", res, err)
}

for region, ips := range datav4 {
for _, ip := range ips {
addr, err := netip.ParseAddr(ip)
if err != nil {
return nil, fmt.Errorf("could not parse CIDR from %s: %v", ip, err)
}
IPs = append(IPs, StaticIP{Region: region, Address: netip.PrefixFrom(addr, 32)})
}
}

return IPs, nil
}

// dumpResponse writes the raw response data to the debug output, if set, or
// standard error otherwise.
func (c *client) dumpResponse(resp *http.Response) {
Expand Down
57 changes: 57 additions & 0 deletions checkly_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ import (
"io/ioutil"
"net/http"
"net/http/httptest"
"net/netip"
"os"
"path"
"path/filepath"
"reflect"
"strconv"
"strings"
"testing"
Expand Down Expand Up @@ -1516,3 +1519,57 @@ func TestGetPrivateLocation(t *testing.T) {
t.Error(cmp.Diff(testPrivateLocation, *pl, ignorePrivateLocationFields))
}
}

func TestGetStaticIPs(t *testing.T) {
t.Parallel()

fixtureMap := map[string]string{
"/v1/static-ips-by-region": "StaticIPs.json",
"/v1/static-ipv6s-by-region": "StaticIPv6s.json",
}

// we can't use cannedResponseServer here since we need a response on more than one URL
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fileName, ok := fixtureMap[r.URL.Path]
if !ok {
http.Error(w, "URL not found", http.StatusNotFound)
return
}

filePath := filepath.Join("fixtures", fileName)
fileData, err := ioutil.ReadFile(filePath)
if err != nil {
http.Error(w, "File not found", http.StatusNotFound)
return
}
w.Write(fileData)
}))
defer ts.Close()

client := checkly.NewClient(ts.URL, "dummy-key", ts.Client(), nil)
gotStaticIPs, err := client.GetStaticIPs(context.Background())
if err != nil {
t.Error(err)
}

exampleIPv4 := netip.MustParsePrefix("54.151.146.209/32")
exampleIPv6 := netip.MustParsePrefix("2600:1f18:12ca:3000::/56")

expected := []checkly.StaticIP{
{Region: "ap-southeast-1", Address: exampleIPv4},
{Region: "us-east-1", Address: exampleIPv6},
}

for _, exp := range expected {
found := false
for _, ip := range gotStaticIPs {
if reflect.DeepEqual(ip, exp) {
found = true
break
}
}
if !found {
t.Errorf("Expected %+v to be included in %+v, but it was not found", exp, gotStaticIPs)
}
}
}
1 change: 1 addition & 0 deletions fixtures/StaticIPs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"af-south-1":["13.244.136.126","13.244.236.0","13.245.106.43","13.245.148.249","13.246.130.231","13.247.30.251"],"ap-east-1":["16.162.201.45","16.163.4.182","16.163.237.192","18.163.68.67","18.166.1.159","43.199.11.165"],"ap-northeast-1":["3.114.75.140","13.113.60.181","18.177.47.156","18.177.64.19","18.177.131.104","57.180.166.209"],"ap-northeast-2":["3.34.12.129","3.37.59.136","13.209.34.65","13.209.211.14","15.164.121.38","15.164.200.158","43.202.173.18","43.202.219.81"],"ap-northeast-3":["13.208.82.239","15.152.103.65","15.152.125.107","15.168.5.169","15.168.45.240","15.168.106.208"],"ap-south-1":["3.6.20.243","3.109.106.92","3.109.109.177","3.109.167.65","15.207.219.98","65.0.112.148"],"ap-southeast-1":["13.214.117.85","13.228.244.82","52.74.182.121","52.220.40.195","54.151.146.209","122.248.238.187"],"ap-southeast-2":["13.54.45.181","13.55.213.62","13.211.27.92","13.237.8.239","13.238.60.37","54.252.49.95"],"ap-southeast-3":["43.218.8.168","43.218.19.251","43.218.154.173","43.218.202.200","43.218.237.62","43.218.250.173"],"ca-central-1":["3.98.215.170","15.156.126.181","15.157.99.108","15.157.101.15","52.60.138.202","52.60.240.255"],"eu-central-1":["3.74.107.228","3.78.155.165","3.125.108.148","18.184.0.56","18.193.141.226","18.197.172.39"],"eu-north-1":["13.48.162.54","16.170.38.94","51.20.29.65","51.20.153.4","51.20.158.132","51.21.16.250"],"eu-south-1":["15.161.180.124","18.102.35.213","18.102.39.196","18.102.46.79","18.102.59.137","18.102.92.39"],"eu-west-1":["3.255.54.55","34.242.17.159","34.246.74.139","34.246.204.133","52.212.195.72","54.195.90.61"],"eu-west-2":["13.43.156.224","18.132.86.84","18.134.149.153","18.134.201.213","18.135.179.55","35.176.249.175"],"eu-west-3":["13.36.226.230","13.39.3.231","13.39.232.43","13.39.236.84","15.188.122.137","35.180.153.150"],"me-south-1":["15.184.22.185","15.184.252.133","15.185.92.84","15.185.104.229","15.185.156.205","157.241.93.172"],"sa-east-1":["15.229.56.35","18.229.243.24","18.230.50.229","54.94.0.175","54.207.45.193","54.233.84.10"],"us-east-1":["3.211.217.48","34.230.212.244","44.206.103.147","44.210.168.97","44.221.164.148","44.221.215.176","52.22.78.31","52.71.172.74","52.201.210.118","54.146.26.208","54.161.245.122","54.164.9.242"],"us-east-2":["3.17.106.146","3.134.230.82","3.134.239.96","3.143.128.19","18.188.44.71","18.223.8.66"],"us-west-1":["13.52.93.107","52.8.167.200","54.177.183.174","54.241.196.177"],"us-west-2":["34.209.2.129","34.215.165.113","44.235.44.60","44.237.79.79","44.240.116.205","52.36.214.162","52.42.153.190","54.186.86.230"]}
1 change: 1 addition & 0 deletions fixtures/StaticIPv6s.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"af-south-1":"2406:da11:e9f:a800::/56","ap-east-1":"2406:da1e:f19:b000::/56","ap-northeast-1":"2406:da14:8e6:8700::/56","ap-northeast-2":"2406:da12:940:c700::/56","ap-northeast-3":"2406:da16:422:8400::/56","ap-south-1":"2406:da1a:ec4:6100::/56","ap-southeast-1":"2406:da18:51c:e500::/56","ap-southeast-2":"2406:da1c:a54:1c00::/56","ap-southeast-3":"2406:da19:772:2100::/56","ca-central-1":"2600:1f11:c05:aa00::/56","eu-central-1":"2a05:d014:ed3:f100::/56","eu-north-1":"2a05:d016:407:6600::/56","eu-south-1":"2a05:d01a:d6a:3100::/56","eu-west-1":"2a05:d018:6a0:af00::/56","eu-west-2":"2a05:d01c:b4b:c00::/56","eu-west-3":"2a05:d012:4ab:2200::/56","me-south-1":"2a05:d01e:364:c000::/56","sa-east-1":"2600:1f1e:d01:6d00::/56","us-east-1":"2600:1f18:12ca:3000::/56","us-east-2":"2600:1f16:1971:eb00::/56","us-west-1":"2600:1f1c:95e:a400::/56","us-west-2":"2600:1f14:3144:5c00::/56"}
11 changes: 11 additions & 0 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"log"
"net/http"
"net/netip"
"time"
)

Expand Down Expand Up @@ -356,6 +357,8 @@ type Client interface {
ctx context.Context,
ID string,
) (*Runtime, error)

GetStaticIPs(ctx context.Context) ([]StaticIP, error)
}

// client represents a Checkly client. If the Debug field is set to an io.Writer
Expand Down Expand Up @@ -912,6 +915,14 @@ type Runtime struct {
Description string `json:"description"`
}

// This type is used to describe Checkly's official
// public range of IP addresses checks are executed from
// see https://www.checklyhq.com/docs/monitoring/allowlisting/#ip-range-allowlisting
type StaticIP struct {
Region string
Address netip.Prefix
}

// SetConfig sets config of alert channel based on it's type
func (a *AlertChannel) SetConfig(cfg interface{}) {
switch v := cfg.(type) {
Expand Down

0 comments on commit 1e565ea

Please sign in to comment.