-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: [PC-13433]: add get Adjustment Events
- Loading branch information
1 parent
925d57d
commit 34b34be
Showing
6 changed files
with
295 additions
and
2 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,12 @@ | ||
# Get Adjustment Events for 'sample-adjustment-name' from 2024-09-23T00:45:00 UTC to 2024-09-23T20:46:00 UTC. | ||
sloctl budgetadjustments get --adjustment-name=sample-adjustment-name --from=2024-09-23T00:45:00Z --to=2024-09-23T20:46:00Z | ||
|
||
|
||
# Get Adjustment Events for 'sample-adjustment-name' from 2024-09-23T00:45:00 UTC to 2024-09-23T20:46:00 UTC | ||
# only for one slo with sloName and project filters. | ||
sloctl budgetadjustments get \ | ||
--adjustment-name=sample-adjustment-name \ | ||
--from=2024-09-23T00:45:00Z \ | ||
--to=2024-09-23T20:46:00Z \ | ||
--project=sample-project-name \ | ||
--slo-name=sample-slo-name |
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,96 @@ | ||
package budgetadjustments | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/spf13/cobra" | ||
|
||
"github.com/nobl9/sloctl/internal/csv" | ||
) | ||
|
||
const ( | ||
flagAdjustment = "adjustment-name" | ||
flagFrom = "from" | ||
flagTo = "to" | ||
flagProject = "project" | ||
flagSloName = "slo-name" | ||
) | ||
|
||
func registerOutputFormatFlags( | ||
cmd *cobra.Command, | ||
outputFormat, fieldSeparator, recordSeparator *string, | ||
) { | ||
cmd.PersistentFlags().StringVarP(outputFormat, "output", "o", "yaml", | ||
`Output format: one of yaml|json|csv.`) | ||
|
||
cmd.PersistentFlags().StringVarP(fieldSeparator, csv.FieldSeparatorFlag, "", | ||
csv.DefaultFieldSeparator, "Field Separator for CSV.") | ||
|
||
cmd.PersistentFlags().StringVarP(recordSeparator, csv.RecordSeparatorFlag, "", | ||
csv.DefaultRecordSeparator, "Record Separator for CSV.") | ||
|
||
if err := cmd.PersistentFlags().MarkHidden(csv.RecordSeparatorFlag); err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
func registerAdjustmentFlag(cmd *cobra.Command, storeIn *string) { | ||
cmd.Flags().StringVar(storeIn, flagAdjustment, "", "Name of the Adjustment.") | ||
if err := cmd.MarkFlagRequired(flagAdjustment); err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
func registerProjectFlag(cmd *cobra.Command, storeIn *string) { | ||
cmd.Flags().StringVarP(storeIn, flagProject, "", "", | ||
"Name of the project. Required when sloName is defined.") | ||
} | ||
|
||
func registerSloNameFlag(cmd *cobra.Command, storeIn *string) { | ||
cmd.Flags().StringVarP(storeIn, flagSloName, "", "", | ||
"Name of the SLO. Required when sloName is defined.") | ||
} | ||
|
||
type TimeValue struct{ time.Time } | ||
|
||
const ( | ||
timeLayout = time.RFC3339 | ||
timeLayoutString = "RFC3339" | ||
) | ||
|
||
func (t *TimeValue) String() string { | ||
if t.IsZero() { | ||
return "" | ||
} | ||
return t.Format(timeLayout) | ||
} | ||
|
||
func (t *TimeValue) Set(s string) (err error) { | ||
t.Time, err = time.Parse(timeLayout, s) | ||
return | ||
} | ||
|
||
func (t *TimeValue) Type() string { | ||
return "time" | ||
} | ||
|
||
func registerFromFlag( | ||
cmd *cobra.Command, | ||
storeIn *TimeValue, | ||
) { | ||
cmd.Flags(). | ||
Var(storeIn, flagFrom, "Specifies the start date and time for the data range (in UTC).") | ||
if err := cmd.MarkFlagRequired(flagFrom); err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
func registerToFlag( | ||
cmd *cobra.Command, | ||
storeIn *TimeValue, | ||
) { | ||
cmd.Flags().Var(storeIn, flagTo, "Specifies the end date and time for the data range (in UTC).") | ||
if err := cmd.MarkFlagRequired(flagTo); err != nil { | ||
panic(err) | ||
} | ||
} |
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,129 @@ | ||
package budgetadjustments | ||
|
||
import ( | ||
_ "embed" | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"net/http" | ||
"net/url" | ||
"os" | ||
"time" | ||
|
||
"github.com/nobl9/nobl9-go/sdk" | ||
"github.com/pkg/errors" | ||
"github.com/spf13/cobra" | ||
|
||
"github.com/nobl9/sloctl/internal/printer" | ||
) | ||
|
||
type GetCmd struct { | ||
client *sdk.Client | ||
filepath string | ||
dryRun bool | ||
outputFormat string | ||
fieldSeparator string | ||
recordSeparator string | ||
out io.Writer | ||
adjustment string | ||
from, to TimeValue | ||
project, sloName string | ||
} | ||
|
||
type SLO struct { | ||
Project string `json:"project" validate:"required"` | ||
Name string `json:"name" validate:"required"` | ||
} | ||
|
||
type Event struct { | ||
EventStart time.Time `json:"eventStart"` | ||
EventEnd time.Time `json:"eventEnd"` | ||
Slos []SLO `json:"slos"` | ||
} | ||
|
||
//go:embed examples/get_example.sh | ||
var example string | ||
|
||
func NewGetCmd(client *sdk.Client) *cobra.Command { | ||
get := &GetCmd{out: os.Stdout} | ||
|
||
cmd := &cobra.Command{ | ||
Use: "get", | ||
Short: "Return a list of events for given Adjustment with related SLOs.", | ||
Long: "This endpoint only return past and ongoing events (events that are already started)." + | ||
"Please see Editing budget adjustments." + | ||
"Maximum 500 events can be returned." + | ||
"Optional filtering for specific SLO (only one). If SLO is defined we will return only events for that SLO and the result will also include other SLOs that this events have. Sorted by eventStart.", | ||
Example: example, | ||
PersistentPreRun: func(cmd *cobra.Command, args []string) { | ||
get.client = client | ||
project, _ := cmd.Flags().GetString(flagProject) | ||
sloName, _ := cmd.Flags().GetString(flagSloName) | ||
if project != "" { | ||
cmd.MarkFlagRequired(flagSloName) | ||
} | ||
if sloName != "" { | ||
cmd.MarkFlagRequired(flagProject) | ||
} | ||
}, | ||
RunE: func(cmd *cobra.Command, args []string) error { return get.run(cmd) }, | ||
} | ||
|
||
registerOutputFormatFlags(cmd, &get.outputFormat, &get.fieldSeparator, &get.recordSeparator) | ||
registerAdjustmentFlag(cmd, &get.adjustment) | ||
registerProjectFlag(cmd, &get.project) | ||
registerSloNameFlag(cmd, &get.sloName) | ||
registerFromFlag(cmd, &get.from) | ||
registerToFlag(cmd, &get.to) | ||
|
||
return cmd | ||
} | ||
|
||
func (g *GetCmd) run(cmd *cobra.Command) error { | ||
if g.dryRun { | ||
g.client.WithDryRun() | ||
} | ||
values := url.Values{"from": {g.from.String()}, "to": {g.to.String()}} | ||
if g.sloName != "" { | ||
values.Add("sloName", g.sloName) | ||
} | ||
if g.project != "" { | ||
values.Add("project", g.project) | ||
} | ||
|
||
resBody, err := doRequest( | ||
g.client, | ||
cmd.Context(), | ||
http.MethodGet, | ||
fmt.Sprintf("%s/%s/events", budgetAdjustmentAPI, g.adjustment), | ||
values, | ||
) | ||
if err != nil { | ||
return errors.Wrap(err, "failed to get") | ||
} | ||
|
||
var events []Event | ||
if err := json.Unmarshal(resBody, &events); err != nil { | ||
return errors.Wrap(err, "failed parse response") | ||
} | ||
|
||
g.printObjects(events) | ||
|
||
return nil | ||
} | ||
|
||
func (g *GetCmd) printObjects(objects interface{}) error { | ||
p, err := printer.New( | ||
g.out, | ||
printer.Format(g.outputFormat), | ||
g.fieldSeparator, | ||
g.recordSeparator, | ||
) | ||
if err != nil { | ||
return err | ||
} | ||
if err = p.Print(objects); err != nil { | ||
return err | ||
} | ||
return 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,35 @@ | ||
package budgetadjustments | ||
|
||
import ( | ||
"context" | ||
_ "embed" | ||
"io" | ||
"net/url" | ||
|
||
"github.com/nobl9/nobl9-go/sdk" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
const budgetAdjustmentAPI = "/v1/budgetadjustments" | ||
|
||
func doRequest( | ||
client *sdk.Client, | ||
ctx context.Context, | ||
method, endpoint string, | ||
values url.Values, | ||
) ([]byte, error) { | ||
req, err := client.CreateRequest(ctx, method, endpoint, nil, values, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
resp, err := client.HTTP.Do(req) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer func() { _ = resp.Body.Close() }() | ||
if resp.StatusCode >= 300 { | ||
data, _ := io.ReadAll(resp.Body) | ||
return nil, errors.Errorf("bad response (status: %d): %s", resp.StatusCode, string(data)) | ||
} | ||
return io.ReadAll(resp.Body) | ||
} |
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,19 @@ | ||
package budgetadjustments | ||
|
||
import ( | ||
_ "embed" | ||
"fmt" | ||
|
||
"github.com/nobl9/nobl9-go/sdk" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
func NewRootCmd(client *sdk.Client) *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "budgetadjustments", | ||
Short: "Manage budgetadjustment.", | ||
} | ||
cmd.PersistentFlags().BoolP("help", "h", false, fmt.Sprintf("Help for %s.", cmd.Name())) | ||
cmd.AddCommand(NewGetCmd(client)) | ||
return cmd | ||
} |
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