Skip to content
This repository has been archived by the owner on Jan 15, 2024. It is now read-only.

Fix retry mechanism not sending body if first request fails before reading the body #150

Merged
merged 8 commits into from
May 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions admin.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gapi

import (
"bytes"
"encoding/json"
"fmt"
)
Expand All @@ -25,7 +24,7 @@ func (c *Client) CreateUser(user User) (int64, error) {
ID int64 `json:"id"`
}{}

err = c.request("POST", "/api/admin/users", nil, bytes.NewBuffer(data), &created)
err = c.request("POST", "/api/admin/users", nil, data, &created)
if err != nil {
return id, err
}
Expand All @@ -45,7 +44,7 @@ func (c *Client) UpdateUserPassword(id int64, password string) error {
if err != nil {
return err
}
return c.request("PUT", fmt.Sprintf("/api/admin/users/%d/password", id), nil, bytes.NewBuffer(data), nil)
return c.request("PUT", fmt.Sprintf("/api/admin/users/%d/password", id), nil, data, nil)
}

// UpdateUserPermissions sets a user's admin status.
Expand All @@ -55,7 +54,7 @@ func (c *Client) UpdateUserPermissions(id int64, isAdmin bool) error {
if err != nil {
return err
}
return c.request("PUT", fmt.Sprintf("/api/admin/users/%d/permissions", id), nil, bytes.NewBuffer(data), nil)
return c.request("PUT", fmt.Sprintf("/api/admin/users/%d/permissions", id), nil, data, nil)
}

// PauseAllAlerts pauses all Grafana alerts.
Expand All @@ -68,7 +67,7 @@ func (c *Client) PauseAllAlerts() (PauseAllAlertsResponse, error) {
return result, err
}

err = c.request("POST", "/api/admin/pause-all-alerts", nil, bytes.NewBuffer(data), &result)
err = c.request("POST", "/api/admin/pause-all-alerts", nil, data, &result)

return result, err
}
3 changes: 1 addition & 2 deletions alert.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gapi

import (
"bytes"
"encoding/json"
"fmt"
"net/url"
Expand Down Expand Up @@ -68,7 +67,7 @@ func (c *Client) PauseAlert(id int64) (PauseAlertResponse, error) {
return result, err
}

err = c.request("POST", path, nil, bytes.NewBuffer(data), &result)
err = c.request("POST", path, nil, data, &result)
if err != nil {
return result, err
}
Expand Down
7 changes: 3 additions & 4 deletions alerting_alert_rule.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gapi

import (
"bytes"
"encoding/json"
"fmt"
"time"
Expand Down Expand Up @@ -93,7 +92,7 @@ func (c *Client) SetAlertRuleGroup(group RuleGroup) error {
}

uri := fmt.Sprintf("/api/v1/provisioning/folder/%s/rule-groups/%s", folderUID, name)
return c.request("PUT", uri, nil, bytes.NewBuffer(req), nil)
return c.request("PUT", uri, nil, req, nil)
}

// NewAlertRule creates a new alert rule and returns its UID.
Expand All @@ -104,7 +103,7 @@ func (c *Client) NewAlertRule(ar *AlertRule) (string, error) {
return "", err
}
result := AlertRule{}
err = c.request("POST", "/api/v1/provisioning/alert-rules", nil, bytes.NewBuffer(req), &result)
err = c.request("POST", "/api/v1/provisioning/alert-rules", nil, req, &result)
if err != nil {
return "", err
}
Expand All @@ -120,7 +119,7 @@ func (c *Client) UpdateAlertRule(ar *AlertRule) error {
return err
}

return c.request("PUT", uri, nil, bytes.NewBuffer(req), nil)
return c.request("PUT", uri, nil, req, nil)
}

// DeleteAlertRule deletes a alert rule, identified by the alert rule's UID.
Expand Down
5 changes: 2 additions & 3 deletions alerting_contact_point.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gapi

import (
"bytes"
"encoding/json"
"fmt"
"net/url"
Expand Down Expand Up @@ -62,7 +61,7 @@ func (c *Client) NewContactPoint(p *ContactPoint) (string, error) {
}
result := ContactPoint{}

err = c.request("POST", "/api/v1/provisioning/contact-points", nil, bytes.NewBuffer(req), &result)
err = c.request("POST", "/api/v1/provisioning/contact-points", nil, req, &result)
if err != nil {
return "", err
}
Expand All @@ -77,7 +76,7 @@ func (c *Client) UpdateContactPoint(p *ContactPoint) error {
return err
}

return c.request("PUT", uri, nil, bytes.NewBuffer(req), nil)
return c.request("PUT", uri, nil, req, nil)
}

