diff --git a/cmd/account.go b/cmd/account.go index 14ae44c8..4e641721 100644 --- a/cmd/account.go +++ b/cmd/account.go @@ -16,6 +16,7 @@ package cmd import ( "context" + "errors" "fmt" "os" @@ -37,4 +38,10 @@ var accountCmd = &cobra.Command{ printer.Account(account) }, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } diff --git a/cmd/backups.go b/cmd/backups.go index 142298f5..6414bd6d 100644 --- a/cmd/backups.go +++ b/cmd/backups.go @@ -30,6 +30,12 @@ func Backups() *cobra.Command { Use: "backups", Aliases: []string{"b"}, Short: "Display backups", + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } backupsCmd.AddCommand(backupsList, backupsGet) diff --git a/cmd/bareMetal.go b/cmd/bareMetal.go index b1db3fab..3477ed17 100644 --- a/cmd/bareMetal.go +++ b/cmd/bareMetal.go @@ -62,6 +62,12 @@ func BareMetal() *cobra.Command { Aliases: []string{"bm"}, Long: bareMetalLong, Example: bareMetalExample, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } bareMetalCmd.AddCommand( diff --git a/cmd/billing.go b/cmd/billing.go index f68e674a..28fde1f6 100644 --- a/cmd/billing.go +++ b/cmd/billing.go @@ -94,6 +94,12 @@ func Billing() *cobra.Command { Short: "Display billing information", Long: billingLong, Example: billingExample, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } historyCmd := &cobra.Command{ diff --git a/cmd/blockStorage.go b/cmd/blockStorage.go index 8ec1846e..3393fddc 100644 --- a/cmd/blockStorage.go +++ b/cmd/blockStorage.go @@ -112,6 +112,12 @@ func BlockStorageCmd() *cobra.Command { Aliases: []string{"bs"}, Short: "block storage commands", Long: `block-storage is used to interact with the block-storage api`, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } bsCmd.AddCommand(bsAttach, bsCreate, bsDelete, bsDetach, bsLabelSet, bsList, bsGet, bsResize) diff --git a/cmd/database.go b/cmd/database.go index 4dc30f9e..00e796f8 100644 --- a/cmd/database.go +++ b/cmd/database.go @@ -66,6 +66,12 @@ func Database() *cobra.Command { //nolint:funlen Short: "commands to interact with managed databases on vultr", Long: databaseLong, Example: databaseExample, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } databaseCmd.AddCommand(databaseList, databaseCreate, databaseInfo, databaseUpdate, databaseDelete) diff --git a/cmd/dns.go b/cmd/dns.go index f34866b1..913ab31b 100644 --- a/cmd/dns.go +++ b/cmd/dns.go @@ -15,6 +15,8 @@ package cmd import ( + "errors" + "github.com/spf13/cobra" ) @@ -24,6 +26,12 @@ func DNS() *cobra.Command { Use: "dns", Short: "dns is used to access dns commands", Long: ``, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } dnsCmd.AddCommand(DNSDomain()) diff --git a/cmd/firewall.go b/cmd/firewall.go index 23899c32..f312bae2 100644 --- a/cmd/firewall.go +++ b/cmd/firewall.go @@ -15,6 +15,8 @@ package cmd import ( + "errors" + "github.com/spf13/cobra" ) @@ -25,6 +27,12 @@ func Firewall() *cobra.Command { Short: "firewall is used to access firewall commands", Long: ``, Aliases: []string{"fw"}, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } firewallCmd.AddCommand(FirewallGroup(), FirewallRule()) diff --git a/cmd/instance.go b/cmd/instance.go index c80c693d..34e6b0fb 100644 --- a/cmd/instance.go +++ b/cmd/instance.go @@ -95,6 +95,12 @@ func Instance() *cobra.Command { //nolint: funlen,gocyclo Short: "commands to interact with instances on vultr", Long: instanceLong, Example: instanceExample, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } instanceCmd.AddCommand( diff --git a/cmd/iso.go b/cmd/iso.go index c74c2789..e5ce629b 100644 --- a/cmd/iso.go +++ b/cmd/iso.go @@ -32,6 +32,12 @@ func ISO() *cobra.Command { Use: "iso", Short: "iso is used to access iso commands", Long: ``, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } isoCmd.AddCommand(isoCreate, isoDelete, isoPrivateGet, isoPrivateList, isoPublic) diff --git a/cmd/kubernetes.go b/cmd/kubernetes.go index 12c1eb26..4c60d0bc 100644 --- a/cmd/kubernetes.go +++ b/cmd/kubernetes.go @@ -229,6 +229,12 @@ func Kubernetes() *cobra.Command { //nolint: funlen Short: "kubernetes is used to access kubernetes commands", Long: kubernetesLong, Example: kubernetesExample, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } kubernetesCmd.AddCommand(k8Create, k8Get, k8List, k8GetConfig, k8Update, k8Delete, k8DeleteWithResources, k8GetVersions) diff --git a/cmd/loadBalancer.go b/cmd/loadBalancer.go index 74b28689..8fa90922 100644 --- a/cmd/loadBalancer.go +++ b/cmd/loadBalancer.go @@ -86,6 +86,12 @@ func LoadBalancer() *cobra.Command { //nolint: funlen Short: "load balancer commands", Long: lbLong, Example: lbExample, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } lbCmd.AddCommand(lbCreate, lbDelete, lbGet, lbList, lbUpdate) diff --git a/cmd/network.go b/cmd/network.go index 643dca34..234aaf84 100644 --- a/cmd/network.go +++ b/cmd/network.go @@ -40,6 +40,12 @@ func Network() *cobra.Command { Short: "network interacts with network actions", Long: netLong, Deprecated: "Use vpc instead.", + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } networkCmd.AddCommand(networkGet, networkList, networkDelete, networkCreate) diff --git a/cmd/objectStorage.go b/cmd/objectStorage.go index 7fe9202d..fe6ec2ed 100644 --- a/cmd/objectStorage.go +++ b/cmd/objectStorage.go @@ -31,6 +31,12 @@ func ObjectStorageCmd() *cobra.Command { Aliases: []string{"objStorage"}, Short: "object storage commands", Long: `object-storage is used to interact with the object-storage api`, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } objStorageCmd.AddCommand( diff --git a/cmd/reservedIP.go b/cmd/reservedIP.go index bfbfe675..429d4f94 100644 --- a/cmd/reservedIP.go +++ b/cmd/reservedIP.go @@ -113,6 +113,12 @@ func ReservedIP() *cobra.Command { Short: "reserved-ip lets you interact with reserved-ip ", Long: reservedIPLong, Example: reservedIPExample, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } reservedIPCmd.AddCommand( diff --git a/cmd/root.go b/cmd/root.go index deb5493c..af82fdd3 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -31,8 +31,16 @@ import ( const ( userAgent = "vultr-cli/" + version perPageDefault int = 100 + //nolint: gosec + apiKeyError string = ` +Please export your VULTR API key as an environment variable or add 'api-key' to your config file, eg: +export VULTR_API_KEY='' + ` ) +// ctxAuthKey is the context key for the authorized token check +type ctxAuthKey struct{} + var cfgFile string var client *govultr.Client @@ -47,7 +55,6 @@ var rootCmd = &cobra.Command{ // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { if err := rootCmd.Execute(); err != nil { - fmt.Println(err) os.Exit(1) } } @@ -83,11 +90,13 @@ func init() { rootCmd.AddCommand(User()) rootCmd.AddCommand(VPC()) rootCmd.AddCommand(VPC2()) - cobra.OnInitialize(initConfig) + + ctx := initConfig() + rootCmd.SetContext(ctx) } // initConfig reads in config file and ENV variables if set. -func initConfig() { +func initConfig() context.Context { var token string configPath := viper.GetString("config") @@ -112,18 +121,22 @@ func initConfig() { token = os.Getenv("VULTR_API_KEY") } + ctx := context.Background() + if token == "" { - fmt.Println("Please export your VULTR API key as an environment variable or add `api-key` to your config file, eg:") - fmt.Println("export VULTR_API_KEY=''") - os.Exit(1) + client = govultr.NewClient(nil) + ctx = context.WithValue(ctx, ctxAuthKey{}, false) + } else { + config := &oauth2.Config{} + ts := config.TokenSource(ctx, &oauth2.Token{AccessToken: token}) + client = govultr.NewClient(oauth2.NewClient(ctx, ts)) + ctx = context.WithValue(ctx, ctxAuthKey{}, true) } - config := &oauth2.Config{} - ts := config.TokenSource(context.Background(), &oauth2.Token{AccessToken: token}) - client = govultr.NewClient(oauth2.NewClient(context.Background(), ts)) - client.SetRateLimit(1 * time.Second) client.SetUserAgent(userAgent) + + return ctx } func getPaging(cmd *cobra.Command) *govultr.ListOptions { diff --git a/cmd/script.go b/cmd/script.go index 6d795973..b37524eb 100644 --- a/cmd/script.go +++ b/cmd/script.go @@ -32,6 +32,12 @@ func Script() *cobra.Command { Aliases: []string{"ss"}, Short: "startup script commands", Long: `script is used to access startup script commands`, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } cmd.AddCommand(scriptCreate, scriptGet, scriptDelete, scriptList, scriptUpdate) diff --git a/cmd/snapshot.go b/cmd/snapshot.go index 53361a27..dcf4def3 100644 --- a/cmd/snapshot.go +++ b/cmd/snapshot.go @@ -32,6 +32,12 @@ func Snapshot() *cobra.Command { Aliases: []string{"sn"}, Short: "snapshot commands", Long: `snapshot is used to access snapshot commands`, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } cmd.AddCommand(snapshotCreate, snapshotCreateFromURL, snapshotGet, snapshotDelete, snapshotList) diff --git a/cmd/sshKey.go b/cmd/sshKey.go index 7f43a2fe..ce1e07b9 100644 --- a/cmd/sshKey.go +++ b/cmd/sshKey.go @@ -32,6 +32,12 @@ func SSHKey() *cobra.Command { Aliases: []string{"ssh"}, Short: "ssh-key commands", Long: `ssh-key is used to access SSH key commands`, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } cmd.AddCommand(sshCreate, sshDelete, sshGet, sshList, sshUpdate) diff --git a/cmd/user.go b/cmd/user.go index ce74e1ba..261fee32 100644 --- a/cmd/user.go +++ b/cmd/user.go @@ -32,6 +32,12 @@ func User() *cobra.Command { Aliases: []string{"u"}, Short: "user commands", Long: `user is used to access user commands`, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } cmd.AddCommand(userCreate, userDelete, userGet, userList, userUpdate) diff --git a/cmd/vpc.go b/cmd/vpc.go index 72969729..2e3f197d 100644 --- a/cmd/vpc.go +++ b/cmd/vpc.go @@ -82,6 +82,12 @@ func VPC() *cobra.Command { Short: "Interact with VPCs", Long: vpcLong, Example: vpcExample, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } vpcCmd.AddCommand(vpcGet, vpcList, vpcDelete, vpcCreate, vpcUpdate) diff --git a/cmd/vpc2.go b/cmd/vpc2.go index c2c32388..c136baab 100644 --- a/cmd/vpc2.go +++ b/cmd/vpc2.go @@ -62,6 +62,12 @@ func VPC2() *cobra.Command { Short: "commands to interact with vpc2 on vultr", Long: vpc2Long, Example: vpc2Example, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Context().Value(ctxAuthKey{}).(bool) { + return errors.New(apiKeyError) + } + return nil + }, } vpc2Cmd.AddCommand(vpc2List, vpc2Create, vpc2Info, vpc2Update, vpc2Delete)