Skip to content

Commit 8be6526

Browse files
authored
feat(cli): add entropy cli commands (#53)
* feat: add resource commands * fix: forbidigo linter to ignore cli * feat: add action & logs cmds * fix: lint issues * fix: remove context, goroutine etc * feat: add yaml output & args support * fix: remove UseEnumNumbers from MarshalOptions * feat: add groupig & usage details * chore: change filePath flag to file * fix: allow only json & yaml output * fix: error handling in default case
1 parent bf4ba7e commit 8be6526

11 files changed

+607
-8
lines changed

.golangci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,5 +130,9 @@ issues:
130130
linters:
131131
- gocritic
132132
- dupl
133+
- path: cli
134+
linters:
135+
- forbidigo
136+
- contextcheck
133137
severity:
134138
default-severity: error

cli/action.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/odpf/salt/term" //nolint
7+
entropyv1beta1 "go.buf.build/odpf/gwv/odpf/proton/odpf/entropy/v1beta1"
8+
"google.golang.org/protobuf/types/known/structpb"
9+
10+
"github.com/MakeNowJust/heredoc"
11+
"github.com/odpf/salt/printer"
12+
"github.com/spf13/cobra"
13+
)
14+
15+
func cmdAction() *cobra.Command {
16+
var urn, file, output string
17+
var params *structpb.Value
18+
cmd := &cobra.Command{
19+
Use: "action <action-name>",
20+
Aliases: []string{"action"},
21+
Short: "Manage actions",
22+
Example: heredoc.Doc(`
23+
$ entropy action start --urn=<resource-urn> --file=<file-path> --out=json
24+
`),
25+
Annotations: map[string]string{
26+
"group:core": "true",
27+
},
28+
Args: cobra.ExactArgs(1),
29+
RunE: func(cmd *cobra.Command, args []string) error {
30+
spinner := printer.Spin("")
31+
defer spinner.Stop()
32+
cs := term.NewColorScheme()
33+
34+
var reqBody entropyv1beta1.ApplyActionRequest
35+
if file != "" {
36+
if err := parseFile(file, params); err != nil {
37+
return err
38+
}
39+
reqBody.Params = params
40+
}
41+
42+
reqBody.Urn = urn
43+
reqBody.Action = args[0]
44+
45+
err := reqBody.ValidateAll()
46+
if err != nil {
47+
return err
48+
}
49+
50+
client, cancel, err := createClient(cmd)
51+
if err != nil {
52+
return err
53+
}
54+
defer cancel()
55+
56+
res, err := client.ApplyAction(cmd.Context(), &reqBody)
57+
if err != nil {
58+
return err
59+
}
60+
spinner.Stop()
61+
62+
fmt.Println(cs.Greenf("Action applied successfully"))
63+
if output == outputJSON || output == outputYAML || output == outputYML {
64+
formattedString, err := formatOutput(res.GetResource(), output)
65+
if err != nil {
66+
return err
67+
}
68+
fmt.Println(cs.Bluef(formattedString))
69+
}
70+
71+
return nil
72+
},
73+
}
74+
75+
cmd.Flags().StringVarP(&urn, "urn", "u", "", "urn of the resource")
76+
cmd.Flags().StringVarP(&file, "file", "f", "", "path to the params file")
77+
cmd.Flags().StringVarP(&output, "out", "o", "", "output format, `-o json | yaml`")
78+
79+
return cmd
80+
}

