Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: PC-14087 Add SLO Status API to SDK #537

Merged
merged 20 commits into from
Oct 9, 2024
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
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
Loading