Skip to content

Commit

Permalink
feat: PC-14087 Add SLO Status API to SDK (#537)
Browse files Browse the repository at this point in the history
  • Loading branch information
BSski authored Oct 9, 2024
1 parent 1ff0ee1 commit f584589
Show file tree
Hide file tree
Showing 18 changed files with 649 additions and 0 deletions.
1 change: 1 addition & 0 deletions cspell.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ words:
- sloerrorbudgetstatus
- sloname
- slos
- slostatusapi
- sourcetype
- stablebetaalpha
- startuml
Expand Down
5 changes: 5 additions & 0 deletions sdk/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/nobl9/nobl9-go/manifest"
"github.com/nobl9/nobl9-go/sdk/endpoints/authdata"
"github.com/nobl9/nobl9-go/sdk/endpoints/objects"
"github.com/nobl9/nobl9-go/sdk/endpoints/slostatusapi"
)

// ProjectsWildcard is used in HeaderProject when requesting for all projects.
Expand Down Expand Up @@ -88,6 +89,10 @@ func (c *Client) AuthData() authdata.Versions {
return authdata.NewVersions(c)
}

func (c *Client) SLOStatusAPI() slostatusapi.Versions {
return slostatusapi.NewVersions(c)
}

// CreateRequest creates a new http.Request pointing at the Nobl9 API URL.
// It also adds all the mandatory headers to the request and encodes query parameters.
func (c *Client) CreateRequest(
Expand Down
2 changes: 2 additions & 0 deletions sdk/endpoints/slostatusapi/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package slostatusapi provides the API for managing SLO status API requests in the SDK.
package slostatusapi
2 changes: 2 additions & 0 deletions sdk/endpoints/slostatusapi/v1/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package v1 provides the API for managing SLO status API V1 requests in the SDK.
package v1
87 changes: 87 additions & 0 deletions sdk/endpoints/slostatusapi/v1/endpoints.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package v1

import (
"context"
"encoding/json"
"net/http"
"net/url"
"path"
"strconv"

"github.com/pkg/errors"

endpointsHelpers "github.com/nobl9/nobl9-go/internal/endpoints"
"github.com/nobl9/nobl9-go/internal/sdk"
)

const (
baseAPIPath = "v1/slos"
)

//go:generate ../../../../bin/ifacemaker -y " " -f ./*.go -s endpoints -i Endpoints -o endpoints_interface.go -p "$GOPACKAGE"

func NewEndpoints(client endpointsHelpers.Client) Endpoints {
return endpoints{client: client}
}

type endpoints struct {
client endpointsHelpers.Client
}

func (e endpoints) GetSLO(ctx context.Context, project, name string) (slo SLODetails, err error) {
req, err := e.client.CreateRequest(
ctx,
http.MethodGet,
path.Join(baseAPIPath, name),
http.Header{sdk.HeaderProject: {project}},
nil,
nil,
)
if err != nil {
return slo, err
}
resp, err := e.client.Do(req)
if err != nil {
return slo, err
}
defer func() { _ = resp.Body.Close() }()

if err = json.NewDecoder(resp.Body).Decode(&slo); err != nil {
return slo, errors.Wrap(err, "failed to decode response body")
}
return slo, nil
}

func (e endpoints) GetSLOs(ctx context.Context, params GetSLOsRequest) (slos SLOListResponse, err error) {
req, err := e.client.CreateRequest(
ctx,
http.MethodGet,
baseAPIPath,
nil,
url.Values{
QueryKeyLimit: []string{strconv.Itoa(params.Limit)},
QueryKeyCursor: []string{params.Cursor},
},
nil,
)
if err != nil {
return slos, err
}
resp, err := e.client.Do(req)
if err != nil {
return slos, err
}
defer func() { _ = resp.Body.Close() }()

if err = json.NewDecoder(resp.Body).Decode(&slos); err != nil {
return slos, errors.Wrap(err, "failed to decode response body")
}
if slos.Links.Next != "" {
nextURL, err := url.Parse(slos.Links.Next)
if err != nil {
return slos, errors.Wrap(err, "failed to parse 'next' cursor link URL")
}
slos.Links.Cursor = nextURL.Query().Get("cursor")
}
return slos, nil
}
12 changes: 12 additions & 0 deletions sdk/endpoints/slostatusapi/v1/endpoints_interface.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions sdk/endpoints/slostatusapi/v1/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package v1

const (
QueryKeyLimit = "limit"
QueryKeyCursor = "cursor"
)
6 changes: 6 additions & 0 deletions sdk/endpoints/slostatusapi/v1/request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package v1

type GetSLOsRequest struct {
Limit int
Cursor string
}
61 changes: 61 additions & 0 deletions sdk/endpoints/slostatusapi/v1/response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package v1

type SLOListResponse struct {
Data []SLODetails `json:"data"`
Links Links `json:"links"`
}

type Links struct {
Self string `json:"self"`
Next string `json:"next"`
Cursor string `json:"cursor"`
}

type SLODetails struct {
Name string `json:"name"`
DisplayName string `json:"displayName"`
Description string `json:"description"`
Project string `json:"project"`
Service string `json:"service"`
CreatedAt string `json:"createdAt"`
Objectives []Objective `json:"objectives"`
Composite *Composite `json:"composite,omitempty"`
Labels map[string][]string `json:"labels,omitempty"`
Annotations map[string]string `json:"annotations,omitempty"`
BudgetingMethod string `json:"budgetingMethod"`
}

type Objective struct {
Name string `json:"name"`
DisplayName string `json:"displayName"`
Target float64 `json:"target"`
BurnRate *float64 `json:"burnRate,omitempty"`
ErrorBudgetRemaining *float64 `json:"errorBudgetRemaining,omitempty"`
ErrorBudgetRemainingPercentage *float64 `json:"errorBudgetRemainingPercentage,omitempty"`
Reliability *float64 `json:"reliability,omitempty"`
Counts *Counts `json:"counts,omitempty"`
SLIType string `json:"sliType"`
}

type Composite struct {
Target *float64 `json:"target,omitempty"`
BurnRateCondition *BurnRateCondition `json:"burnRateCondition,omitempty"`
CompositeObjective
}

type CompositeObjective struct {
BurnRate *float64 `json:"burnRate,omitempty"`
ErrorBudgetRemaining *float64 `json:"errorBudgetRemaining,omitempty"`
ErrorBudgetRemainingPercentage *float64 `json:"errorBudgetRemainingPercentage,omitempty"`
Reliability *float64 `json:"reliability,omitempty"`
}

type BurnRateCondition struct {
Value float64 `json:"value"`
Operator string `json:"op"`
}

type Counts struct {
Good *float64 `json:"good,omitempty"`
Total *float64 `json:"total,omitempty"`
}
2 changes: 2 additions & 0 deletions sdk/endpoints/slostatusapi/v2/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package v2 provides the API for managing SLO status API V2 requests in the SDK.
package v2
87 changes: 87 additions & 0 deletions sdk/endpoints/slostatusapi/v2/endpoints.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package v2

import (
"context"
"encoding/json"
"net/http"
"net/url"
"path"
"strconv"

"github.com/pkg/errors"

endpointsHelpers "github.com/nobl9/nobl9-go/internal/endpoints"
"github.com/nobl9/nobl9-go/internal/sdk"
)

const (
baseAPIPath = "v2/slos"
)

//go:generate ../../../../bin/ifacemaker -y " " -f ./*.go -s endpoints -i Endpoints -o endpoints_interface.go -p "$GOPACKAGE"

func NewEndpoints(client endpointsHelpers.Client) Endpoints {
return endpoints{client: client}
}

type endpoints struct {
client endpointsHelpers.Client
}

func (e endpoints) GetSLO(ctx context.Context, project, name string) (slo SLODetails, err error) {
req, err := e.client.CreateRequest(
ctx,
http.MethodGet,
path.Join(baseAPIPath, name),
http.Header{sdk.HeaderProject: {project}},
nil,
nil,
)
if err != nil {
return slo, err
}
resp, err := e.client.Do(req)
if err != nil {
return slo, err
}
defer func() { _ = resp.Body.Close() }()

if err = json.NewDecoder(resp.Body).Decode(&slo); err != nil {
return slo, errors.Wrap(err, "failed to decode response body")
}
return slo, nil
}

func (e endpoints) GetSLOs(ctx context.Context, params GetSLOsRequest) (slos SLOListResponse, err error) {
req, err := e.client.CreateRequest(
ctx,
http.MethodGet,
baseAPIPath,
nil,
url.Values{
QueryKeyLimit: []string{strconv.Itoa(params.Limit)},
QueryKeyCursor: []string{params.Cursor},
},
nil,
)
if err != nil {
return slos, err
}
resp, err := e.client.Do(req)
if err != nil {
return slos, err
}
defer func() { _ = resp.Body.Close() }()

if err = json.NewDecoder(resp.Body).Decode(&slos); err != nil {
return slos, errors.Wrap(err, "failed to decode response body")
}
if slos.Links.Next != "" {
nextURL, err := url.Parse(slos.Links.Next)
if err != nil {
return slos, errors.Wrap(err, "failed to parse 'next' cursor link URL")
}
slos.Links.Cursor = nextURL.Query().Get("cursor")
}
return slos, nil
}
12 changes: 12 additions & 0 deletions sdk/endpoints/slostatusapi/v2/endpoints_interface.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions sdk/endpoints/slostatusapi/v2/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package v2

const (
QueryKeyLimit = "limit"
QueryKeyCursor = "cursor"
)
6 changes: 6 additions & 0 deletions sdk/endpoints/slostatusapi/v2/request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package v2

type GetSLOsRequest struct {
Limit int
Cursor string
}
Loading

0 comments on commit f584589

Please sign in to comment.