-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
slo: add methods related to slo resource
- Loading branch information
Showing
7 changed files
with
526 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package signalfx | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"github.com/signalfx/signalfx-go/slo" | ||
"io" | ||
"net/http" | ||
) | ||
|
||
const SloAPIURL = "/v2/slo" | ||
|
||
func (c *Client) GetSlo(ctx context.Context, id string) (*slo.SloObject, error) { | ||
return c.executeSloRequest(ctx, SloAPIURL+"/"+id, http.MethodGet, http.StatusOK, nil) | ||
} | ||
|
||
func (c *Client) CreateSlo(ctx context.Context, sloRequest *slo.SloObject) (*slo.SloObject, error) { | ||
return c.executeSloRequest(ctx, SloAPIURL, http.MethodPost, http.StatusOK, sloRequest) | ||
} | ||
|
||
func (c *Client) ValidateSlo(ctx context.Context, sloRequest *slo.SloObject) error { | ||
_, err := c.executeSloRequest(ctx, SloAPIURL+"/validate", http.MethodPost, http.StatusNoContent, sloRequest) | ||
return err | ||
} | ||
|
||
func (c *Client) UpdateSlo(ctx context.Context, id string, sloRequest *slo.SloObject) (*slo.SloObject, error) { | ||
return c.executeSloRequest(ctx, SloAPIURL+"/"+id, http.MethodPut, http.StatusOK, sloRequest) | ||
} | ||
|
||
func (c *Client) DeleteSlo(ctx context.Context, id string) error { | ||
_, err := c.executeSloRequest(ctx, SloAPIURL+"/"+id, http.MethodDelete, http.StatusNoContent, nil) | ||
return err | ||
} | ||
|
||
func (c *Client) executeSloRequest(ctx context.Context, url string, method string, expectedValidStatus int, sloRequest *slo.SloObject) (*slo.SloObject, error) { | ||
var body io.Reader | ||
|
||
if sloRequest != nil { | ||
payload, err := json.Marshal(sloRequest) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
body = bytes.NewReader(payload) | ||
} | ||
|
||
resp, err := c.doRequest(ctx, method, url, nil, body) | ||
if resp != nil { | ||
defer resp.Body.Close() | ||
} | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if resp.StatusCode != expectedValidStatus { | ||
message, _ := io.ReadAll(resp.Body) | ||
return nil, fmt.Errorf("Bad status %d: %s", resp.StatusCode, message) | ||
} | ||
|
||
if resp.Body != nil { | ||
returnedSlo := &slo.SloObject{} | ||
err = json.NewDecoder(resp.Body).Decode(returnedSlo) | ||
return returnedSlo, nil | ||
} else { | ||
_, _ = io.Copy(io.Discard, resp.Body) | ||
return nil, nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package slo | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"github.com/signalfx/signalfx-go/detector" | ||
) | ||
|
||
const ( | ||
BreachRule = "BREACH" | ||
ErrorBudgetLeftRule = "ERROR_BUDGET_LEFT" | ||
BurnRateRule = "BURN_RATE" | ||
) | ||
|
||
type BreachSloAlertRule struct { | ||
Rules []*BreachDetectorRule `json:"rules,omitempty"` | ||
} | ||
|
||
type BreachDetectorRule struct { | ||
detector.Rule | ||
Parameters *BreachDetectorParameters `json:"parameters,omitempty"` | ||
} | ||
|
||
type BreachDetectorParameters struct { | ||
FireLasting string `json:"fireLasting,omitempty"` | ||
PercentOfLasting float64 `json:"percentOfLasting,omitempty"` | ||
} | ||
|
||
type ErrorBudgetLeftSloAlertRule struct { | ||
Rules []*ErrorBudgetLeftDetectorRule `json:"rules,omitempty"` | ||
} | ||
|
||
type ErrorBudgetLeftDetectorRule struct { | ||
detector.Rule | ||
Parameters *ErrorBudgetLeftDetectorParameters `json:"parameters,omitempty"` | ||
} | ||
|
||
type ErrorBudgetLeftDetectorParameters struct { | ||
FireLasting string `json:"fireLasting,omitempty"` | ||
PercentOfLasting float64 `json:"percentOfLasting,omitempty"` | ||
PercentErrorBudgetLeft float64 `json:"percentErrorBudgetLeft,omitempty"` | ||
} | ||
|
||
type BurnRateSloAlertRule struct { | ||
Rules []*BurnRateDetectorRule `json:"rules,omitempty"` | ||
} | ||
|
||
type BurnRateDetectorRule struct { | ||
detector.Rule | ||
Parameters *BurnRateDetectorParameters `json:"parameters,omitempty"` | ||
} | ||
|
||
type BurnRateDetectorParameters struct { | ||
ShortWindow1 string `json:"shortWindow1,omitempty"` | ||
LongWindow1 string `json:"longWindow1,omitempty"` | ||
ShortWindow2 string `json:"shortWindow2,omitempty"` | ||
LongWindow2 string `json:"longWindow2,omitempty"` | ||
BurnRateThreshold1 float64 `json:"burnRateThreshold1,omitempty"` | ||
BurnRateThreshold2 float64 `json:"burnRateThreshold2,omitempty"` | ||
} | ||
|
||
type BaseSloAlertRule struct { | ||
Type string `json:"type,omitempty"` | ||
} | ||
|
||
type SloAlertRule struct { | ||
BaseSloAlertRule | ||
*BreachSloAlertRule | ||
*ErrorBudgetLeftSloAlertRule | ||
*BurnRateSloAlertRule | ||
} | ||
|
||
func (rule *SloAlertRule) UnmarshalJSON(data []byte) error { | ||
if err := json.Unmarshal(data, &rule.BaseSloAlertRule); err != nil { | ||
return err | ||
} | ||
switch rule.Type { | ||
case BreachRule: | ||
rule.BreachSloAlertRule = &BreachSloAlertRule{} | ||
return json.Unmarshal(data, rule.BreachSloAlertRule) | ||
case ErrorBudgetLeftRule: | ||
rule.ErrorBudgetLeftSloAlertRule = &ErrorBudgetLeftSloAlertRule{} | ||
return json.Unmarshal(data, rule.ErrorBudgetLeftSloAlertRule) | ||
case BurnRateRule: | ||
rule.BurnRateSloAlertRule = &BurnRateSloAlertRule{} | ||
return json.Unmarshal(data, rule.BurnRateSloAlertRule) | ||
default: | ||
return fmt.Errorf("unrecognized SLO alert rule type %s", rule.Type) | ||
} | ||
} | ||
|
||
func (rule *SloAlertRule) MarshalJSON() ([]byte, error) { | ||
switch rule.Type { | ||
case BreachRule: | ||
return json.Marshal(struct { | ||
BaseSloAlertRule | ||
*BreachSloAlertRule | ||
}{rule.BaseSloAlertRule, rule.BreachSloAlertRule}) | ||
case ErrorBudgetLeftRule: | ||
return json.Marshal(struct { | ||
BaseSloAlertRule | ||
*ErrorBudgetLeftSloAlertRule | ||
}{rule.BaseSloAlertRule, rule.ErrorBudgetLeftSloAlertRule}) | ||
case BurnRateRule: | ||
return json.Marshal(struct { | ||
BaseSloAlertRule | ||
*BurnRateSloAlertRule | ||
}{rule.BaseSloAlertRule, rule.BurnRateSloAlertRule}) | ||
default: | ||
return nil, fmt.Errorf("unrecognized SLO alert rule type %s", rule.Type) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package slo | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
) | ||
|
||
const ( | ||
RequestBased = "RequestBased" | ||
WindowsBased = "WindowsBased" | ||
) | ||
|
||
type BaseSlo struct { | ||
Creator string `json:"creator,omitempty"` | ||
LastUpdatedBy string `json:"lastUpdatedBy,omitempty"` | ||
Created int64 `json:"created,omitempty"` | ||
LastUpdated int64 `json:"lastUpdated,omitempty"` | ||
Id string `json:"id,omitempty"` | ||
Name string `json:"name,omitempty"` | ||
Description string `json:"description,omitempty"` | ||
Targets []SloTarget `json:"targets,omitempty"` | ||
Type string `json:"type,omitempty"` | ||
Metadata []string `json:"metadata,omitempty"` | ||
} | ||
|
||
type SloObject struct { | ||
BaseSlo | ||
*RequestBasedSlo | ||
*WindowBasedSlo | ||
} | ||
|
||
type RequestBasedSlo struct { | ||
Inputs *RequestBasedSloInput `json:"inputs,omitempty"` | ||
} | ||
|
||
type WindowBasedSlo struct { | ||
Inputs *WindowBasedSloInput `json:"inputs,omitempty"` | ||
} | ||
|
||
type RequestBasedSloInput struct { | ||
ProgramText string `json:"programText,omitempty"` | ||
GoodEventsLabel string `json:"goodEventsLabel,omitempty"` | ||
TotalEventsLabel string `json:"totalEventsLabel,omitempty"` | ||
} | ||
|
||
type WindowBasedSloInput struct { | ||
ProgramText string `json:"programText,omitempty"` | ||
} | ||
|
||
func (slo *SloObject) UnmarshalJSON(data []byte) error { | ||
if err := json.Unmarshal(data, &slo.BaseSlo); err != nil { | ||
return err | ||
} | ||
switch slo.Type { | ||
case RequestBased: | ||
slo.RequestBasedSlo = &RequestBasedSlo{} | ||
return json.Unmarshal(data, slo.RequestBasedSlo) | ||
case WindowsBased: | ||
slo.WindowBasedSlo = &WindowBasedSlo{} | ||
return json.Unmarshal(data, slo.WindowBasedSlo) | ||
default: | ||
return fmt.Errorf("unrecognized SLO type %s", slo.Type) | ||
} | ||
} | ||
|
||
func (slo SloObject) MarshalJSON() ([]byte, error) { | ||
switch slo.Type { | ||
case RequestBased: | ||
return json.Marshal(struct { | ||
BaseSlo | ||
*RequestBasedSlo | ||
}{slo.BaseSlo, slo.RequestBasedSlo}) | ||
case WindowsBased: | ||
return json.Marshal(struct { | ||
BaseSlo | ||
*WindowBasedSlo | ||
}{slo.BaseSlo, slo.WindowBasedSlo}) | ||
default: | ||
return nil, fmt.Errorf("unrecognized SLO type %s", slo.Type) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package slo | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
) | ||
|
||
const ( | ||
RollingWindowTarget = "RollingWindow" | ||
CalendarWindowTarget = "CalendarWindow" | ||
) | ||
|
||
type SloTarget struct { | ||
BaseSloTarget | ||
*RollingWindowSloTarget | ||
*CalendarWindowSloTarget | ||
} | ||
|
||
type BaseSloTarget struct { | ||
Slo float64 `json:"slo,omitempty"` | ||
SloAlertRules []SloAlertRule `json:"sloAlertRules,omitempty"` | ||
Type string `json:"type,omitempty"` | ||
} | ||
|
||
type RollingWindowSloTarget struct { | ||
CompliancePeriod string `json:"compliancePeriod,omitempty"` | ||
} | ||
|
||
type CalendarWindowSloTarget struct { | ||
CycleType string `json:"cycleType,omitempty"` | ||
CycleStart string `json:"cycleStart,omitempty"` | ||
} | ||
|
||
func (target *SloTarget) UnmarshalJSON(data []byte) error { | ||
if err := json.Unmarshal(data, &target.BaseSloTarget); err != nil { | ||
return err | ||
} | ||
switch target.Type { | ||
case RollingWindowTarget: | ||
target.RollingWindowSloTarget = &RollingWindowSloTarget{} | ||
return json.Unmarshal(data, target.RollingWindowSloTarget) | ||
case CalendarWindowTarget: | ||
target.CalendarWindowSloTarget = &CalendarWindowSloTarget{} | ||
return json.Unmarshal(data, target.CalendarWindowSloTarget) | ||
default: | ||
return fmt.Errorf("unrecognized SLO target type %s", target.Type) | ||
} | ||
} | ||
|
||
func (target *SloTarget) MarshalJSON() ([]byte, error) { | ||
switch target.Type { | ||
case RollingWindowTarget: | ||
return json.Marshal(struct { | ||
BaseSloTarget | ||
*RollingWindowSloTarget | ||
}{target.BaseSloTarget, target.RollingWindowSloTarget}) | ||
case CalendarWindowTarget: | ||
return json.Marshal(struct { | ||
BaseSloTarget | ||
*CalendarWindowSloTarget | ||
}{target.BaseSloTarget, target.CalendarWindowSloTarget}) | ||
default: | ||
return nil, fmt.Errorf("unrecognized SLO target type %s", target.Type) | ||
} | ||
} |
Oops, something went wrong.