// DeleteContactPoint deletes a contact point.
Expand Down
3 changes: 1 addition & 2 deletions alerting_message_template.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gapi

import (
"bytes"
"encoding/json"
"fmt"
)
Expand Down Expand Up @@ -44,7 +43,7 @@ func (c *Client) SetMessageTemplate(name, content string) error {
}

uri := fmt.Sprintf("/api/v1/provisioning/templates/%s", name)
return c.request("PUT", uri, nil, bytes.NewBuffer(body), nil)
return c.request("PUT", uri, nil, body, nil)
}

// DeleteMessageTemplate deletes a message template.
Expand Down
5 changes: 2 additions & 3 deletions alerting_mute_timing.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gapi

import (
"bytes"
"encoding/json"
"fmt"
)
Expand Down Expand Up @@ -65,7 +64,7 @@ func (c *Client) NewMuteTiming(mt *MuteTiming) error {
return err
}

return c.request("POST", "/api/v1/provisioning/mute-timings", nil, bytes.NewBuffer(req), nil)
return c.request("POST", "/api/v1/provisioning/mute-timings", nil, req, nil)
}

// UpdateMuteTiming updates a mute timing.
Expand All @@ -76,7 +75,7 @@ func (c *Client) UpdateMuteTiming(mt *MuteTiming) error {
return err
}

return c.request("PUT", uri, nil, bytes.NewBuffer(req), nil)
return c.request("PUT", uri, nil, req, nil)
}

// DeleteMutetiming deletes a mute timing.
Expand Down
3 changes: 1 addition & 2 deletions alerting_notification_policy.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gapi

import (
"bytes"
"encoding/json"
"fmt"
)
Expand Down Expand Up @@ -116,7 +115,7 @@ func (c *Client) SetNotificationPolicyTree(np *NotificationPolicyTree) error {
if err != nil {
return err
}
return c.request("PUT", "/api/v1/provisioning/policies", nil, bytes.NewBuffer(req), nil)
return c.request("PUT", "/api/v1/provisioning/policies", nil, req, nil)
}