cli/cli.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@ familiar languages, tools, and engineering practices.`,
1717
func Execute(ctx context.Context) {
1818
rootCmd.PersistentFlags().StringP(configFlag, "c", "", "Override config file")
1919
rootCmd.AddCommand(
20-
cmdServe(ctx),
21-
cmdMigrate(ctx),
20+
cmdServe(),
21+
cmdMigrate(),
2222
cmdVersion(),
2323
cmdShowConfigs(),
24+
cmdResource(),
25+
cmdAction(),
26+
cmdLogs(),
2427
)
2528

2629
cmdx.SetHelp(rootCmd)
27-
_ = rootCmd.Execute()
30+
_ = rootCmd.ExecuteContext(ctx)
2831
}

cli/client.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
"strconv"
6+
"time"
7+
8+
"github.com/spf13/cobra"
9+
entropyv1beta1 "go.buf.build/odpf/gwv/odpf/proton/odpf/entropy/v1beta1"
10+
"google.golang.org/grpc"
11+
"google.golang.org/grpc/credentials/insecure"
12+
)
13+
14+
const timeout = 2
15+
16+
func createConnection(ctx context.Context, host string) (*grpc.ClientConn, error) {
17+
opts := []grpc.DialOption{
18+
grpc.WithTransportCredentials(insecure.NewCredentials()),
19+
grpc.WithBlock(),
20+
}
21+
22+
return grpc.DialContext(ctx, host, opts...)
23+
}
24+
25+
func createClient(cmd *cobra.Command) (entropyv1beta1.ResourceServiceClient, func(), error) {
26+
c, err := loadConfig(cmd)
27+
if err != nil {
28+
return nil, nil, err
29+
}
30+
31+
host := c.Service.Host + ":" + strconv.Itoa(c.Service.Port)
32+
33+
dialTimeoutCtx, dialCancel := context.WithTimeout(cmd.Context(), time.Second*timeout)
34+
conn, err := createConnection(dialTimeoutCtx, host)
35+
if err != nil {
36+
dialCancel()
37+
return nil, nil, err
38+
}
39+
40+
cancel := func() {
41+
dialCancel()
42+
conn.Close()
43+
}
44+
45+
client := entropyv1beta1.NewResourceServiceClient(conn)
46+
return client, cancel, nil
47+
}

cli/logs.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package cli
2+
3+
import (
4+
"errors"
5+
"io"
6+
"log"
7+
"strings"
8+
9+
"github.com/odpf/salt/term" //nolint
10+
entropyv1beta1 "go.buf.build/odpf/gwv/odpf/proton/odpf/entropy/v1beta1"
11+
12+
"github.com/MakeNowJust/heredoc"
13+
"github.com/odpf/salt/printer"
14+
"github.com/spf13/cobra"
15+
)
16+
17+
func cmdLogs() *cobra.Command {
18+
var filter []string
19+
filters := make(map[string]string)
20+
cmd := &cobra.Command{
21+
Use: "logs <resource-urn>",
22+
Aliases: []string{"logs"},
23+
Short: "Gets logs",
24+
Example: heredoc.Doc(`
25+
$ entropy logs <resource-urn> --filter="key1=value1" --filter="key2=value2"
26+
`),
27+
Annotations: map[string]string{
28+
"group:core": "true",
29+
},
30+
Args: cobra.ExactArgs(1),
31+
RunE: func(cmd *cobra.Command, args []string) error {
32+
spinner := printer.Spin("")
33+
defer spinner.Stop()
34+
cs := term.NewColorScheme()
35+
36+
client, cancel, err := createClient(cmd)
37+
if err != nil {
38+
return err
39+
}
40+
defer cancel()
41+
42+
var reqBody entropyv1beta1.GetLogRequest
43+
for _, f := range filter {
44+
keyValue := strings.Split(f, "=")
45+
filters[keyValue[0]] = keyValue[1]
46+
}
47+
48+
reqBody.Filter = filters
49+
reqBody.Urn = args[0]
50+
51+
err = reqBody.ValidateAll()
52+
if err != nil {
53+
return err
54+
}
55+
56+
stream, err := client.GetLog(cmd.Context(), &reqBody)
57+
if err != nil {
58+
return err
59+
}
60+
spinner.Stop()
61+
62+
for {
63+
resp, err := stream.Recv()
64+
if errors.Is(err, io.EOF) {
65+
break
66+
}
67+
if err != nil {
68+
log.Fatalf("cannot receive %v", err)
69+
}
70+
log.SetFlags(0)
71+
log.Printf(cs.Bluef("%s", resp.GetChunk().GetData())) //nolint
72+
}
73+
74+
return nil
75+
},
76+
}
77+
78+
cmd.Flags().StringArrayVarP(&filter, "filter", "f", nil, "Use filters. Example: --filter=\"key=value\"")
79+
80+
return cmd
81+
}

cli/migrate.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ import (
88
"github.com/odpf/entropy/internal/store/mongodb"
99
)
1010

11-
func cmdMigrate(ctx context.Context) *cobra.Command {
11+
func cmdMigrate() *cobra.Command {
1212
cmd := &cobra.Command{
1313
Use: "migrate",
1414
Short: "Run DB migrations",
15+
Annotations: map[string]string{
16+
"group:other": "server",
17+
},
1518
}
1619

1720
cmd.RunE = func(cmd *cobra.Command, args []string) error {
@@ -20,7 +23,7 @@ func cmdMigrate(ctx context.Context) *cobra.Command {
2023
return err
2124
}
2225

23-
return runMigrations(ctx, cfg.DB)
26+
return runMigrations(cmd.Context(), cfg.DB)
2427
}
2528

2629
return cmd

0 commit comments

Comments
 (0)