From 9b12e4fe6f3c95986f1f3ec791636c58ca7e7583 Mon Sep 17 00:00:00 2001 From: Jake Champlin Date: Fri, 9 Jun 2017 17:54:32 +0000 Subject: Transfer of provider code --- vendor/github.com/DreamItGetIT/statuscake/LICENSE | 21 ++ .../github.com/DreamItGetIT/statuscake/README.md | 5 + .../github.com/DreamItGetIT/statuscake/client.go | 170 ++++++++++++ vendor/github.com/DreamItGetIT/statuscake/doc.go | 34 +++ .../github.com/DreamItGetIT/statuscake/errors.go | 80 ++++++ vendor/github.com/DreamItGetIT/statuscake/makefile | 11 + .../DreamItGetIT/statuscake/responses.go | 70 +++++ vendor/github.com/DreamItGetIT/statuscake/tests.go | 298 +++++++++++++++++++++ 8 files changed, 689 insertions(+) create mode 100644 vendor/github.com/DreamItGetIT/statuscake/LICENSE create mode 100644 vendor/github.com/DreamItGetIT/statuscake/README.md create mode 100644 vendor/github.com/DreamItGetIT/statuscake/client.go create mode 100644 vendor/github.com/DreamItGetIT/statuscake/doc.go create mode 100644 vendor/github.com/DreamItGetIT/statuscake/errors.go create mode 100644 vendor/github.com/DreamItGetIT/statuscake/makefile create mode 100644 vendor/github.com/DreamItGetIT/statuscake/responses.go create mode 100644 vendor/github.com/DreamItGetIT/statuscake/tests.go (limited to 'vendor/github.com/DreamItGetIT') diff --git a/vendor/github.com/DreamItGetIT/statuscake/LICENSE b/vendor/github.com/DreamItGetIT/statuscake/LICENSE new file mode 100644 index 0000000..5442aad --- /dev/null +++ b/vendor/github.com/DreamItGetIT/statuscake/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 DreamItGetIT + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/DreamItGetIT/statuscake/README.md b/vendor/github.com/DreamItGetIT/statuscake/README.md new file mode 100644 index 0000000..f1e4eaf --- /dev/null +++ b/vendor/github.com/DreamItGetIT/statuscake/README.md @@ -0,0 +1,5 @@ +# statuscake + +`statuscake` is a Go pkg that implements a client for the [statuscake]("https://statuscake.com") API. + +More documentation and examples at [http://godoc.org/github.com/DreamItGetIT/statuscake](http://godoc.org/github.com/DreamItGetIT/statuscake). diff --git a/vendor/github.com/DreamItGetIT/statuscake/client.go b/vendor/github.com/DreamItGetIT/statuscake/client.go new file mode 100644 index 0000000..6094be5 --- /dev/null +++ b/vendor/github.com/DreamItGetIT/statuscake/client.go @@ -0,0 +1,170 @@ +package statuscake + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "strings" +) + +const apiBaseURL = "https://app.statuscake.com/API" + +type responseBody struct { + io.Reader +} + +func (r *responseBody) Close() error { + return nil +} + +// Auth wraps the authorisation headers required for each request +type Auth struct { + Username string + Apikey string +} + +func (a *Auth) validate() error { + e := make(ValidationError) + + if a.Username == "" { + e["Username"] = "is required" + } + + if a.Apikey == "" { + e["Apikey"] = "is required" + } + + if len(e) > 0 { + return e + } + + return nil +} + +type httpClient interface { + Do(*http.Request) (*http.Response, error) +} + +type apiClient interface { + get(string, url.Values) (*http.Response, error) + delete(string, url.Values) (*http.Response, error) + put(string, url.Values) (*http.Response, error) +} + +// Client is the http client that wraps the remote API. +type Client struct { + c httpClient + username string + apiKey string + testsClient Tests +} + +// New returns a new Client +func New(auth Auth) (*Client, error) { + if err := auth.validate(); err != nil { + return nil, err + } + + return &Client{ + c: &http.Client{}, + username: auth.Username, + apiKey: auth.Apikey, + }, nil +} + +func (c *Client) newRequest(method string, path string, v url.Values, body io.Reader) (*http.Request, error) { + url := fmt.Sprintf("%s%s", apiBaseURL, path) + if v != nil { + url = fmt.Sprintf("%s?%s", url, v.Encode()) + } + + r, err := http.NewRequest(method, url, body) + if err != nil { + return nil, err + } + + r.Header.Set("Username", c.username) + r.Header.Set("API", c.apiKey) + + return r, nil +} + +func (c *Client) doRequest(r *http.Request) (*http.Response, error) { + resp, err := c.c.Do(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode < 200 || resp.StatusCode > 299 { + return nil, &httpError{ + status: resp.Status, + statusCode: resp.StatusCode, + } + } + + var aer autheticationErrorResponse + + // We read and save the response body so that if we don't have error messages + // we can set it again for future usage + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + err = json.Unmarshal(b, &aer) + if err == nil && aer.ErrNo == 0 && aer.Error != "" { + return nil, &AuthenticationError{ + errNo: aer.ErrNo, + message: aer.Error, + } + } + + resp.Body = &responseBody{ + Reader: bytes.NewReader(b), + } + + return resp, nil +} + +func (c *Client) get(path string, v url.Values) (*http.Response, error) { + r, err := c.newRequest("GET", path, v, nil) + if err != nil { + return nil, err + } + + return c.doRequest(r) +} + +func (c *Client) put(path string, v url.Values) (*http.Response, error) { + r, err := c.newRequest("PUT", path, nil, strings.NewReader(v.Encode())) + r.Header.Set("Content-Type", "application/x-www-form-urlencoded") + + if err != nil { + return nil, err + } + + return c.doRequest(r) +} + +func (c *Client) delete(path string, v url.Values) (*http.Response, error) { + r, err := c.newRequest("DELETE", path, v, nil) + if err != nil { + return nil, err + } + + return c.doRequest(r) +} + +// Tests returns a client that implements the `Tests` API. +func (c *Client) Tests() Tests { + if c.testsClient == nil { + c.testsClient = newTests(c) + } + + return c.testsClient +} diff --git a/vendor/github.com/DreamItGetIT/statuscake/doc.go b/vendor/github.com/DreamItGetIT/statuscake/doc.go new file mode 100644 index 0000000..fa68d94 --- /dev/null +++ b/vendor/github.com/DreamItGetIT/statuscake/doc.go @@ -0,0 +1,34 @@ +// Package statuscake implements a client for statuscake.com API. +// +// // list all `Tests` +// c, err := statuscake.New(statuscake.Auth{Username: username, Apikey: apikey}) +// if err != nil { +// log.Fatal(err) +// } +// +// tests, err := c.Tests().All() +// if err != nil { +// log.Fatal(err) +// } +// +// // delete a `Test` +// err = c.Tests().Delete(TestID) +// +// // create a test +// t := &statuscake.Test{ +// WebsiteName: "Foo", +// WebsiteURL: "htto://example.com", +// ... other required args... +// } +// +// if err = t.Validate(); err != nil { +// log.Fatal(err) +// } +// +// t2 := c.Tests().Update(t) +// fmt.Printf("New Test created with id: %d\n", t2.TestID) +// +// // get Tests details +// t, err := tt.Detail(id) +// ... +package statuscake diff --git a/vendor/github.com/DreamItGetIT/statuscake/errors.go b/vendor/github.com/DreamItGetIT/statuscake/errors.go new file mode 100644 index 0000000..4c51991 --- /dev/null +++ b/vendor/github.com/DreamItGetIT/statuscake/errors.go @@ -0,0 +1,80 @@ +package statuscake + +import ( + "fmt" + "strings" +) + +// APIError implements the error interface an it's used when the API response has errors. +type APIError interface { + APIError() string +} + +type httpError struct { + status string + statusCode int +} + +func (e *httpError) Error() string { + return fmt.Sprintf("HTTP error: %d - %s", e.statusCode, e.status) +} + +// ValidationError is a map where the key is the invalid field and the value is a message describing why the field is invalid. +type ValidationError map[string]string + +func (e ValidationError) Error() string { + var messages []string + + for k, v := range e { + m := fmt.Sprintf("%s %s", k, v) + messages = append(messages, m) + } + + return strings.Join(messages, ", ") +} + +type updateError struct { + Issues interface{} +} + +func (e *updateError) Error() string { + var messages []string + + if issues, ok := e.Issues.(map[string]interface{}); ok { + for k, v := range issues { + m := fmt.Sprintf("%s %s", k, v) + messages = append(messages, m) + } + } else if issues, ok := e.Issues.([]interface{}); ok { + for _, v := range issues { + m := fmt.Sprint(v) + messages = append(messages, m) + } + } + + return strings.Join(messages, ", ") +} + +// APIError returns the error specified in the API response +func (e *updateError) APIError() string { + return e.Error() +} + +type deleteError struct { + Message string +} + +func (e *deleteError) Error() string { + return e.Message +} + +// AuthenticationError implements the error interface and it's returned +// when API responses have authentication errors +type AuthenticationError struct { + errNo int + message string +} + +func (e *AuthenticationError) Error() string { + return fmt.Sprintf("%d, %s", e.errNo, e.message) +} diff --git a/vendor/github.com/DreamItGetIT/statuscake/makefile b/vendor/github.com/DreamItGetIT/statuscake/makefile new file mode 100644 index 0000000..946f6d9 --- /dev/null +++ b/vendor/github.com/DreamItGetIT/statuscake/makefile @@ -0,0 +1,11 @@ +.PHONY: default lint test + +default: lint test + +lint: + @golint ./... + @go vet ./... + +test: + go test ${GOTEST_ARGS} ./... + diff --git a/vendor/github.com/DreamItGetIT/statuscake/responses.go b/vendor/github.com/DreamItGetIT/statuscake/responses.go new file mode 100644 index 0000000..b9216b7 --- /dev/null +++ b/vendor/github.com/DreamItGetIT/statuscake/responses.go @@ -0,0 +1,70 @@ +package statuscake + +type autheticationErrorResponse struct { + ErrNo int + Error string +} + +type updateResponse struct { + Issues interface{} `json:"Issues"` + Success bool `json:"Success"` + Message string `json:"Message"` + InsertID int `json:"InsertID"` +} + +type deleteResponse struct { + Success bool `json:"Success"` + Error string `json:"Error"` +} + +type detailResponse struct { + Method string `json:"Method"` + TestID int `json:"TestID"` + TestType string `json:"TestType"` + Paused bool `json:"Paused"` + WebsiteName string `json:"WebsiteName"` + URI string `json:"URI"` + ContactID int `json:"ContactID"` + Status string `json:"Status"` + Uptime float64 `json:"Uptime"` + CheckRate int `json:"CheckRate"` + Timeout int `json:"Timeout"` + LogoImage string `json:"LogoImage"` + Confirmation int `json:"Confirmation,string"` + WebsiteHost string `json:"WebsiteHost"` + NodeLocations []string `json:"NodeLocations"` + FindString string `json:"FindString"` + DoNotFind bool `json:"DoNotFind"` + LastTested string `json:"LastTested"` + NextLocation string `json:"NextLocation"` + Port int `json:"Port"` + Processing bool `json:"Processing"` + ProcessingState string `json:"ProcessingState"` + ProcessingOn string `json:"ProcessingOn"` + DownTimes int `json:"DownTimes,string"` + Sensitive bool `json:"Sensitive"` + TriggerRate int `json:"TriggerRate,string"` +} + +func (d *detailResponse) test() *Test { + return &Test{ + TestID: d.TestID, + TestType: d.TestType, + Paused: d.Paused, + WebsiteName: d.WebsiteName, + WebsiteURL: d.URI, + ContactID: d.ContactID, + Status: d.Status, + Uptime: d.Uptime, + CheckRate: d.CheckRate, + Timeout: d.Timeout, + LogoImage: d.LogoImage, + Confirmation: d.Confirmation, + WebsiteHost: d.WebsiteHost, + NodeLocations: d.NodeLocations, + FindString: d.FindString, + DoNotFind: d.DoNotFind, + Port: d.Port, + TriggerRate: d.TriggerRate, + } +} diff --git a/vendor/github.com/DreamItGetIT/statuscake/tests.go b/vendor/github.com/DreamItGetIT/statuscake/tests.go new file mode 100644 index 0000000..4053e53 --- /dev/null +++ b/vendor/github.com/DreamItGetIT/statuscake/tests.go @@ -0,0 +1,298 @@ +package statuscake + +import ( + "encoding/json" + "fmt" + "net/url" + "reflect" + "strings" +) + +const queryStringTag = "querystring" + +// Test represents a statuscake Test +type Test struct { + // ThiTestID is an int, use this to get more details about this test. If not provided will insert a new check, else will update + TestID int `json:"TestID" querystring:"TestID" querystringoptions:"omitempty"` + + // Sent tfalse To Unpause and true To Pause. + Paused bool `json:"Paused" querystring:"Paused"` + + // Website name. Tags are stripped out + WebsiteName string `json:"WebsiteName" querystring:"WebsiteName"` + + // Test location, either an IP (for TCP and Ping) or a fully qualified URL for other TestTypes + WebsiteURL string `json:"WebsiteURL" querystring:"WebsiteURL"` + + // A Port to use on TCP Tests + Port int `json:"Port" querystring:"Port"` + + // Contact group ID - will return int of contact group used else 0 + ContactID int `json:"ContactID" querystring:"ContactGroup"` + + // Current status at last test + Status string `json:"Status"` + + // 7 Day Uptime + Uptime float64 `json:"Uptime"` + + // Any test locations seperated by a comma (using the Node Location IDs) + NodeLocations []string `json:"NodeLocations" querystring:"NodeLocations"` + + // Timeout in an int form representing seconds. + Timeout int `json:"Timeout" querystring:"Timeout"` + + // A URL to ping if a site goes down. + PingURL string `json:"PingURL" querystring:"PingURL"` + + Confirmation int `json:"Confirmationi,string" querystring:"Confirmation"` + + // The number of seconds between checks. + CheckRate int `json:"CheckRate" querystring:"CheckRate"` + + // A Basic Auth User account to use to login + BasicUser string `json:"BasicUser" querystring:"BasicUser"` + + // If BasicUser is set then this should be the password for the BasicUser + BasicPass string `json:"BasicPass" querystring:"BasicPass"` + + // Set 1 to enable public reporting, 0 to disable + Public int `json:"Public" querystring:"Public"` + + // A URL to a image to use for public reporting + LogoImage string `json:"LogoImage" querystring:"LogoImage"` + + // Set to 0 to use branding (default) or 1 to disable public reporting branding + Branding int `json:"Branding" querystring:"Branding"` + + // Used internally by the statuscake API + WebsiteHost string `json:"WebsiteHost"` + + // Enable virus checking or not. 1 to enable + Virus int `json:"Virus" querystring:"Virus"` + + // A string that should either be found or not found. + FindString string `json:"FindString" querystring:"FindString"` + + // If the above string should be found to trigger a alert. true will trigger if FindString found + DoNotFind bool `json:"DoNotFind" querystring:"DoNotFind"` + + // What type of test type to use. Accepted values are HTTP, TCP, PING + TestType string `json:"TestType" querystring:"TestType"` + + // Use 1 to TURN OFF real browser testing + RealBrowser int `json:"RealBrowser" querystring:"RealBrowser"` + + // How many minutes to wait before sending an alert + TriggerRate int `json:"TriggerRate" querystring:"TriggerRate"` + + // Tags should be seperated by a comma - no spacing between tags (this,is,a set,of,tags) + TestTags string `json:"TestTags" querystring:"TestTags"` + + // Comma Seperated List of StatusCodes to Trigger Error on (on Update will replace, so send full list each time) + StatusCodes string `json:"StatusCodes" querystring:"StatusCodes"` +} + +// Validate checks if the Test is valid. If it's invalid, it returns a ValidationError with all invalid fields. It returns nil otherwise. +func (t *Test) Validate() error { + e := make(ValidationError) + + if t.WebsiteName == "" { + e["WebsiteName"] = "is required" + } + + if t.WebsiteURL == "" { + e["WebsiteURL"] = "is required" + } + + if t.Timeout != 0 && (t.Timeout < 6 || t.Timeout > 99) { + e["Timeout"] = "must be 0 or between 6 and 99" + } + + if t.Confirmation < 0 || t.Confirmation > 9 { + e["Confirmation"] = "must be between 0 and 9" + } + + if t.CheckRate < 0 || t.CheckRate > 23999 { + e["CheckRate"] = "must be between 0 and 23999" + } + + if t.Public < 0 || t.Public > 1 { + e["Public"] = "must be 0 or 1" + } + + if t.Virus < 0 || t.Virus > 1 { + e["Virus"] = "must be 0 or 1" + } + + if t.TestType != "HTTP" && t.TestType != "TCP" && t.TestType != "PING" { + e["TestType"] = "must be HTTP, TCP, or PING" + } + + if t.RealBrowser < 0 || t.RealBrowser > 1 { + e["RealBrowser"] = "must be 0 or 1" + } + + if t.TriggerRate < 0 || t.TriggerRate > 59 { + e["TriggerRate"] = "must be between 0 and 59" + } + + if len(e) > 0 { + return e + } + + return nil +} + +// ToURLValues returns url.Values of all fields required to create/update a Test. +func (t Test) ToURLValues() url.Values { + values := make(url.Values) + st := reflect.TypeOf(t) + sv := reflect.ValueOf(t) + for i := 0; i < st.NumField(); i++ { + sf := st.Field(i) + tag := sf.Tag.Get(queryStringTag) + ft := sf.Type + if ft.Name() == "" && ft.Kind() == reflect.Ptr { + // Follow pointer. + ft = ft.Elem() + } + + v := sv.Field(i) + options := sf.Tag.Get("querystringoptions") + omit := options == "omitempty" && isEmptyValue(v) + + if tag != "" && !omit { + values.Set(tag, valueToQueryStringValue(v)) + } + } + + return values +} + +func isEmptyValue(v reflect.Value) bool { + switch v.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + } + + return false +} + +func valueToQueryStringValue(v reflect.Value) string { + if v.Type().Name() == "bool" { + if v.Bool() { + return "1" + } + + return "0" + } + + if v.Type().Kind() == reflect.Slice { + if ss, ok := v.Interface().([]string); ok { + return strings.Join(ss, ",") + } + } + + return fmt.Sprint(v) +} + +// Tests is a client that implements the `Tests` API. +type Tests interface { + All() ([]*Test, error) + Detail(int) (*Test, error) + Update(*Test) (*Test, error) + Delete(TestID int) error +} + +type tests struct { + client apiClient +} + +func newTests(c apiClient) Tests { + return &tests{ + client: c, + } +} + +func (tt *tests) All() ([]*Test, error) { + resp, err := tt.client.get("/Tests", nil) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var tests []*Test + err = json.NewDecoder(resp.Body).Decode(&tests) + + return tests, err +} + +func (tt *tests) Update(t *Test) (*Test, error) { + resp, err := tt.client.put("/Tests/Update", t.ToURLValues()) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var ur updateResponse + err = json.NewDecoder(resp.Body).Decode(&ur) + if err != nil { + return nil, err + } + + if !ur.Success { + return nil, &updateError{Issues: ur.Issues} + } + + t2 := *t + t2.TestID = ur.InsertID + + return &t2, err +} + +func (tt *tests) Delete(testID int) error { + resp, err := tt.client.delete("/Tests/Details", url.Values{"TestID": {fmt.Sprint(testID)}}) + if err != nil { + return err + } + defer resp.Body.Close() + + var dr deleteResponse + err = json.NewDecoder(resp.Body).Decode(&dr) + if err != nil { + return err + } + + if !dr.Success { + return &deleteError{Message: dr.Error} + } + + return nil +} + +func (tt *tests) Detail(testID int) (*Test, error) { + resp, err := tt.client.get("/Tests/Details", url.Values{"TestID": {fmt.Sprint(testID)}}) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var dr *detailResponse + err = json.NewDecoder(resp.Body).Decode(&dr) + if err != nil { + return nil, err + } + + return dr.test(), nil +} -- cgit v1.2.3