-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(usage-view): download usage data in csv format
Signed-off-by: Michal Wasilewski <[email protected]>
- Loading branch information
Showing
5 changed files
with
238 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
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
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
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
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,103 @@ | ||
package profile | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"io" | ||
"log" | ||
"net/http" | ||
"os" | ||
|
||
"github.com/urfave/cli/v2" | ||
|
||
"github.com/spacelift-io/spacectl/internal/cmd" | ||
"github.com/spacelift-io/spacectl/internal/cmd/authenticated" | ||
) | ||
|
||
type queryArgs struct { | ||
since string | ||
until string | ||
aspect string | ||
groupBy string | ||
} | ||
|
||
func usageViewCSVCommand() *cli.Command { | ||
return &cli.Command{ | ||
Name: "usage-view-csv", | ||
Usage: "Prints CSV with usage data for the current account", | ||
ArgsUsage: cmd.EmptyArgsUsage, | ||
Flags: []cli.Flag{ | ||
flagUsageViewCSVSince, | ||
flagUsageViewCSVUntil, | ||
flagUsageViewCSVAspect, | ||
flagUsageViewCSVGroupBy, | ||
flagUsageViewCSVFile, | ||
}, | ||
Before: authenticated.Ensure, | ||
Action: func(ctx *cli.Context) error { | ||
// prep http query | ||
args := &queryArgs{ | ||
since: ctx.String(flagUsageViewCSVSince.Name), | ||
until: ctx.String(flagUsageViewCSVUntil.Name), | ||
aspect: ctx.String(flagUsageViewCSVAspect.Name), | ||
groupBy: ctx.String(flagUsageViewCSVGroupBy.Name), | ||
} | ||
params := buildQueryParams(args) | ||
req, err := http.NewRequestWithContext(ctx.Context, http.MethodGet, "/usageanalytics/csv", nil) | ||
if err != nil { | ||
return fmt.Errorf("failed to create an HTTP request: %w", err) | ||
} | ||
q := req.URL.Query() | ||
for k, v := range params { | ||
q.Add(k, v) | ||
} | ||
req.URL.RawQuery = q.Encode() | ||
|
||
// execute http query | ||
log.Println("Querying Spacelift for usage data...") | ||
resp, err := authenticated.Client.Do(req) | ||
if err != nil { | ||
return err | ||
} | ||
defer resp.Body.Close() | ||
if resp.StatusCode != http.StatusOK { | ||
return fmt.Errorf("unexpected status code: %d", resp.StatusCode) | ||
} | ||
|
||
// save response to a file | ||
var filename string | ||
if !ctx.IsSet(flagUsageViewCSVFile.Name) { | ||
filename = fmt.Sprintf("usage-%s-%s-%s.csv", args.aspect, args.since, args.until) | ||
} else { | ||
filename = ctx.String(flagUsageViewCSVFile.Name) | ||
} | ||
fd, err := os.OpenFile("./"+filename, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0644) | ||
Check failure Code scanning / gosec Potential file inclusion via variable Error
Potential file inclusion via variable
Check failure Code scanning / gosec Expect file permissions to be 0600 or less Error
Expect file permissions to be 0600 or less
|
||
if err != nil { | ||
return fmt.Errorf("failed to open a file descriptor: %w", err) | ||
} | ||
defer fd.Close() | ||
bfd := bufio.NewWriter(fd) | ||
defer bfd.Flush() | ||
_, err = io.Copy(bfd, resp.Body) | ||
if err != nil { | ||
return fmt.Errorf("failed to write the response to a file: %w", err) | ||
} | ||
log.Println("Usage data saved to", filename) | ||
return nil | ||
}, | ||
} | ||
} | ||
|
||
func buildQueryParams(args *queryArgs) map[string]string { | ||
params := make(map[string]string) | ||
|
||
params["since"] = args.since | ||
params["until"] = args.until | ||
params["aspect"] = args.aspect | ||
|
||
if args.aspect == "run-minutes" { | ||
params["groupBy"] = args.groupBy | ||
} | ||
|
||
return params | ||
} |