func (c *Client) ResetNotificationPolicyTree() error {
Expand Down
5 changes: 2 additions & 3 deletions alertnotification.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gapi

import (
"bytes"
"encoding/json"
"fmt"
)
Expand Down Expand Up @@ -59,7 +58,7 @@ func (c *Client) NewAlertNotification(a *AlertNotification) (int64, error) {
ID int64 `json:"id"`
}{}

err = c.request("POST", "/api/alert-notifications", nil, bytes.NewBuffer(data), &result)
err = c.request("POST", "/api/alert-notifications", nil, data, &result)
if err != nil {
return 0, err
}
Expand All @@ -75,7 +74,7 @@ func (c *Client) UpdateAlertNotification(a *AlertNotification) error {
if err != nil {
return err
}
err = c.request("PUT", path, nil, bytes.NewBuffer(data), nil)
err = c.request("PUT", path, nil, data, nil)

return err
}
Expand Down
13 changes: 6 additions & 7 deletions annotation.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gapi

import (
"bytes"
"encoding/json"
"fmt"
"net/url"
Expand Down Expand Up @@ -58,7 +57,7 @@ func (c *Client) NewAnnotation(a *Annotation) (int64, error) {
ID int64 `json:"id"`
}{}

err = c.request("POST", "/api/annotations", nil, bytes.NewBuffer(data), &result)
err = c.request("POST", "/api/annotations", nil, data, &result)
if err != nil {
return 0, err
}
Expand All @@ -77,7 +76,7 @@ func (c *Client) NewGraphiteAnnotation(gfa *GraphiteAnnotation) (int64, error) {
ID int64 `json:"id"`
}{}

err = c.request("POST", "/api/annotations/graphite", nil, bytes.NewBuffer(data), &result)
err = c.request("POST", "/api/annotations/graphite", nil, data, &result)
if err != nil {
return 0, err
}
Expand All @@ -97,7 +96,7 @@ func (c *Client) UpdateAnnotation(id int64, a *Annotation) (string, error) {
Message string `json:"message"`
}{}

err = c.request("PUT", path, nil, bytes.NewBuffer(data), &result)
err = c.request("PUT", path, nil, data, &result)
if err != nil {
return "", err
}
Expand All @@ -117,7 +116,7 @@ func (c *Client) PatchAnnotation(id int64, a *Annotation) (string, error) {
Message string `json:"message"`
}{}

err = c.request("PATCH", path, nil, bytes.NewBuffer(data), &result)
err = c.request("PATCH", path, nil, data, &result)
if err != nil {
return "", err
}
Expand All @@ -132,7 +131,7 @@ func (c *Client) DeleteAnnotation(id int64) (string, error) {
Message string `json:"message"`
}{}

err := c.request("DELETE", path, nil, bytes.NewBuffer(nil), &result)
err := c.request("DELETE", path, nil, nil, &result)
if err != nil {
return "", err
}
Expand All @@ -147,7 +146,7 @@ func (c *Client) DeleteAnnotationByRegionID(id int64) (string, error) {
Message string `json:"message"`
}{}

err := c.request("DELETE", path, nil, bytes.NewBuffer(nil), &result)
err := c.request("DELETE", path, nil, nil, &result)
if err != nil {
return "", err
}
Expand Down
3 changes: 1 addition & 2 deletions api_key.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gapi

import (
"bytes"
"encoding/json"
"fmt"
"net/url"
Expand Down Expand Up @@ -42,7 +41,7 @@ func (c *Client) CreateAPIKey(request CreateAPIKeyRequest) (CreateAPIKeyResponse
return response, err
}

err = c.request("POST", "/api/auth/keys", nil, bytes.NewBuffer(data), &response)
err = c.request("POST", "/api/auth/keys", nil, data, &response)
return response, err
}

Expand Down
5 changes: 2 additions & 3 deletions builtin_role_assignments.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gapi

import (
"bytes"
"encoding/json"
"fmt"
)
Expand Down Expand Up @@ -33,7 +32,7 @@ func (c *Client) NewBuiltInRoleAssignment(builtInRoleAssignment BuiltInRoleAssig

br := &BuiltInRoleAssignment{}

err = c.request("POST", baseURL, nil, bytes.NewBuffer(body), &br)
err = c.request("POST", baseURL, nil, body, &br)
if err != nil {
return nil, err
}
Expand All @@ -52,7 +51,7 @@ func (c *Client) DeleteBuiltInRoleAssignment(builtInRole BuiltInRoleAssignment)
"global": {fmt.Sprint(builtInRole.Global)},
}
url := fmt.Sprintf("%s/%s/roles/%s", baseURL, builtInRole.BuiltinRole, builtInRole.RoleUID)
err = c.request("DELETE", url, qp, bytes.NewBuffer(data), nil)
err = c.request("DELETE", url, qp, data, nil)

return err
}
22 changes: 8 additions & 14 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type Config struct {
OrgID int64
// NumRetries contains the number of attempted retries
NumRetries int
// RetryTimeout says how long to wait before retrying a request
RetryTimeout time.Duration
}

// New creates a new Grafana client.
Expand Down Expand Up @@ -71,35 +73,27 @@ func (c Client) WithOrgID(orgID int64) *Client {
return &c
}

func (c *Client) request(method, requestPath string, query url.Values, body io.Reader, responseStruct interface{}) error {
func (c *Client) request(method, requestPath string, query url.Values, body []byte, responseStruct interface{}) error {
var (
req *http.Request
resp *http.Response
err error
bodyContents []byte
)

// If we want to retry a request that sends data, we'll need to stash the request data in memory. Otherwise, we lose it since readers cannot be replayed.
var bodyBuffer bytes.Buffer
if c.config.NumRetries > 0 && body != nil {
body = io.TeeReader(body, &bodyBuffer)
}

// retry logic
for n := 0; n <= c.config.NumRetries; n++ {
// If it's not the first request, re-use the request body we stashed earlier.
if n > 0 {
body = bytes.NewReader(bodyBuffer.Bytes())
}

req, err = c.newRequest(method, requestPath, query, body)
req, err = c.newRequest(method, requestPath, query, bytes.NewReader(body))
if err != nil {
return err
}

// Wait a bit if that's not the first request
if n != 0 {
time.Sleep(time.Second * 5)
if c.config.RetryTimeout == 0 {
c.config.RetryTimeout = time.Second * 5
}
time.Sleep(c.config.RetryTimeout)
}

resp, err = c.client.Do(req)
Expand Down
Loading