From cfd6ecd8f2c2e69093041a50642514b541e74311 Mon Sep 17 00:00:00 2001 From: Muhammad Abduh Date: Fri, 9 Sep 2022 10:52:10 +0700 Subject: [PATCH 1/2] feat!: improve client config cli and rearrange cmd --- cli/alert.go | 22 +++++-- cli/{grpc.go => client.go} | 23 +++++++ cli/config.go | 83 +++++++++++------------ cli/errors.go | 14 ++++ cli/help.go | 13 ++++ cli/migrate.go | 39 ----------- cli/namespace.go | 108 +++++++++++++++++++++++------- cli/provider.go | 107 +++++++++++++++++++++++------- cli/receiver.go | 127 ++++++++++++++++++++++++++++-------- cli/root.go | 55 +++++++++------- cli/rule.go | 67 +++++++++++++++---- cli/{serve.go => server.go} | 98 +++++++++++++++++++++++++--- cli/template.go | 120 +++++++++++++++++++++++++++------- config/config.go | 12 ++-- config/config.yaml | 5 +- config/init.go | 25 +++++++ go.mod | 4 +- go.sum | 14 +++- main.go | 7 +- pkg/cortex/config.go | 6 +- pkg/telemetry/telemetry.go | 6 +- 21 files changed, 706 insertions(+), 249 deletions(-) rename cli/{grpc.go => client.go} (61%) create mode 100644 cli/errors.go create mode 100644 cli/help.go delete mode 100644 cli/migrate.go rename cli/{serve.go => server.go} (68%) create mode 100644 config/init.go diff --git a/cli/alert.go b/cli/alert.go index 616b855d..2e43dd0a 100644 --- a/cli/alert.go +++ b/cli/alert.go @@ -1,19 +1,19 @@ package cli import ( - "context" "fmt" "os" "strconv" "github.com/MakeNowJust/heredoc" + "github.com/odpf/salt/cmdx" "github.com/odpf/salt/printer" "github.com/odpf/siren/pkg/errors" sirenv1beta1 "github.com/odpf/siren/proto/odpf/siren/v1beta1" "github.com/spf13/cobra" ) -func alertsCmd(c *configuration) *cobra.Command { +func alertsCmd(cmdxConfig *cmdx.Config) *cobra.Command { cmd := &cobra.Command{ Use: "alert", Aliases: []string{"alerts"}, @@ -29,15 +29,16 @@ func alertsCmd(c *configuration) *cobra.Command { `), Annotations: map[string]string{ "group:core": "true", + "client": "true", }, } - cmd.AddCommand(listAlertsCmd(c)) + cmd.AddCommand(listAlertsCmd(cmdxConfig)) return cmd } -func listAlertsCmd(c *configuration) *cobra.Command { +func listAlertsCmd(cmdxConfig *cmdx.Config) *cobra.Command { var providerName string var providerId uint64 var resouceName string @@ -53,7 +54,16 @@ func listAlertsCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -71,6 +81,7 @@ func listAlertsCmd(c *configuration) *cobra.Command { return err } + spinner.Stop() if res.GetAlerts() == nil { return errors.New("no response from server") } @@ -106,5 +117,6 @@ func listAlertsCmd(c *configuration) *cobra.Command { cmd.Flags().StringVar(&resouceName, "resource-name", "", "resource name") cmd.Flags().Uint64Var(&startTime, "start-time", 0, "start time") cmd.Flags().Uint64Var(&endTime, "end-time", 0, "end time") + return cmd } diff --git a/cli/grpc.go b/cli/client.go similarity index 61% rename from cli/grpc.go rename to cli/client.go index b72a82bc..b87c236d 100644 --- a/cli/grpc.go +++ b/cli/client.go @@ -4,11 +4,34 @@ import ( "context" "time" + "github.com/odpf/salt/cmdx" + "github.com/odpf/salt/config" + "github.com/odpf/siren/pkg/errors" sirenv1beta1 "github.com/odpf/siren/proto/odpf/siren/v1beta1" + "github.com/spf13/cobra" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) +type ClientConfig struct { + Host string `yaml:"host" cmdx:"host"` +} + +func loadClientConfig(cmd *cobra.Command, cmdxConfig *cmdx.Config) (*ClientConfig, error) { + var clientConfig ClientConfig + + if err := cmdxConfig.Load( + &clientConfig, + cmdx.WithFlags(cmd.Flags()), + ); err != nil { + if !errors.Is(err, new(config.ConfigFileNotFoundError)) { + return nil, err + } + } + + return &clientConfig, nil +} + func createConnection(ctx context.Context, host string) (*grpc.ClientConn, error) { opts := []grpc.DialOption{ grpc.WithTransportCredentials(insecure.NewCredentials()), diff --git a/cli/config.go b/cli/config.go index c345a98a..27ccc3ae 100644 --- a/cli/config.go +++ b/cli/config.go @@ -2,67 +2,68 @@ package cli import ( "fmt" - "os" + "github.com/MakeNowJust/heredoc" + "github.com/odpf/salt/cmdx" + "github.com/odpf/salt/printer" "github.com/spf13/cobra" - "gopkg.in/yaml.v3" ) -var ( - DefaultHost = "localhost" - FileName = ".siren" - FileExtension = "yaml" -) - -type configuration struct { - Host string `yaml:"host"` -} - -func configCmd() *cobra.Command { +func configCmd(cmdxConfig *cmdx.Config) *cobra.Command { cmd := &cobra.Command{ - Use: "config", - Short: "manage siren CLI configuration", + Use: "config ", + Short: "Manage siren CLI configuration", + Example: heredoc.Doc(` + $ siren config init + $ siren config list + `), } - cmd.AddCommand(configInitCommand()) + cmd.AddCommand(configInitCommand(cmdxConfig)) + cmd.AddCommand(configListCommand(cmdxConfig)) return cmd } -func configInitCommand() *cobra.Command { +func configInitCommand(cmdxConfig *cmdx.Config) *cobra.Command { return &cobra.Command{ Use: "init", - Short: "initialize CLI configuration", + Short: "Initialize CLI configuration", + Example: heredoc.Doc(` + $ siren config init + `), + Annotations: map[string]string{ + "group": "core", + }, RunE: func(cmd *cobra.Command, args []string) error { - config := configuration{ - Host: DefaultHost, - } - - b, err := yaml.Marshal(config) - if err != nil { - return err - } - - filepath := fmt.Sprintf("%v.%v", FileName, FileExtension) - if err := os.WriteFile(filepath, b, 0655); err != nil { + if err := cmdxConfig.Init(&ClientConfig{}); err != nil { return err } - fmt.Printf("config created: %v", filepath) + fmt.Printf("config created: %v\n", cmdxConfig.File()) + printer.SuccessIcon() return nil }, } } -func readConfig() (*configuration, error) { - var c configuration - filepath := fmt.Sprintf("%v.%v", FileName, FileExtension) - b, err := os.ReadFile(filepath) - if err != nil { - return nil, err - } +func configListCommand(cmdxConfig *cmdx.Config) *cobra.Command { + var cmd = &cobra.Command{ + Use: "list", + Short: "List client configuration settings", + Example: heredoc.Doc(` + $ siren config list + `), + Annotations: map[string]string{ + "group": "core", + }, + RunE: func(cmd *cobra.Command, args []string) error { + data, err := cmdxConfig.Read() + if err != nil { + return ErrClientConfigNotFound + } - if err := yaml.Unmarshal(b, &c); err != nil { - return nil, err + fmt.Println(data) + return nil + }, } - - return &c, nil + return cmd } diff --git a/cli/errors.go b/cli/errors.go new file mode 100644 index 00000000..127552e1 --- /dev/null +++ b/cli/errors.go @@ -0,0 +1,14 @@ +package cli + +import ( + "github.com/MakeNowJust/heredoc" + "github.com/odpf/siren/pkg/errors" +) + +var ( + ErrClientConfigNotFound = errors.New(heredoc.Doc(` + Siren client config not found. + Run "siren config init" to initialize a new client config or + Run "siren help environment" for more information. + `)) +) diff --git a/cli/help.go b/cli/help.go new file mode 100644 index 00000000..00e2f211 --- /dev/null +++ b/cli/help.go @@ -0,0 +1,13 @@ +package cli + +import "github.com/MakeNowJust/heredoc" + +var envHelp = map[string]string{ + "short": "List of supported environment variables", + "long": heredoc.Doc(` + ODPF_CONFIG_DIR: the directory where siren will store configuration files. Default: + "$XDG_CONFIG_HOME/odpf" or "$HOME/.config/odpf". + NO_COLOR: set to any value to avoid printing ANSI escape sequences for color output. + CLICOLOR: set to "0" to disable printing ANSI colors in output. + `), +} diff --git a/cli/migrate.go b/cli/migrate.go deleted file mode 100644 index c973fc90..00000000 --- a/cli/migrate.go +++ /dev/null @@ -1,39 +0,0 @@ -package cli - -import ( - "github.com/odpf/salt/log" - "github.com/odpf/siren/config" - "github.com/odpf/siren/internal/store/postgres" - "github.com/spf13/cobra" -) - -func migrateCmd() *cobra.Command { - var configFile string - - cmd := &cobra.Command{ - Use: "migrate", - Short: "Migrate database schema", - Annotations: map[string]string{ - "group:other": "dev", - }, - RunE: func(cmd *cobra.Command, args []string) error { - cfg, err := config.LoadConfig(configFile) - if err != nil { - return err - } - - logger := initLogger(cfg.Log.Level) - if err := runPostgresMigrations(logger, cfg); err != nil { - return err - } - return nil - }, - } - - cmd.Flags().StringVarP(&configFile, "config", "c", "./config.yaml", "Config file path") - return cmd -} - -func runPostgresMigrations(logger log.Logger, cfg config.Config) error { - return postgres.Migrate(cfg.DB) -} diff --git a/cli/namespace.go b/cli/namespace.go index af16a8a8..b4a1db6a 100644 --- a/cli/namespace.go +++ b/cli/namespace.go @@ -1,12 +1,12 @@ package cli import ( - "context" "fmt" "os" "strconv" "github.com/MakeNowJust/heredoc" + "github.com/odpf/salt/cmdx" "github.com/odpf/salt/printer" "github.com/odpf/siren/core/namespace" "github.com/odpf/siren/pkg/errors" @@ -15,7 +15,7 @@ import ( "google.golang.org/protobuf/types/known/structpb" ) -func namespacesCmd(c *configuration) *cobra.Command { +func namespacesCmd(cmdxConfig *cmdx.Config) *cobra.Command { cmd := &cobra.Command{ Use: "namespace", Aliases: []string{"namespaces"}, @@ -27,19 +27,23 @@ func namespacesCmd(c *configuration) *cobra.Command { `), Annotations: map[string]string{ "group:core": "true", + "client": "true", }, } - cmd.AddCommand(listNamespacesCmd(c)) - cmd.AddCommand(createNamespaceCmd(c)) - cmd.AddCommand(getNamespaceCmd(c)) - cmd.AddCommand(updateNamespaceCmd(c)) - cmd.AddCommand(deleteNamespaceCmd(c)) + cmd.AddCommand( + listNamespacesCmd(cmdxConfig), + createNamespaceCmd(cmdxConfig), + getNamespaceCmd(cmdxConfig), + updateNamespaceCmd(cmdxConfig), + deleteNamespaceCmd(cmdxConfig), + ) + return cmd } -func listNamespacesCmd(c *configuration) *cobra.Command { - return &cobra.Command{ +func listNamespacesCmd(cmdxConfig *cmdx.Config) *cobra.Command { + cmd := &cobra.Command{ Use: "list", Short: "List namespaces", Long: heredoc.Doc(` @@ -49,7 +53,16 @@ func listNamespacesCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -65,6 +78,7 @@ func listNamespacesCmd(c *configuration) *cobra.Command { return errors.New("no response from server") } + spinner.Stop() namespaces := res.GetNamespaces() report := [][]string{} @@ -84,9 +98,11 @@ func listNamespacesCmd(c *configuration) *cobra.Command { return nil }, } + + return cmd } -func createNamespaceCmd(c *configuration) *cobra.Command { +func createNamespaceCmd(cmdxConfig *cmdx.Config) *cobra.Command { var filePath string cmd := &cobra.Command{ Use: "create", @@ -98,6 +114,16 @@ func createNamespaceCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + var namespaceConfig namespace.Namespace if err := parseFile(filePath, &namespaceConfig); err != nil { return err @@ -108,7 +134,6 @@ func createNamespaceCmd(c *configuration) *cobra.Command { return err } - ctx := context.Background() client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -127,8 +152,10 @@ func createNamespaceCmd(c *configuration) *cobra.Command { return err } - fmt.Printf("namespace created with id: %v\n", res.GetId()) - + spinner.Stop() + printer.Successf("Namespace created with id: %v", res.GetId()) + printer.Space() + printer.SuccessIcon() return nil }, } @@ -139,7 +166,7 @@ func createNamespaceCmd(c *configuration) *cobra.Command { return cmd } -func getNamespaceCmd(c *configuration) *cobra.Command { +func getNamespaceCmd(cmdxConfig *cmdx.Config) *cobra.Command { var format string cmd := &cobra.Command{ Use: "view", @@ -147,7 +174,7 @@ func getNamespaceCmd(c *configuration) *cobra.Command { Long: heredoc.Doc(` View a namespace. - Display the Id, name, and other information about a namespace. + Display the id, name, and other information about a namespace. `), Example: heredoc.Doc(` $ siren namespace view 1 @@ -157,7 +184,16 @@ func getNamespaceCmd(c *configuration) *cobra.Command { }, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -190,6 +226,7 @@ func getNamespaceCmd(c *configuration) *cobra.Command { UpdatedAt: res.GetNamespace().GetUpdatedAt().AsTime(), } + spinner.Stop() if err := printer.File(nspace, format); err != nil { return fmt.Errorf("failed to format namespace: %v", err) } @@ -202,7 +239,7 @@ func getNamespaceCmd(c *configuration) *cobra.Command { return cmd } -func updateNamespaceCmd(c *configuration) *cobra.Command { +func updateNamespaceCmd(cmdxConfig *cmdx.Config) *cobra.Command { var id uint64 var filePath string cmd := &cobra.Command{ @@ -215,6 +252,16 @@ func updateNamespaceCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + var namespaceConfig namespace.Namespace if err := parseFile(filePath, &namespaceConfig); err != nil { return err @@ -225,7 +272,6 @@ func updateNamespaceCmd(c *configuration) *cobra.Command { return err } - ctx := context.Background() client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -243,7 +289,10 @@ func updateNamespaceCmd(c *configuration) *cobra.Command { return err } - fmt.Printf("Successfully updated namespace with id %d", res.GetId()) + spinner.Stop() + printer.Successf("Successfully updated namespace with id %d", res.GetId()) + printer.Space() + printer.SuccessIcon() return nil }, @@ -257,7 +306,7 @@ func updateNamespaceCmd(c *configuration) *cobra.Command { return cmd } -func deleteNamespaceCmd(c *configuration) *cobra.Command { +func deleteNamespaceCmd(cmdxConfig *cmdx.Config) *cobra.Command { cmd := &cobra.Command{ Use: "delete", Short: "Delete a namespace details", @@ -269,7 +318,16 @@ func deleteNamespaceCmd(c *configuration) *cobra.Command { }, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -288,7 +346,11 @@ func deleteNamespaceCmd(c *configuration) *cobra.Command { return err } - fmt.Println("Successfully deleted namespace") + spinner.Stop() + printer.Success("Successfully deleted namespace") + printer.Space() + printer.SuccessIcon() + return nil }, } diff --git a/cli/provider.go b/cli/provider.go index 8f4ff004..9a647ddb 100644 --- a/cli/provider.go +++ b/cli/provider.go @@ -1,12 +1,12 @@ package cli import ( - "context" "fmt" "os" "strconv" "github.com/MakeNowJust/heredoc" + "github.com/odpf/salt/cmdx" "github.com/odpf/salt/printer" "github.com/odpf/siren/core/provider" "github.com/odpf/siren/pkg/errors" @@ -15,7 +15,7 @@ import ( "google.golang.org/protobuf/types/known/structpb" ) -func providersCmd(c *configuration) *cobra.Command { +func providersCmd(cmdxConfig *cmdx.Config) *cobra.Command { cmd := &cobra.Command{ Use: "provider", Aliases: []string{"providers"}, @@ -27,19 +27,23 @@ func providersCmd(c *configuration) *cobra.Command { `), Annotations: map[string]string{ "group:core": "true", + "client": "true", }, } - cmd.AddCommand(listProvidersCmd(c)) - cmd.AddCommand(createProviderCmd(c)) - cmd.AddCommand(getProviderCmd(c)) - cmd.AddCommand(updateProviderCmd(c)) - cmd.AddCommand(deleteProviderCmd(c)) + cmd.AddCommand( + listProvidersCmd(cmdxConfig), + createProviderCmd(cmdxConfig), + getProviderCmd(cmdxConfig), + updateProviderCmd(cmdxConfig), + deleteProviderCmd(cmdxConfig), + ) + return cmd } -func listProvidersCmd(c *configuration) *cobra.Command { - return &cobra.Command{ +func listProvidersCmd(cmdxConfig *cmdx.Config) *cobra.Command { + cmd := &cobra.Command{ Use: "list", Short: "List providers", Long: heredoc.Doc(` @@ -49,7 +53,16 @@ func listProvidersCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -65,6 +78,7 @@ func listProvidersCmd(c *configuration) *cobra.Command { return errors.New("no response from server") } + spinner.Stop() providers := res.GetProviders() report := [][]string{} @@ -86,9 +100,11 @@ func listProvidersCmd(c *configuration) *cobra.Command { return nil }, } + + return cmd } -func createProviderCmd(c *configuration) *cobra.Command { +func createProviderCmd(cmdxConfig *cmdx.Config) *cobra.Command { var filePath string cmd := &cobra.Command{ Use: "create", @@ -100,6 +116,16 @@ func createProviderCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + var providerConfig provider.Provider if err := parseFile(filePath, &providerConfig); err != nil { return err @@ -110,7 +136,6 @@ func createProviderCmd(c *configuration) *cobra.Command { return err } - ctx := context.Background() client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -130,7 +155,10 @@ func createProviderCmd(c *configuration) *cobra.Command { return err } - fmt.Printf("Provider created with id: %v\n", res.GetId()) + spinner.Stop() + printer.Successf("Provider created with id: %v", res.GetId()) + printer.Space() + printer.SuccessIcon() return nil }, @@ -142,7 +170,7 @@ func createProviderCmd(c *configuration) *cobra.Command { return cmd } -func getProviderCmd(c *configuration) *cobra.Command { +func getProviderCmd(cmdxConfig *cmdx.Config) *cobra.Command { var format string cmd := &cobra.Command{ Use: "view", @@ -150,7 +178,7 @@ func getProviderCmd(c *configuration) *cobra.Command { Long: heredoc.Doc(` View a provider. - Display the Id, name, and other information about a provider. + Display the id, name, and other information about a provider. `), Example: heredoc.Doc(` $ siren provider view 1 @@ -160,7 +188,16 @@ func getProviderCmd(c *configuration) *cobra.Command { }, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -195,6 +232,7 @@ func getProviderCmd(c *configuration) *cobra.Command { UpdatedAt: res.GetProvider().GetUpdatedAt().AsTime(), } + spinner.Stop() if err := printer.File(provider, format); err != nil { return fmt.Errorf("failed to format provider: %v", err) } @@ -207,7 +245,7 @@ func getProviderCmd(c *configuration) *cobra.Command { return cmd } -func updateProviderCmd(c *configuration) *cobra.Command { +func updateProviderCmd(cmdxConfig *cmdx.Config) *cobra.Command { var id uint64 var filePath string cmd := &cobra.Command{ @@ -220,6 +258,16 @@ func updateProviderCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + var providerConfig provider.Provider if err := parseFile(filePath, &providerConfig); err != nil { return err @@ -230,7 +278,6 @@ func updateProviderCmd(c *configuration) *cobra.Command { return err } - ctx := context.Background() client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -249,7 +296,10 @@ func updateProviderCmd(c *configuration) *cobra.Command { return err } - fmt.Println("Successfully updated provider") + spinner.Stop() + printer.Success("Successfully updated provider") + printer.Space() + printer.SuccessIcon() return nil }, @@ -263,7 +313,7 @@ func updateProviderCmd(c *configuration) *cobra.Command { return cmd } -func deleteProviderCmd(c *configuration) *cobra.Command { +func deleteProviderCmd(cmdxConfig *cmdx.Config) *cobra.Command { cmd := &cobra.Command{ Use: "delete", Short: "Delete a provider details", @@ -275,7 +325,16 @@ func deleteProviderCmd(c *configuration) *cobra.Command { }, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -294,7 +353,11 @@ func deleteProviderCmd(c *configuration) *cobra.Command { return err } - fmt.Println("Successfully deleted provider") + spinner.Stop() + printer.Success("Successfully deleted provider") + printer.Space() + printer.SuccessIcon() + return nil }, } diff --git a/cli/receiver.go b/cli/receiver.go index a747c4af..ebce6880 100644 --- a/cli/receiver.go +++ b/cli/receiver.go @@ -1,12 +1,12 @@ package cli import ( - "context" "fmt" "os" "strconv" "github.com/MakeNowJust/heredoc" + "github.com/odpf/salt/cmdx" "github.com/odpf/salt/printer" "github.com/odpf/siren/core/receiver" "github.com/odpf/siren/pkg/errors" @@ -15,7 +15,7 @@ import ( "google.golang.org/protobuf/types/known/structpb" ) -func receiversCmd(c *configuration) *cobra.Command { +func receiversCmd(cmdxConfig *cmdx.Config) *cobra.Command { cmd := &cobra.Command{ Use: "receiver", Aliases: []string{"receivers"}, @@ -27,20 +27,24 @@ func receiversCmd(c *configuration) *cobra.Command { `), Annotations: map[string]string{ "group:core": "true", + "client": "true", }, } - cmd.AddCommand(listReceiversCmd(c)) - cmd.AddCommand(createReceiverCmd(c)) - cmd.AddCommand(getReceiverCmd(c)) - cmd.AddCommand(updateReceiverCmd(c)) - cmd.AddCommand(deleteReceiverCmd(c)) - cmd.AddCommand(notifyReceiverCmd(c)) + cmd.AddCommand( + listReceiversCmd(cmdxConfig), + createReceiverCmd(cmdxConfig), + getReceiverCmd(cmdxConfig), + updateReceiverCmd(cmdxConfig), + deleteReceiverCmd(cmdxConfig), + notifyReceiverCmd(cmdxConfig), + ) + return cmd } -func listReceiversCmd(c *configuration) *cobra.Command { - return &cobra.Command{ +func listReceiversCmd(cmdxConfig *cmdx.Config) *cobra.Command { + cmd := &cobra.Command{ Use: "list", Short: "List receivers", Long: heredoc.Doc(` @@ -50,7 +54,16 @@ func listReceiversCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -66,6 +79,7 @@ func listReceiversCmd(c *configuration) *cobra.Command { return errors.New("no response from server") } + spinner.Stop() receivers := res.GetReceivers() report := [][]string{} @@ -85,9 +99,11 @@ func listReceiversCmd(c *configuration) *cobra.Command { return nil }, } + + return cmd } -func createReceiverCmd(c *configuration) *cobra.Command { +func createReceiverCmd(cmdxConfig *cmdx.Config) *cobra.Command { var filePath string cmd := &cobra.Command{ Use: "create", @@ -99,6 +115,16 @@ func createReceiverCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + var receiverConfig receiver.Receiver if err := parseFile(filePath, &receiverConfig); err != nil { return err @@ -109,7 +135,6 @@ func createReceiverCmd(c *configuration) *cobra.Command { return err } - ctx := context.Background() client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -127,7 +152,10 @@ func createReceiverCmd(c *configuration) *cobra.Command { return err } - fmt.Printf("Receiver created with id: %v\n", res.GetId()) + spinner.Stop() + printer.Successf("Receiver created with id: %v", res.GetId()) + printer.Space() + printer.SuccessIcon() return nil }, @@ -139,7 +167,7 @@ func createReceiverCmd(c *configuration) *cobra.Command { return cmd } -func getReceiverCmd(c *configuration) *cobra.Command { +func getReceiverCmd(cmdxConfig *cmdx.Config) *cobra.Command { var format string cmd := &cobra.Command{ Use: "view", @@ -147,7 +175,7 @@ func getReceiverCmd(c *configuration) *cobra.Command { Long: heredoc.Doc(` View a receiver. - Display the Id, name, and other information about a receiver. + Display the id, name, and other information about a receiver. `), Example: heredoc.Doc(` $ siren receiver view 1 @@ -157,7 +185,16 @@ func getReceiverCmd(c *configuration) *cobra.Command { }, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -191,6 +228,7 @@ func getReceiverCmd(c *configuration) *cobra.Command { UpdatedAt: res.GetReceiver().GetUpdatedAt().AsTime(), } + spinner.Stop() if err := printer.File(receiver, format); err != nil { return fmt.Errorf("failed to format receiver: %v", err) } @@ -203,7 +241,7 @@ func getReceiverCmd(c *configuration) *cobra.Command { return cmd } -func updateReceiverCmd(c *configuration) *cobra.Command { +func updateReceiverCmd(cmdxConfig *cmdx.Config) *cobra.Command { var id uint64 var filePath string cmd := &cobra.Command{ @@ -216,6 +254,16 @@ func updateReceiverCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + var receiverConfig receiver.Receiver if err := parseFile(filePath, &receiverConfig); err != nil { return err @@ -226,7 +274,6 @@ func updateReceiverCmd(c *configuration) *cobra.Command { return err } - ctx := context.Background() client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -244,7 +291,10 @@ func updateReceiverCmd(c *configuration) *cobra.Command { return err } - fmt.Printf("Successfully updated receiver with id %d\n", id) + spinner.Stop() + printer.Successf("Successfully updated receiver with id %d", id) + printer.Space() + printer.SuccessIcon() return nil }, @@ -258,7 +308,7 @@ func updateReceiverCmd(c *configuration) *cobra.Command { return cmd } -func deleteReceiverCmd(c *configuration) *cobra.Command { +func deleteReceiverCmd(cmdxConfig *cmdx.Config) *cobra.Command { cmd := &cobra.Command{ Use: "delete", Short: "Delete a receiver details", @@ -270,7 +320,16 @@ func deleteReceiverCmd(c *configuration) *cobra.Command { }, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -289,7 +348,11 @@ func deleteReceiverCmd(c *configuration) *cobra.Command { return err } - fmt.Println("Successfully deleted receiver") + spinner.Stop() + printer.Success("Successfully deleted receiver") + printer.Space() + printer.SuccessIcon() + return nil }, } @@ -297,7 +360,7 @@ func deleteReceiverCmd(c *configuration) *cobra.Command { return cmd } -func notifyReceiverCmd(c *configuration) *cobra.Command { +func notifyReceiverCmd(cmdxConfig *cmdx.Config) *cobra.Command { var id uint64 var filePath string cmd := &cobra.Command{ @@ -310,7 +373,16 @@ func notifyReceiverCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -345,7 +417,10 @@ func notifyReceiverCmd(c *configuration) *cobra.Command { return err } - fmt.Println("Successfully send receiver notification") + spinner.Stop() + printer.Success("Successfully send receiver notification") + printer.Space() + printer.SuccessIcon() return nil }, diff --git a/cli/root.go b/cli/root.go index 025ab5ab..c0bf3c01 100644 --- a/cli/root.go +++ b/cli/root.go @@ -1,8 +1,7 @@ package cli import ( - "fmt" - "os" + "context" "github.com/MakeNowJust/heredoc" "github.com/odpf/salt/cmdx" @@ -10,12 +9,12 @@ import ( "github.com/spf13/cobra" ) -// Execute runs the command line interface -func Execute() { +func New(ctx context.Context) *cobra.Command { rootCmd := &cobra.Command{ - Use: "siren [flags]", - Short: "siren", - Long: "Work seemlessly with your observability stack.", + Use: "siren [flags]", + Short: "siren", + Long: heredoc.Doc(` + Work seamlessly with your observability stack.`), SilenceUsage: true, SilenceErrors: true, Annotations: map[string]string{ @@ -27,28 +26,34 @@ func Execute() { "help:feedback": heredoc.Doc(` Open an issue here https://github.com/odpf/siren/issues `), + "help:environment": heredoc.Doc(` + See 'siren help environment' for the list of supported environment variables. + `), }, } - cliConfig, err := readConfig() - if err != nil { - fmt.Println(err) - } + cmdxConfig := cmdx.SetConfig("siren") + + rootCmd.AddCommand(serverCmd()) + rootCmd.AddCommand(configCmd(cmdxConfig)) + rootCmd.AddCommand(providersCmd(cmdxConfig)) + rootCmd.AddCommand(namespacesCmd(cmdxConfig)) + rootCmd.AddCommand(receiversCmd(cmdxConfig)) + rootCmd.AddCommand(templatesCmd(cmdxConfig)) + rootCmd.AddCommand(rulesCmd(cmdxConfig)) + rootCmd.AddCommand(alertsCmd(cmdxConfig)) + // Help topics cmdx.SetHelp(rootCmd) + rootCmd.AddCommand(cmdx.SetCompletionCmd("siren")) + rootCmd.AddCommand(cmdx.SetHelpTopicCmd("environment", envHelp)) + rootCmd.AddCommand(cmdx.SetRefCmd(rootCmd)) - rootCmd.AddCommand(configCmd()) - rootCmd.AddCommand(serveCmd()) - rootCmd.AddCommand(migrateCmd()) - rootCmd.AddCommand(providersCmd(cliConfig)) - rootCmd.AddCommand(namespacesCmd(cliConfig)) - rootCmd.AddCommand(receiversCmd(cliConfig)) - rootCmd.AddCommand(templatesCmd(cliConfig)) - rootCmd.AddCommand(rulesCmd(cliConfig)) - rootCmd.AddCommand(alertsCmd(cliConfig)) - - if err := rootCmd.Execute(); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } + cmdx.SetClientHook(rootCmd, func(cmd *cobra.Command) { + // client config + cmd.PersistentFlags().StringP("host", "h", "", "Siren API service to connect to") + cmd.MarkPersistentFlagRequired("host") + }) + + return rootCmd } diff --git a/cli/rule.go b/cli/rule.go index 08925509..8b43d73a 100644 --- a/cli/rule.go +++ b/cli/rule.go @@ -3,6 +3,7 @@ package cli import ( "context" "fmt" + "io/ioutil" "os" "strconv" "strings" @@ -11,6 +12,7 @@ import ( "gopkg.in/yaml.v3" "github.com/MakeNowJust/heredoc" + "github.com/odpf/salt/cmdx" "github.com/odpf/salt/printer" "github.com/odpf/siren/core/rule" sirenv1beta1 "github.com/odpf/siren/proto/odpf/siren/v1beta1" @@ -36,7 +38,7 @@ type ruleYaml struct { } `yaml:"rules"` } -func rulesCmd(c *configuration) *cobra.Command { +func rulesCmd(cmdxConfig *cmdx.Config) *cobra.Command { cmd := &cobra.Command{ Use: "rule", Aliases: []string{"rules"}, @@ -48,17 +50,20 @@ func rulesCmd(c *configuration) *cobra.Command { `), Annotations: map[string]string{ "group:core": "true", + "client": "true", }, } - cmd.AddCommand(listRulesCmd(c)) - cmd.AddCommand(updateRuleCmd(c)) - cmd.AddCommand(uploadRuleCmd(c)) + cmd.AddCommand( + listRulesCmd(cmdxConfig), + updateRuleCmd(cmdxConfig), + uploadRuleCmd(cmdxConfig), + ) return cmd } -func listRulesCmd(c *configuration) *cobra.Command { +func listRulesCmd(cmdxConfig *cmdx.Config) *cobra.Command { var name string var namespace string var groupName string @@ -74,7 +79,16 @@ func listRulesCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -95,10 +109,10 @@ func listRulesCmd(c *configuration) *cobra.Command { return errors.New("no response from server") } + spinner.Stop() rules := res.GetRules() report := [][]string{} - // TODO unclear log fmt.Printf(" \nShowing %d of %d rules\n \n", len(rules), len(rules)) report = append(report, []string{"ID", "NAME", "GROUP_NAME", "TEMPLATE", "ENABLED"}) @@ -127,7 +141,7 @@ func listRulesCmd(c *configuration) *cobra.Command { return cmd } -func updateRuleCmd(c *configuration) *cobra.Command { +func updateRuleCmd(cmdxConfig *cmdx.Config) *cobra.Command { var id uint64 var filePath string cmd := &cobra.Command{ @@ -140,12 +154,21 @@ func updateRuleCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + var ruleConfig rule.Rule if err := parseFile(filePath, &ruleConfig); err != nil { return err } - ctx := context.Background() client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -174,7 +197,10 @@ func updateRuleCmd(c *configuration) *cobra.Command { return err } - fmt.Println("Successfully updated rule") + spinner.Stop() + printer.Success("Successfully updated rule") + printer.Space() + printer.SuccessIcon() return nil }, @@ -188,9 +214,9 @@ func updateRuleCmd(c *configuration) *cobra.Command { return cmd } -func uploadRuleCmd(c *configuration) *cobra.Command { - var fileReader = os.ReadFile - return &cobra.Command{ +func uploadRuleCmd(cmdxConfig *cmdx.Config) *cobra.Command { + var fileReader = ioutil.ReadFile + cmd := &cobra.Command{ Use: "upload", Short: "Upload Rules YAML file", Annotations: map[string]string{ @@ -198,7 +224,16 @@ func uploadRuleCmd(c *configuration) *cobra.Command { }, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -224,6 +259,8 @@ func uploadRuleCmd(c *configuration) *cobra.Command { if err != nil { return err } + + spinner.Stop() //TODO might need to print the actual rule here or log error rules printRulesID(rulesID) return nil @@ -231,6 +268,8 @@ func uploadRuleCmd(c *configuration) *cobra.Command { return errors.New("yaml is not rule type") }, } + + return cmd } func uploadRules(client sirenv1beta1.SirenServiceClient, yamlFile []byte) ([]uint64, error) { diff --git a/cli/serve.go b/cli/server.go similarity index 68% rename from cli/serve.go rename to cli/server.go index 6ea28278..4870bd1d 100644 --- a/cli/serve.go +++ b/cli/server.go @@ -4,8 +4,10 @@ import ( "fmt" "net/http" + "github.com/MakeNowJust/heredoc" "github.com/odpf/salt/db" "github.com/odpf/salt/log" + "github.com/odpf/salt/printer" "github.com/odpf/siren/config" "github.com/odpf/siren/core/alert" "github.com/odpf/siren/core/namespace" @@ -26,18 +28,70 @@ import ( "go.uber.org/zap/zapcore" ) -func serveCmd() *cobra.Command { - var configFile string - +func serverCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "serve", + Use: "server ", Aliases: []string{"s"}, Short: "Run siren server", - Annotations: map[string]string{ - "group:other": "dev", + Long: "Server management commands.", + Example: heredoc.Doc(` + $ siren server init + $ siren server start + $ siren server start -c ./config.yaml + $ siren server migrate + $ siren server migrate -c ./config.yaml + `), + } + + cmd.AddCommand( + serverInitCommand(), + serverStartCommand(), + serverMigrateCommand(), + ) + + return cmd +} + +func serverInitCommand() *cobra.Command { + var configFile string + // var resourcesURL string + // var rulesURL string + + cmd := &cobra.Command{ + Use: "init", + Short: "Initialize server", + Long: heredoc.Doc(` + Initializing server. Creating a sample of siren server config. + Default: ./config.yaml + `), + Example: "siren server init", + RunE: func(cmd *cobra.Command, args []string) error { + if err := config.Init(configFile); err != nil { + return err + } + + printer.Successf("Server config created: %s", configFile) + printer.Space() + printer.SuccessIcon() + + return nil }, + } + + cmd.Flags().StringVarP(&configFile, "output", "o", "./config.yaml", "Output config file path") + + return cmd +} + +func serverStartCommand() *cobra.Command { + var configFile string + + c := &cobra.Command{ + Use: "start", + Short: "Start server on default port 8080", + Example: "siren server start", RunE: func(cmd *cobra.Command, args []string) error { - cfg, err := config.LoadConfig(configFile) + cfg, err := config.Load(configFile) if err != nil { return err } @@ -45,8 +99,32 @@ func serveCmd() *cobra.Command { }, } - cmd.Flags().StringVarP(&configFile, "config", "c", "./config.yaml", "Config file path") - return cmd + c.Flags().StringVarP(&configFile, "config", "c", "config.yaml", "Config file path") + return c +} + +func serverMigrateCommand() *cobra.Command { + var configFile string + + c := &cobra.Command{ + Use: "migrate", + Short: "Run DB Schema Migrations", + Example: "siren migrate", + RunE: func(c *cobra.Command, args []string) error { + cfg, err := config.Load(configFile) + if err != nil { + return err + } + + if err := postgres.Migrate(cfg.DB); err != nil { + return err + } + return nil + }, + } + + c.Flags().StringVarP(&configFile, "config", "c", "", "Config file path") + return c } func runServer(cfg config.Config) error { @@ -123,7 +201,7 @@ func runServer(cfg config.Config) error { subscriptionService := subscription.NewService(subscriptionRepository, providerService, namespaceService, receiverService, cortexClient) return server.RunServer( - cfg.SirenService, + cfg.Service, logger, nr, templateService, diff --git a/cli/template.go b/cli/template.go index a89a312f..993ef549 100644 --- a/cli/template.go +++ b/cli/template.go @@ -3,6 +3,7 @@ package cli import ( "context" "fmt" + "io/ioutil" "os" "strings" @@ -10,6 +11,7 @@ import ( "gopkg.in/yaml.v3" "github.com/MakeNowJust/heredoc" + "github.com/odpf/salt/cmdx" "github.com/odpf/salt/printer" "github.com/odpf/siren/core/template" sirenv1beta1 "github.com/odpf/siren/proto/odpf/siren/v1beta1" @@ -34,7 +36,7 @@ type templateStruct struct { Variables []template.Variable `yaml:"variables"` } -func templatesCmd(c *configuration) *cobra.Command { +func templatesCmd(cmdxConfig *cmdx.Config) *cobra.Command { cmd := &cobra.Command{ Use: "template", Aliases: []string{"templates"}, @@ -46,20 +48,23 @@ func templatesCmd(c *configuration) *cobra.Command { `), Annotations: map[string]string{ "group:core": "true", + "client": "true", }, } - cmd.AddCommand(listTemplatesCmd(c)) - cmd.AddCommand(upsertTemplateCmd(c)) - cmd.AddCommand(getTemplateCmd(c)) - cmd.AddCommand(deleteTemplateCmd(c)) - cmd.AddCommand(renderTemplateCmd(c)) - cmd.AddCommand(uploadTemplateCmd(c)) + cmd.AddCommand( + listTemplatesCmd(cmdxConfig), + upsertTemplateCmd(cmdxConfig), + getTemplateCmd(cmdxConfig), + deleteTemplateCmd(cmdxConfig), + renderTemplateCmd(cmdxConfig), + uploadTemplateCmd(cmdxConfig), + ) return cmd } -func listTemplatesCmd(c *configuration) *cobra.Command { +func listTemplatesCmd(cmdxConfig *cmdx.Config) *cobra.Command { var tag string cmd := &cobra.Command{ Use: "list", @@ -71,7 +76,16 @@ func listTemplatesCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -89,6 +103,7 @@ func listTemplatesCmd(c *configuration) *cobra.Command { return errors.New("no response from server") } + spinner.Stop() templates := res.GetTemplates() report := [][]string{} @@ -114,7 +129,7 @@ func listTemplatesCmd(c *configuration) *cobra.Command { return cmd } -func upsertTemplateCmd(c *configuration) *cobra.Command { +func upsertTemplateCmd(cmdxConfig *cmdx.Config) *cobra.Command { var filePath string cmd := &cobra.Command{ Use: "upsert", @@ -126,12 +141,21 @@ func upsertTemplateCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + var templateConfig template.Template if err := parseFile(filePath, &templateConfig); err != nil { return err } - ctx := context.Background() client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -159,7 +183,10 @@ func upsertTemplateCmd(c *configuration) *cobra.Command { return err } - fmt.Printf("template created with id: %v\n", res.GetId()) + spinner.Stop() + printer.Successf("Template created with id: %v", res.GetId()) + printer.Space() + printer.SuccessIcon() return nil }, @@ -171,7 +198,7 @@ func upsertTemplateCmd(c *configuration) *cobra.Command { return cmd } -func getTemplateCmd(c *configuration) *cobra.Command { +func getTemplateCmd(cmdxConfig *cmdx.Config) *cobra.Command { var format string cmd := &cobra.Command{ Use: "view", @@ -179,7 +206,7 @@ func getTemplateCmd(c *configuration) *cobra.Command { Long: heredoc.Doc(` View a template. - Display the Id, name, and other information about a template. + Display the id, name, and other information about a template. `), Example: heredoc.Doc(` $ siren template view @@ -189,7 +216,16 @@ func getTemplateCmd(c *configuration) *cobra.Command { }, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -230,6 +266,7 @@ func getTemplateCmd(c *configuration) *cobra.Command { UpdatedAt: templateData.UpdatedAt.AsTime(), } + spinner.Stop() if err := printer.File(template, format); err != nil { return fmt.Errorf("failed to format template: %v", err) } @@ -242,7 +279,7 @@ func getTemplateCmd(c *configuration) *cobra.Command { return cmd } -func deleteTemplateCmd(c *configuration) *cobra.Command { +func deleteTemplateCmd(cmdxConfig *cmdx.Config) *cobra.Command { cmd := &cobra.Command{ Use: "delete", Short: "Delete a template details", @@ -254,7 +291,16 @@ func deleteTemplateCmd(c *configuration) *cobra.Command { }, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -269,7 +315,11 @@ func deleteTemplateCmd(c *configuration) *cobra.Command { return err } - fmt.Println("Successfully deleted template") + spinner.Stop() + printer.Success("Successfully deleted template") + printer.Space() + printer.SuccessIcon() + return nil }, } @@ -277,7 +327,7 @@ func deleteTemplateCmd(c *configuration) *cobra.Command { return cmd } -func renderTemplateCmd(c *configuration) *cobra.Command { +func renderTemplateCmd(cmdxConfig *cmdx.Config) *cobra.Command { var name string var filePath string var format string @@ -289,6 +339,16 @@ func renderTemplateCmd(c *configuration) *cobra.Command { "group:core": "true", }, RunE: func(cmd *cobra.Command, args []string) error { + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + var variableConfig struct { Variables map[string]string } @@ -296,7 +356,6 @@ func renderTemplateCmd(c *configuration) *cobra.Command { return err } - ctx := context.Background() client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -311,6 +370,7 @@ func renderTemplateCmd(c *configuration) *cobra.Command { return err } + spinner.Stop() if err := printer.File(template, format); err != nil { return fmt.Errorf("failed to format template: %v", err) } @@ -328,9 +388,9 @@ func renderTemplateCmd(c *configuration) *cobra.Command { return cmd } -func uploadTemplateCmd(c *configuration) *cobra.Command { - var fileReader = os.ReadFile - return &cobra.Command{ +func uploadTemplateCmd(cmdxConfig *cmdx.Config) *cobra.Command { + var fileReader = ioutil.ReadFile + cmd := &cobra.Command{ Use: "upload", Short: "Upload Templates YAML file", Annotations: map[string]string{ @@ -338,7 +398,16 @@ func uploadTemplateCmd(c *configuration) *cobra.Command { }, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() + spinner := printer.Spin("") + defer spinner.Stop() + + ctx := cmd.Context() + + c, err := loadClientConfig(cmd, cmdxConfig) + if err != nil { + return err + } + client, cancel, err := createClient(ctx, c.Host) if err != nil { return err @@ -364,6 +433,7 @@ func uploadTemplateCmd(c *configuration) *cobra.Command { if err != nil { return err } + spinner.Stop() //TODO might need to log the actual template or log error here printTemplateID(templateID) return nil @@ -371,6 +441,8 @@ func uploadTemplateCmd(c *configuration) *cobra.Command { return errors.New("yaml is not rule type") }, } + + return cmd } func uploadTemplate(client sirenv1beta1.SirenServiceClient, yamlFile []byte) (uint64, error) { diff --git a/config/config.go b/config/config.go index 3176db23..7f0d9d15 100644 --- a/config/config.go +++ b/config/config.go @@ -19,8 +19,8 @@ var ( promAMConfigYamlString string ) -// LoadConfig returns application configuration -func LoadConfig(configFile string) (Config, error) { +// Load returns application configuration +func Load(configFile string) (Config, error) { var cfg Config loader := config.NewLoader(config.WithFile(configFile)) @@ -37,12 +37,12 @@ func LoadConfig(configFile string) (Config, error) { } type LogConfig struct { - Level string `mapstructure:"level" default:"info"` + Level string `yaml:"level" mapstructure:"level" default:"info"` } type SlackApp struct { - ClientID string `mapstructure:"client_id"` - ClientSecret string `mapstructure:"client_secret"` + ClientID string `yaml:"client_id" mapstructure:"client_id"` + ClientSecret string `yaml:"client_secret" mapstructure:"client_secret"` } // Config contains the application configuration @@ -50,7 +50,7 @@ type Config struct { DB db.Config `mapstructure:"db"` Cortex cortex.Config `mapstructure:"cortex"` NewRelic telemetry.NewRelicConfig `mapstructure:"newrelic"` - SirenService server.Config `mapstructure:"siren_service"` + Service server.Config `mapstructure:"service"` Log LogConfig `mapstructure:"log"` SlackApp SlackApp `mapstructure:"slack_app"` EncryptionKey string `mapstructure:"encryption_key"` diff --git a/config/config.yaml b/config/config.yaml index 11238672..18df57b5 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -8,8 +8,6 @@ # Per default, Siren will look up and load file ~/config.yaml. All configuration keys can be set using environment # variables as well. # - -port: 3000 db: host: localhost user: postgres @@ -23,8 +21,9 @@ newrelic: enabled: false appname: siren license: ____LICENSE_STRING_OF_40_CHARACTERS_____ -siren_service: +service: host: localhost + port: 8080 slack_app: client_id: 123.456 client_secret: xyz diff --git a/config/init.go b/config/init.go new file mode 100644 index 00000000..9d703bb4 --- /dev/null +++ b/config/init.go @@ -0,0 +1,25 @@ +package config + +import ( + "io/ioutil" + + "github.com/mcuadros/go-defaults" + "gopkg.in/yaml.v2" +) + +func Init(configFile string) error { + cfg := &Config{} + + defaults.SetDefaults(cfg) + + data, err := yaml.Marshal(cfg) + if err != nil { + return err + } + + if err := ioutil.WriteFile(configFile, data, 0655); err != nil { + return err + } + + return nil +} diff --git a/go.mod b/go.mod index 755aa313..7d7d8bd4 100644 --- a/go.mod +++ b/go.mod @@ -26,10 +26,11 @@ require ( github.com/lib/pq v1.10.2 github.com/mattn/go-isatty v0.0.16 // indirect github.com/mattn/go-sqlite3 v1.14.12 // indirect + github.com/mcuadros/go-defaults v1.2.0 github.com/muesli/termenv v0.12.0 // indirect github.com/newrelic/go-agent/v3 v3.12.0 github.com/newrelic/go-agent/v3/integrations/nrgrpc v1.3.1 - github.com/odpf/salt v0.1.1-0.20220830230424-94215a338f4c + github.com/odpf/salt v0.1.1-0.20220912101358-d28f61d005ca github.com/ory/dockertest/v3 v3.9.1 github.com/pelletier/go-toml/v2 v2.0.2 // indirect github.com/prometheus/alertmanager v0.21.1-0.20200911160112-1fdff6b3f939 @@ -52,5 +53,6 @@ require ( google.golang.org/grpc v1.48.0 google.golang.org/protobuf v1.28.1 gopkg.in/ini.v1 v1.66.6 // indirect + gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index bf879c91..1b8760b2 100644 --- a/go.sum +++ b/go.sum @@ -75,6 +75,7 @@ contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeS dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= +github.com/AlecAivazis/survey/v2 v2.3.5/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= @@ -176,6 +177,7 @@ github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5 github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -367,6 +369,8 @@ github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2u github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/cli/safeexec v1.0.0 h1:0VngyaIyqACHdcMNWfo6+KdUYnqEr2Sg+bSP1pdF+dI= +github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -520,8 +524,9 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= +github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= @@ -1171,6 +1176,7 @@ github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpT github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hetznercloud/hcloud-go v1.21.1/go.mod h1:xng8lbDUg+xM1dgc0yGHX5EeqbwIq7UYlMWMTx3SQVg= github.com/hetznercloud/hcloud-go v1.22.0/go.mod h1:xng8lbDUg+xM1dgc0yGHX5EeqbwIq7UYlMWMTx3SQVg= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= github.com/hodgesds/perf-utils v0.0.8/go.mod h1:F6TfvsbtrF88i++hou29dTXlI2sfsJv+gRZDtmTJkAs= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= @@ -1585,8 +1591,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/odpf/salt v0.1.1-0.20220830230424-94215a338f4c h1:yIHpxv/P+bz81S0jQJjCuPLB/w/5cEe0fvrdIPY9LvQ= -github.com/odpf/salt v0.1.1-0.20220830230424-94215a338f4c/go.mod h1:4NsBZd9WPT7KQ6ee70dRnLHppAXBgM9kW8q5sMFhqlU= +github.com/odpf/salt v0.1.1-0.20220912101358-d28f61d005ca h1:fIidiIzdXsM/OVLkgE+CRrIbMi/RfRRSqMJmW2R3NFc= +github.com/odpf/salt v0.1.1-0.20220912101358-d28f61d005ca/go.mod h1:goInym7R4lIwV0jhfmjybtYvuiApEJ8Yuu8tBGzkQ9I= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= @@ -2539,6 +2545,7 @@ golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220405210540-1e041c57c461/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2549,6 +2556,7 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/main.go b/main.go index 314045d6..019f8abc 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,14 @@ package main import ( + "context" + "fmt" + "github.com/odpf/siren/cli" ) func main() { - cli.Execute() + if err := cli.New(context.Background()).Execute(); err != nil { + fmt.Printf("%+v\n", err) + } } diff --git a/pkg/cortex/config.go b/pkg/cortex/config.go index e055811e..ded6781f 100644 --- a/pkg/cortex/config.go +++ b/pkg/cortex/config.go @@ -1,7 +1,7 @@ package cortex type Config struct { - Address string `mapstructure:"address" default:"http://localhost:8080"` - PrometheusAlertManagerConfigYaml string `mapstructure:"configyaml" default:""` - PrometheusAlertManagerHelperTemplate string `mapstructure:"helpertemplate" default:""` + Address string `yaml:"address" mapstructure:"address" default:"http://localhost:8080"` + PrometheusAlertManagerConfigYaml string `yaml:"-" mapstructure:"configyaml" default:""` + PrometheusAlertManagerHelperTemplate string `yaml:"-" mapstructure:"helpertemplate" default:""` } diff --git a/pkg/telemetry/telemetry.go b/pkg/telemetry/telemetry.go index c4714638..7cc40c54 100644 --- a/pkg/telemetry/telemetry.go +++ b/pkg/telemetry/telemetry.go @@ -6,9 +6,9 @@ import ( // NewRelic contains the New Relic go-agent configuration type NewRelicConfig struct { - Enabled bool `mapstructure:"enabled" default:"false"` - AppName string `mapstructure:"appname" default:"siren"` - License string `mapstructure:"license"` + Enabled bool `yaml:"enabled" mapstructure:"enabled" default:"false"` + AppName string `yaml:"appname" mapstructure:"appname" default:"siren"` + License string `yaml:"license" mapstructure:"license"` } func New(c NewRelicConfig) (*newrelic.Application, error) { From 3d8b8b35d3521bc8c2a876d8ea5f309ee1774a35 Mon Sep 17 00:00:00 2001 From: Muhammad Abduh Date: Mon, 12 Sep 2022 19:23:20 +0700 Subject: [PATCH 2/2] fix(deps): replace ioutil with os for read and write file --- cli/rule.go | 3 +-- cli/template.go | 3 +-- config/init.go | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/cli/rule.go b/cli/rule.go index 8b43d73a..dff27848 100644 --- a/cli/rule.go +++ b/cli/rule.go @@ -3,7 +3,6 @@ package cli import ( "context" "fmt" - "io/ioutil" "os" "strconv" "strings" @@ -215,7 +214,7 @@ func updateRuleCmd(cmdxConfig *cmdx.Config) *cobra.Command { } func uploadRuleCmd(cmdxConfig *cmdx.Config) *cobra.Command { - var fileReader = ioutil.ReadFile + var fileReader = os.ReadFile cmd := &cobra.Command{ Use: "upload", Short: "Upload Rules YAML file", diff --git a/cli/template.go b/cli/template.go index 993ef549..334e3e7f 100644 --- a/cli/template.go +++ b/cli/template.go @@ -3,7 +3,6 @@ package cli import ( "context" "fmt" - "io/ioutil" "os" "strings" @@ -389,7 +388,7 @@ func renderTemplateCmd(cmdxConfig *cmdx.Config) *cobra.Command { } func uploadTemplateCmd(cmdxConfig *cmdx.Config) *cobra.Command { - var fileReader = ioutil.ReadFile + var fileReader = os.ReadFile cmd := &cobra.Command{ Use: "upload", Short: "Upload Templates YAML file", diff --git a/config/init.go b/config/init.go index 9d703bb4..886bcddb 100644 --- a/config/init.go +++ b/config/init.go @@ -1,7 +1,7 @@ package config import ( - "io/ioutil" + "os" "github.com/mcuadros/go-defaults" "gopkg.in/yaml.v2" @@ -17,7 +17,7 @@ func Init(configFile string) error { return err } - if err := ioutil.WriteFile(configFile, data, 0655); err != nil { + if err := os.WriteFile(configFile, data, 0655); err != nil { return err }